2 * PCI Hot Plug Controller Driver for System z
4 * Copyright 2012 IBM Corp.
7 * Jan Glauber <jang@linux.vnet.ibm.com>
10 #define COMPONENT "zPCI hpc"
11 #define pr_fmt(fmt) COMPONENT ": " fmt
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/slab.h>
16 #include <linux/pci.h>
17 #include <linux/pci_hotplug.h>
18 #include <linux/init.h>
21 #define SLOT_NAME_SIZE 10
22 static LIST_HEAD(s390_hotplug_slot_list
);
24 MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com");
25 MODULE_DESCRIPTION("Hot Plug PCI Controller for System z");
26 MODULE_LICENSE("GPL");
28 static int zpci_fn_configured(enum zpci_state state
)
30 return state
== ZPCI_FN_STATE_CONFIGURED
||
31 state
== ZPCI_FN_STATE_ONLINE
;
35 * struct slot - slot information for each *physical* slot
38 struct list_head slot_list
;
39 struct hotplug_slot
*hotplug_slot
;
40 struct zpci_dev
*zdev
;
43 static int enable_slot(struct hotplug_slot
*hotplug_slot
)
45 struct slot
*slot
= hotplug_slot
->private;
48 if (slot
->zdev
->state
!= ZPCI_FN_STATE_STANDBY
)
51 rc
= sclp_pci_configure(slot
->zdev
->fid
);
53 slot
->zdev
->state
= ZPCI_FN_STATE_CONFIGURED
;
54 /* automatically scan the device after is was configured */
55 zpci_enable_device(slot
->zdev
);
56 zpci_scan_device(slot
->zdev
);
61 static int disable_slot(struct hotplug_slot
*hotplug_slot
)
63 struct slot
*slot
= hotplug_slot
->private;
66 if (!zpci_fn_configured(slot
->zdev
->state
))
69 /* TODO: we rely on the user to unbind/remove the device, is that plausible
70 * or do we need to trigger that here?
72 rc
= sclp_pci_deconfigure(slot
->zdev
->fid
);
74 /* Fixme: better call List-PCI to find the disabled FH
75 for the FID since the FH should be opaque... */
76 slot
->zdev
->fh
&= 0x7fffffff;
77 slot
->zdev
->state
= ZPCI_FN_STATE_STANDBY
;
82 static int get_power_status(struct hotplug_slot
*hotplug_slot
, u8
*value
)
84 struct slot
*slot
= hotplug_slot
->private;
86 switch (slot
->zdev
->state
) {
87 case ZPCI_FN_STATE_STANDBY
:
97 static int get_adapter_status(struct hotplug_slot
*hotplug_slot
, u8
*value
)
99 /* if the slot exits it always contains a function */
104 static void release_slot(struct hotplug_slot
*hotplug_slot
)
106 struct slot
*slot
= hotplug_slot
->private;
108 pr_debug("%s - physical_slot = %s\n", __func__
, hotplug_slot_name(hotplug_slot
));
109 kfree(slot
->hotplug_slot
->info
);
110 kfree(slot
->hotplug_slot
);
114 static struct hotplug_slot_ops s390_hotplug_slot_ops
= {
115 .enable_slot
= enable_slot
,
116 .disable_slot
= disable_slot
,
117 .get_power_status
= get_power_status
,
118 .get_adapter_status
= get_adapter_status
,
121 static int init_pci_slot(struct zpci_dev
*zdev
)
123 struct hotplug_slot
*hotplug_slot
;
124 struct hotplug_slot_info
*info
;
125 char name
[SLOT_NAME_SIZE
];
132 slot
= kzalloc(sizeof(*slot
), GFP_KERNEL
);
136 hotplug_slot
= kzalloc(sizeof(*hotplug_slot
), GFP_KERNEL
);
139 hotplug_slot
->private = slot
;
141 slot
->hotplug_slot
= hotplug_slot
;
144 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
147 hotplug_slot
->info
= info
;
149 hotplug_slot
->ops
= &s390_hotplug_slot_ops
;
150 hotplug_slot
->release
= &release_slot
;
152 get_power_status(hotplug_slot
, &info
->power_status
);
153 get_adapter_status(hotplug_slot
, &info
->adapter_status
);
155 snprintf(name
, SLOT_NAME_SIZE
, "%08x", zdev
->fid
);
156 rc
= pci_hp_register(slot
->hotplug_slot
, zdev
->bus
,
159 pr_err("pci_hp_register failed with error %d\n", rc
);
162 list_add(&slot
->slot_list
, &s390_hotplug_slot_list
);
175 static int __init
init_pci_slots(void)
177 struct zpci_dev
*zdev
;
181 * Create a structure for each slot, and register that slot
182 * with the pci_hotplug subsystem.
184 mutex_lock(&zpci_list_lock
);
185 list_for_each_entry(zdev
, &zpci_list
, entry
) {
190 mutex_unlock(&zpci_list_lock
);
191 return (device
) ? 0 : -ENODEV
;
194 static void exit_pci_slot(struct zpci_dev
*zdev
)
196 struct list_head
*tmp
, *n
;
199 list_for_each_safe(tmp
, n
, &s390_hotplug_slot_list
) {
200 slot
= list_entry(tmp
, struct slot
, slot_list
);
201 if (slot
->zdev
!= zdev
)
203 list_del(&slot
->slot_list
);
204 pci_hp_deregister(slot
->hotplug_slot
);
208 static void __exit
exit_pci_slots(void)
210 struct list_head
*tmp
, *n
;
214 * Unregister all of our slots with the pci_hotplug subsystem.
215 * Memory will be freed in release_slot() callback after slot's
216 * lifespan is finished.
218 list_for_each_safe(tmp
, n
, &s390_hotplug_slot_list
) {
219 slot
= list_entry(tmp
, struct slot
, slot_list
);
220 list_del(&slot
->slot_list
);
221 pci_hp_deregister(slot
->hotplug_slot
);
225 static int __init
pci_hotplug_s390_init(void)
228 * Do specific initialization stuff for your driver here
229 * like initializing your controller hardware (if any) and
230 * determining the number of slots you have in the system
237 /* register callbacks for slot handling from arch code */
238 mutex_lock(&zpci_list_lock
);
239 hotplug_ops
.create_slot
= init_pci_slot
;
240 hotplug_ops
.remove_slot
= exit_pci_slot
;
241 mutex_unlock(&zpci_list_lock
);
242 pr_info("registered hotplug slot callbacks\n");
243 return init_pci_slots();
246 static void __exit
pci_hotplug_s390_exit(void)
251 module_init(pci_hotplug_s390_init
);
252 module_exit(pci_hotplug_s390_exit
);