xref: /linux/drivers/pci/hotplug/s390_pci_hpc.c (revision 7441b0627e2251370902305a204e1330a696ca04)
1*7441b062SJan Glauber /*
2*7441b062SJan Glauber  * PCI Hot Plug Controller Driver for System z
3*7441b062SJan Glauber  *
4*7441b062SJan Glauber  * Copyright 2012 IBM Corp.
5*7441b062SJan Glauber  *
6*7441b062SJan Glauber  * Author(s):
7*7441b062SJan Glauber  *   Jan Glauber <jang@linux.vnet.ibm.com>
8*7441b062SJan Glauber  */
9*7441b062SJan Glauber 
10*7441b062SJan Glauber #define COMPONENT "zPCI hpc"
11*7441b062SJan Glauber #define pr_fmt(fmt) COMPONENT ": " fmt
12*7441b062SJan Glauber 
13*7441b062SJan Glauber #include <linux/module.h>
14*7441b062SJan Glauber #include <linux/kernel.h>
15*7441b062SJan Glauber #include <linux/slab.h>
16*7441b062SJan Glauber #include <linux/pci.h>
17*7441b062SJan Glauber #include <linux/pci_hotplug.h>
18*7441b062SJan Glauber #include <linux/init.h>
19*7441b062SJan Glauber #include <asm/sclp.h>
20*7441b062SJan Glauber 
21*7441b062SJan Glauber #define SLOT_NAME_SIZE	10
22*7441b062SJan Glauber static LIST_HEAD(s390_hotplug_slot_list);
23*7441b062SJan Glauber 
24*7441b062SJan Glauber MODULE_AUTHOR("Jan Glauber <jang@linux.vnet.ibm.com");
25*7441b062SJan Glauber MODULE_DESCRIPTION("Hot Plug PCI Controller for System z");
26*7441b062SJan Glauber MODULE_LICENSE("GPL");
27*7441b062SJan Glauber 
28*7441b062SJan Glauber static int zpci_fn_configured(enum zpci_state state)
29*7441b062SJan Glauber {
30*7441b062SJan Glauber 	return state == ZPCI_FN_STATE_CONFIGURED ||
31*7441b062SJan Glauber 	       state == ZPCI_FN_STATE_ONLINE;
32*7441b062SJan Glauber }
33*7441b062SJan Glauber 
34*7441b062SJan Glauber /*
35*7441b062SJan Glauber  * struct slot - slot information for each *physical* slot
36*7441b062SJan Glauber  */
37*7441b062SJan Glauber struct slot {
38*7441b062SJan Glauber 	struct list_head slot_list;
39*7441b062SJan Glauber 	struct hotplug_slot *hotplug_slot;
40*7441b062SJan Glauber 	struct zpci_dev *zdev;
41*7441b062SJan Glauber };
42*7441b062SJan Glauber 
43*7441b062SJan Glauber static int enable_slot(struct hotplug_slot *hotplug_slot)
44*7441b062SJan Glauber {
45*7441b062SJan Glauber 	struct slot *slot = hotplug_slot->private;
46*7441b062SJan Glauber 	int rc;
47*7441b062SJan Glauber 
48*7441b062SJan Glauber 	if (slot->zdev->state != ZPCI_FN_STATE_STANDBY)
49*7441b062SJan Glauber 		return -EIO;
50*7441b062SJan Glauber 
51*7441b062SJan Glauber 	rc = sclp_pci_configure(slot->zdev->fid);
52*7441b062SJan Glauber 	if (!rc) {
53*7441b062SJan Glauber 		slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
54*7441b062SJan Glauber 		/* automatically scan the device after is was configured */
55*7441b062SJan Glauber 		zpci_enable_device(slot->zdev);
56*7441b062SJan Glauber 		zpci_scan_device(slot->zdev);
57*7441b062SJan Glauber 	}
58*7441b062SJan Glauber 	return rc;
59*7441b062SJan Glauber }
60*7441b062SJan Glauber 
61*7441b062SJan Glauber static int disable_slot(struct hotplug_slot *hotplug_slot)
62*7441b062SJan Glauber {
63*7441b062SJan Glauber 	struct slot *slot = hotplug_slot->private;
64*7441b062SJan Glauber 	int rc;
65*7441b062SJan Glauber 
66*7441b062SJan Glauber 	if (!zpci_fn_configured(slot->zdev->state))
67*7441b062SJan Glauber 		return -EIO;
68*7441b062SJan Glauber 
69*7441b062SJan Glauber 	/* TODO: we rely on the user to unbind/remove the device, is that plausible
70*7441b062SJan Glauber 	 *	 or do we need to trigger that here?
71*7441b062SJan Glauber 	 */
72*7441b062SJan Glauber 	rc = sclp_pci_deconfigure(slot->zdev->fid);
73*7441b062SJan Glauber 	if (!rc) {
74*7441b062SJan Glauber 		/* Fixme: better call List-PCI to find the disabled FH
75*7441b062SJan Glauber 		   for the FID since the FH should be opaque... */
76*7441b062SJan Glauber 		slot->zdev->fh &= 0x7fffffff;
77*7441b062SJan Glauber 		slot->zdev->state = ZPCI_FN_STATE_STANDBY;
78*7441b062SJan Glauber 	}
79*7441b062SJan Glauber 	return rc;
80*7441b062SJan Glauber }
81*7441b062SJan Glauber 
82*7441b062SJan Glauber static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
83*7441b062SJan Glauber {
84*7441b062SJan Glauber 	struct slot *slot = hotplug_slot->private;
85*7441b062SJan Glauber 
86*7441b062SJan Glauber 	switch (slot->zdev->state) {
87*7441b062SJan Glauber 	case ZPCI_FN_STATE_STANDBY:
88*7441b062SJan Glauber 		*value = 0;
89*7441b062SJan Glauber 		break;
90*7441b062SJan Glauber 	default:
91*7441b062SJan Glauber 		*value = 1;
92*7441b062SJan Glauber 		break;
93*7441b062SJan Glauber 	}
94*7441b062SJan Glauber 	return 0;
95*7441b062SJan Glauber }
96*7441b062SJan Glauber 
97*7441b062SJan Glauber static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
98*7441b062SJan Glauber {
99*7441b062SJan Glauber 	/* if the slot exits it always contains a function */
100*7441b062SJan Glauber 	*value = 1;
101*7441b062SJan Glauber 	return 0;
102*7441b062SJan Glauber }
103*7441b062SJan Glauber 
104*7441b062SJan Glauber static void release_slot(struct hotplug_slot *hotplug_slot)
105*7441b062SJan Glauber {
106*7441b062SJan Glauber 	struct slot *slot = hotplug_slot->private;
107*7441b062SJan Glauber 
108*7441b062SJan Glauber 	pr_debug("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
109*7441b062SJan Glauber 	kfree(slot->hotplug_slot->info);
110*7441b062SJan Glauber 	kfree(slot->hotplug_slot);
111*7441b062SJan Glauber 	kfree(slot);
112*7441b062SJan Glauber }
113*7441b062SJan Glauber 
114*7441b062SJan Glauber static struct hotplug_slot_ops s390_hotplug_slot_ops = {
115*7441b062SJan Glauber 	.enable_slot =		enable_slot,
116*7441b062SJan Glauber 	.disable_slot =		disable_slot,
117*7441b062SJan Glauber 	.get_power_status =	get_power_status,
118*7441b062SJan Glauber 	.get_adapter_status =	get_adapter_status,
119*7441b062SJan Glauber };
120*7441b062SJan Glauber 
121*7441b062SJan Glauber static int init_pci_slot(struct zpci_dev *zdev)
122*7441b062SJan Glauber {
123*7441b062SJan Glauber 	struct hotplug_slot *hotplug_slot;
124*7441b062SJan Glauber 	struct hotplug_slot_info *info;
125*7441b062SJan Glauber 	char name[SLOT_NAME_SIZE];
126*7441b062SJan Glauber 	struct slot *slot;
127*7441b062SJan Glauber 	int rc;
128*7441b062SJan Glauber 
129*7441b062SJan Glauber 	if (!zdev)
130*7441b062SJan Glauber 		return 0;
131*7441b062SJan Glauber 
132*7441b062SJan Glauber 	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
133*7441b062SJan Glauber 	if (!slot)
134*7441b062SJan Glauber 		goto error;
135*7441b062SJan Glauber 
136*7441b062SJan Glauber 	hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
137*7441b062SJan Glauber 	if (!hotplug_slot)
138*7441b062SJan Glauber 		goto error_hp;
139*7441b062SJan Glauber 	hotplug_slot->private = slot;
140*7441b062SJan Glauber 
141*7441b062SJan Glauber 	slot->hotplug_slot = hotplug_slot;
142*7441b062SJan Glauber 	slot->zdev = zdev;
143*7441b062SJan Glauber 
144*7441b062SJan Glauber 	info = kzalloc(sizeof(*info), GFP_KERNEL);
145*7441b062SJan Glauber 	if (!info)
146*7441b062SJan Glauber 		goto error_info;
147*7441b062SJan Glauber 	hotplug_slot->info = info;
148*7441b062SJan Glauber 
149*7441b062SJan Glauber 	hotplug_slot->ops = &s390_hotplug_slot_ops;
150*7441b062SJan Glauber 	hotplug_slot->release = &release_slot;
151*7441b062SJan Glauber 
152*7441b062SJan Glauber 	get_power_status(hotplug_slot, &info->power_status);
153*7441b062SJan Glauber 	get_adapter_status(hotplug_slot, &info->adapter_status);
154*7441b062SJan Glauber 
155*7441b062SJan Glauber 	snprintf(name, SLOT_NAME_SIZE, "%08x", zdev->fid);
156*7441b062SJan Glauber 	rc = pci_hp_register(slot->hotplug_slot, zdev->bus,
157*7441b062SJan Glauber 			     ZPCI_DEVFN, name);
158*7441b062SJan Glauber 	if (rc) {
159*7441b062SJan Glauber 		pr_err("pci_hp_register failed with error %d\n", rc);
160*7441b062SJan Glauber 		goto error_reg;
161*7441b062SJan Glauber 	}
162*7441b062SJan Glauber 	list_add(&slot->slot_list, &s390_hotplug_slot_list);
163*7441b062SJan Glauber 	return 0;
164*7441b062SJan Glauber 
165*7441b062SJan Glauber error_reg:
166*7441b062SJan Glauber 	kfree(info);
167*7441b062SJan Glauber error_info:
168*7441b062SJan Glauber 	kfree(hotplug_slot);
169*7441b062SJan Glauber error_hp:
170*7441b062SJan Glauber 	kfree(slot);
171*7441b062SJan Glauber error:
172*7441b062SJan Glauber 	return -ENOMEM;
173*7441b062SJan Glauber }
174*7441b062SJan Glauber 
175*7441b062SJan Glauber static int __init init_pci_slots(void)
176*7441b062SJan Glauber {
177*7441b062SJan Glauber 	struct zpci_dev *zdev;
178*7441b062SJan Glauber 	int device = 0;
179*7441b062SJan Glauber 
180*7441b062SJan Glauber 	/*
181*7441b062SJan Glauber 	 * Create a structure for each slot, and register that slot
182*7441b062SJan Glauber 	 * with the pci_hotplug subsystem.
183*7441b062SJan Glauber 	 */
184*7441b062SJan Glauber 	mutex_lock(&zpci_list_lock);
185*7441b062SJan Glauber 	list_for_each_entry(zdev, &zpci_list, entry) {
186*7441b062SJan Glauber 		init_pci_slot(zdev);
187*7441b062SJan Glauber 		device++;
188*7441b062SJan Glauber 	}
189*7441b062SJan Glauber 
190*7441b062SJan Glauber 	mutex_unlock(&zpci_list_lock);
191*7441b062SJan Glauber 	return (device) ? 0 : -ENODEV;
192*7441b062SJan Glauber }
193*7441b062SJan Glauber 
194*7441b062SJan Glauber static void exit_pci_slot(struct zpci_dev *zdev)
195*7441b062SJan Glauber {
196*7441b062SJan Glauber 	struct list_head *tmp, *n;
197*7441b062SJan Glauber 	struct slot *slot;
198*7441b062SJan Glauber 
199*7441b062SJan Glauber 	list_for_each_safe(tmp, n, &s390_hotplug_slot_list) {
200*7441b062SJan Glauber 		slot = list_entry(tmp, struct slot, slot_list);
201*7441b062SJan Glauber 		if (slot->zdev != zdev)
202*7441b062SJan Glauber 			continue;
203*7441b062SJan Glauber 		list_del(&slot->slot_list);
204*7441b062SJan Glauber 		pci_hp_deregister(slot->hotplug_slot);
205*7441b062SJan Glauber 	}
206*7441b062SJan Glauber }
207*7441b062SJan Glauber 
208*7441b062SJan Glauber static void __exit exit_pci_slots(void)
209*7441b062SJan Glauber {
210*7441b062SJan Glauber 	struct list_head *tmp, *n;
211*7441b062SJan Glauber 	struct slot *slot;
212*7441b062SJan Glauber 
213*7441b062SJan Glauber 	/*
214*7441b062SJan Glauber 	 * Unregister all of our slots with the pci_hotplug subsystem.
215*7441b062SJan Glauber 	 * Memory will be freed in release_slot() callback after slot's
216*7441b062SJan Glauber 	 * lifespan is finished.
217*7441b062SJan Glauber 	 */
218*7441b062SJan Glauber 	list_for_each_safe(tmp, n, &s390_hotplug_slot_list) {
219*7441b062SJan Glauber 		slot = list_entry(tmp, struct slot, slot_list);
220*7441b062SJan Glauber 		list_del(&slot->slot_list);
221*7441b062SJan Glauber 		pci_hp_deregister(slot->hotplug_slot);
222*7441b062SJan Glauber 	}
223*7441b062SJan Glauber }
224*7441b062SJan Glauber 
225*7441b062SJan Glauber static int __init pci_hotplug_s390_init(void)
226*7441b062SJan Glauber {
227*7441b062SJan Glauber 	/*
228*7441b062SJan Glauber 	 * Do specific initialization stuff for your driver here
229*7441b062SJan Glauber 	 * like initializing your controller hardware (if any) and
230*7441b062SJan Glauber 	 * determining the number of slots you have in the system
231*7441b062SJan Glauber 	 * right now.
232*7441b062SJan Glauber 	 */
233*7441b062SJan Glauber 
234*7441b062SJan Glauber 	if (!pci_probe)
235*7441b062SJan Glauber 		return -EOPNOTSUPP;
236*7441b062SJan Glauber 
237*7441b062SJan Glauber 	/* register callbacks for slot handling from arch code */
238*7441b062SJan Glauber 	mutex_lock(&zpci_list_lock);
239*7441b062SJan Glauber 	hotplug_ops.create_slot = init_pci_slot;
240*7441b062SJan Glauber 	hotplug_ops.remove_slot = exit_pci_slot;
241*7441b062SJan Glauber 	mutex_unlock(&zpci_list_lock);
242*7441b062SJan Glauber 	pr_info("registered hotplug slot callbacks\n");
243*7441b062SJan Glauber 	return init_pci_slots();
244*7441b062SJan Glauber }
245*7441b062SJan Glauber 
246*7441b062SJan Glauber static void __exit pci_hotplug_s390_exit(void)
247*7441b062SJan Glauber {
248*7441b062SJan Glauber 	exit_pci_slots();
249*7441b062SJan Glauber }
250*7441b062SJan Glauber 
251*7441b062SJan Glauber module_init(pci_hotplug_s390_init);
252*7441b062SJan Glauber module_exit(pci_hotplug_s390_exit);
253