Merge master.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild
[sfrench/cifs-2.6.git] / drivers / pci / hotplug / rpadlpar_core.c
1 /*
2  * Interface for Dynamic Logical Partitioning of I/O Slots on
3  * RPA-compliant PPC64 platform.
4  *
5  * John Rose <johnrose@austin.ibm.com>
6  * Linda Xie <lxie@us.ibm.com>
7  *
8  * October 2003
9  *
10  * Copyright (C) 2003 IBM.
11  *
12  *      This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  */
17 #include <linux/init.h>
18 #include <linux/pci.h>
19 #include <linux/string.h>
20
21 #include <asm/pci-bridge.h>
22 #include <asm/semaphore.h>
23 #include <asm/rtas.h>
24 #include <asm/vio.h>
25
26 #include "../pci.h"
27 #include "rpaphp.h"
28 #include "rpadlpar.h"
29
30 static DECLARE_MUTEX(rpadlpar_sem);
31
32 #define DLPAR_MODULE_NAME "rpadlpar_io"
33
34 #define NODE_TYPE_VIO  1
35 #define NODE_TYPE_SLOT 2
36 #define NODE_TYPE_PHB  3
37
38 static struct device_node *find_vio_slot_node(char *drc_name)
39 {
40         struct device_node *parent = of_find_node_by_name(NULL, "vdevice");
41         struct device_node *dn = NULL;
42         char *name;
43         int rc;
44
45         if (!parent)
46                 return NULL;
47
48         while ((dn = of_get_next_child(parent, dn))) {
49                 rc = rpaphp_get_drc_props(dn, NULL, &name, NULL, NULL);
50                 if ((rc == 0) && (!strcmp(drc_name, name)))
51                         break;
52         }
53
54         return dn;
55 }
56
57 /* Find dlpar-capable pci node that contains the specified name and type */
58 static struct device_node *find_php_slot_pci_node(char *drc_name,
59                                                   char *drc_type)
60 {
61         struct device_node *np = NULL;
62         char *name;
63         char *type;
64         int rc;
65
66         while ((np = of_find_node_by_type(np, "pci"))) {
67                 rc = rpaphp_get_drc_props(np, NULL, &name, &type, NULL);
68                 if (rc == 0)
69                         if (!strcmp(drc_name, name) && !strcmp(drc_type, type))
70                                 break;
71         }
72
73         return np;
74 }
75
76 static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
77 {
78         struct device_node *dn;
79
80         dn = find_php_slot_pci_node(drc_name, "SLOT");
81         if (dn) {
82                 *node_type = NODE_TYPE_SLOT;
83                 return dn;
84         }
85
86         dn = find_php_slot_pci_node(drc_name, "PHB");
87         if (dn) {
88                 *node_type = NODE_TYPE_PHB;
89                 return dn;
90         }
91
92         dn = find_vio_slot_node(drc_name);
93         if (dn) {
94                 *node_type = NODE_TYPE_VIO;
95                 return dn;
96         }
97
98         return NULL;
99 }
100
101 static struct slot *find_slot(struct device_node *dn)
102 {
103         struct list_head *tmp, *n;
104         struct slot *slot;
105
106         list_for_each_safe(tmp, n, &rpaphp_slot_head) {
107                 slot = list_entry(tmp, struct slot, rpaphp_slot_list);
108                 if (slot->dn == dn)
109                         return slot;
110         }
111
112         return NULL;
113 }
114
115 static void rpadlpar_claim_one_bus(struct pci_bus *b)
116 {
117         struct list_head *ld;
118         struct pci_bus *child_bus;
119
120         for (ld = b->devices.next; ld != &b->devices; ld = ld->next) {
121                 struct pci_dev *dev = pci_dev_b(ld);
122                 int i;
123
124                 for (i = 0; i < PCI_NUM_RESOURCES; i++) {
125                         struct resource *r = &dev->resource[i];
126
127                         if (r->parent || !r->start || !r->flags)
128                                 continue;
129                         rpaphp_claim_resource(dev, i);
130                 }
131         }
132
133         list_for_each_entry(child_bus, &b->children, node)
134                 rpadlpar_claim_one_bus(child_bus);
135 }
136
137 static int pci_add_secondary_bus(struct device_node *dn,
138                 struct pci_dev *bridge_dev)
139 {
140         struct pci_dn *pdn = dn->data;
141         struct pci_controller *hose = pdn->phb;
142         struct pci_bus *child;
143         u8 sec_busno;
144
145         /* Get busno of downstream bus */
146         pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &sec_busno);
147
148         /* Allocate and add to children of bridge_dev->bus */
149         child = pci_add_new_bus(bridge_dev->bus, bridge_dev, sec_busno);
150         if (!child) {
151                 printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__);
152                 return -ENOMEM;
153         }
154
155         sprintf(child->name, "PCI Bus #%02x", child->number);
156
157         /* Fixup subordinate bridge bases and resources */
158         pcibios_fixup_bus(child);
159
160         /* Claim new bus resources */
161         rpadlpar_claim_one_bus(bridge_dev->bus);
162
163         if (hose->last_busno < child->number)
164                 hose->last_busno = child->number;
165
166         pdn->bussubno = child->number;
167
168         /* ioremap() for child bus, which may or may not succeed */
169         remap_bus_range(child);
170
171         return 0;
172 }
173
174 static struct pci_dev *dlpar_find_new_dev(struct pci_bus *parent,
175                                         struct device_node *dev_dn)
176 {
177         struct pci_dev *tmp = NULL;
178         struct device_node *child_dn;
179
180         list_for_each_entry(tmp, &parent->devices, bus_list) {
181                 child_dn = pci_device_to_OF_node(tmp);
182                 if (child_dn == dev_dn)
183                         return tmp;
184         }
185         return NULL;
186 }
187
188 static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
189 {
190         struct pci_dn *pdn = dn->data;
191         struct pci_controller *hose = pdn->phb;
192         struct pci_dev *dev = NULL;
193
194         /* Scan phb bus for EADS device, adding new one to bus->devices */
195         if (!pci_scan_single_device(hose->bus, pdn->devfn)) {
196                 printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
197                 return NULL;
198         }
199
200         /* Add new devices to global lists.  Register in proc, sysfs. */
201         pci_bus_add_devices(hose->bus);
202
203         /* Confirm new bridge dev was created */
204         dev = dlpar_find_new_dev(hose->bus, dn);
205         if (dev) {
206                 if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
207                         printk(KERN_ERR "%s: unexpected header type %d\n",
208                                 __FUNCTION__, dev->hdr_type);
209                         return NULL;
210                 }
211
212                 if (pci_add_secondary_bus(dn, dev))
213                         return NULL;
214         }
215
216         return dev;
217 }
218
219 static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)
220 {
221         struct pci_dev *dev;
222         int rc;
223
224         if (rpaphp_find_pci_bus(dn))
225                 return -EINVAL;
226
227         /* Add pci bus */
228         dev = dlpar_pci_add_bus(dn);
229         if (!dev) {
230                 printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
231                         drc_name);
232                 return -EIO;
233         }
234
235         if (dn->child) {
236                 rc = rpaphp_config_pci_adapter(dev->subordinate);
237                 if (rc < 0) {
238                         printk(KERN_ERR "%s: unable to enable slot %s\n",
239                                 __FUNCTION__, drc_name);
240                         return -EIO;
241                 }
242         }
243
244         /* Add hotplug slot */
245         if (rpaphp_add_slot(dn)) {
246                 printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
247                         __FUNCTION__, drc_name);
248                 return -EIO;
249         }
250         return 0;
251 }
252
253 static int dlpar_remove_root_bus(struct pci_controller *phb)
254 {
255         struct pci_bus *phb_bus;
256         int rc;
257
258         phb_bus = phb->bus;
259         if (!(list_empty(&phb_bus->children) &&
260               list_empty(&phb_bus->devices))) {
261                 return -EBUSY;
262         }
263
264         rc = pcibios_remove_root_bus(phb);
265         if (rc)
266                 return -EIO;
267
268         device_unregister(phb_bus->bridge);
269         pci_remove_bus(phb_bus);
270
271         return 0;
272 }
273
274 static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
275 {
276         struct slot *slot;
277         struct pci_dn *pdn;
278         int rc = 0;
279
280         if (!rpaphp_find_pci_bus(dn))
281                 return -EINVAL;
282
283         slot = find_slot(dn);
284         if (slot) {
285                 /* Remove hotplug slot */
286                 if (rpaphp_remove_slot(slot)) {
287                         printk(KERN_ERR
288                                 "%s: unable to remove hotplug slot %s\n",
289                                 __FUNCTION__, drc_name);
290                         return -EIO;
291                 }
292         }
293
294         pdn = dn->data;
295         BUG_ON(!pdn || !pdn->phb);
296         rc = dlpar_remove_root_bus(pdn->phb);
297         if (rc < 0)
298                 return rc;
299
300         pdn->phb = NULL;
301
302         return 0;
303 }
304
305 static int dlpar_add_phb(char *drc_name, struct device_node *dn)
306 {
307         struct pci_controller *phb;
308
309         if (PCI_DN(dn) && PCI_DN(dn)->phb) {
310                 /* PHB already exists */
311                 return -EINVAL;
312         }
313
314         phb = init_phb_dynamic(dn);
315         if (!phb)
316                 return -EIO;
317
318         if (rpaphp_add_slot(dn)) {
319                 printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
320                         __FUNCTION__, drc_name);
321                 return -EIO;
322         }
323         return 0;
324 }
325
326 static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn)
327 {
328         if (vio_find_node(dn))
329                 return -EINVAL;
330
331         if (!vio_register_device_node(dn)) {
332                 printk(KERN_ERR
333                         "%s: failed to register vio node %s\n",
334                         __FUNCTION__, drc_name);
335                 return -EIO;
336         }
337         return 0;
338 }
339
340 /**
341  * dlpar_add_slot - DLPAR add an I/O Slot
342  * @drc_name: drc-name of newly added slot
343  *
344  * Make the hotplug module and the kernel aware
345  * of a newly added I/O Slot.
346  * Return Codes -
347  * 0                    Success
348  * -ENODEV              Not a valid drc_name
349  * -EINVAL              Slot already added
350  * -ERESTARTSYS         Signalled before obtaining lock
351  * -EIO                 Internal PCI Error
352  */
353 int dlpar_add_slot(char *drc_name)
354 {
355         struct device_node *dn = NULL;
356         int node_type;
357         int rc = -EIO;
358
359         if (down_interruptible(&rpadlpar_sem))
360                 return -ERESTARTSYS;
361
362         /* Find newly added node */
363         dn = find_dlpar_node(drc_name, &node_type);
364         if (!dn) {
365                 rc = -ENODEV;
366                 goto exit;
367         }
368
369         switch (node_type) {
370                 case NODE_TYPE_VIO:
371                         rc = dlpar_add_vio_slot(drc_name, dn);
372                         break;
373                 case NODE_TYPE_SLOT:
374                         rc = dlpar_add_pci_slot(drc_name, dn);
375                         break;
376                 case NODE_TYPE_PHB:
377                         rc = dlpar_add_phb(drc_name, dn);
378                         break;
379         }
380
381         printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
382 exit:
383         up(&rpadlpar_sem);
384         return rc;
385 }
386
387 /**
388  * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
389  * @drc_name: drc-name of newly added slot
390  *
391  * Remove the kernel and hotplug representations
392  * of an I/O Slot.
393  * Return Codes:
394  * 0                    Success
395  * -EINVAL              Vio dev doesn't exist
396  */
397 static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn)
398 {
399         struct vio_dev *vio_dev;
400
401         vio_dev = vio_find_node(dn);
402         if (!vio_dev)
403                 return -EINVAL;
404
405         vio_unregister_device(vio_dev);
406         return 0;
407 }
408
409 /**
410  * dlpar_remove_slot - DLPAR remove a PCI I/O Slot
411  * @drc_name: drc-name of newly added slot
412  *
413  * Remove the kernel and hotplug representations
414  * of a PCI I/O Slot.
415  * Return Codes:
416  * 0                    Success
417  * -ENODEV              Not a valid drc_name
418  * -EIO                 Internal PCI Error
419  */
420 int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
421 {
422         struct pci_bus *bus;
423         struct slot *slot;
424
425         bus = rpaphp_find_pci_bus(dn);
426         if (!bus)
427                 return -EINVAL;
428
429         slot = find_slot(dn);
430         if (slot) {
431                 /* Remove hotplug slot */
432                 if (rpaphp_remove_slot(slot)) {
433                         printk(KERN_ERR
434                                 "%s: unable to remove hotplug slot %s\n",
435                                 __FUNCTION__, drc_name);
436                         return -EIO;
437                 }
438         }
439
440         if (unmap_bus_range(bus)) {
441                 printk(KERN_ERR "%s: failed to unmap bus range\n",
442                         __FUNCTION__);
443                 return -ERANGE;
444         }
445
446         BUG_ON(!bus->self);
447         pci_remove_bus_device(bus->self);
448         return 0;
449 }
450
451 /**
452  * dlpar_remove_slot - DLPAR remove an I/O Slot
453  * @drc_name: drc-name of newly added slot
454  *
455  * Remove the kernel and hotplug representations
456  * of an I/O Slot.
457  * Return Codes:
458  * 0                    Success
459  * -ENODEV              Not a valid drc_name
460  * -EINVAL              Slot already removed
461  * -ERESTARTSYS         Signalled before obtaining lock
462  * -EIO                 Internal Error
463  */
464 int dlpar_remove_slot(char *drc_name)
465 {
466         struct device_node *dn;
467         int node_type;
468         int rc = 0;
469
470         if (down_interruptible(&rpadlpar_sem))
471                 return -ERESTARTSYS;
472
473         dn = find_dlpar_node(drc_name, &node_type);
474         if (!dn) {
475                 rc = -ENODEV;
476                 goto exit;
477         }
478
479         switch (node_type) {
480                 case NODE_TYPE_VIO:
481                         rc = dlpar_remove_vio_slot(drc_name, dn);
482                         break;
483                 case NODE_TYPE_PHB:
484                         rc = dlpar_remove_phb(drc_name, dn);
485                         break;
486                 case NODE_TYPE_SLOT:
487                         rc = dlpar_remove_pci_slot(drc_name, dn);
488                         break;
489         }
490         printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);
491 exit:
492         up(&rpadlpar_sem);
493         return rc;
494 }
495
496 static inline int is_dlpar_capable(void)
497 {
498         int rc = rtas_token("ibm,configure-connector");
499
500         return (int) (rc != RTAS_UNKNOWN_SERVICE);
501 }
502
503 int __init rpadlpar_io_init(void)
504 {
505         int rc = 0;
506
507         if (!is_dlpar_capable()) {
508                 printk(KERN_WARNING "%s: partition not DLPAR capable\n",
509                         __FUNCTION__);
510                 return -EPERM;
511         }
512
513         rc = dlpar_sysfs_init();
514         return rc;
515 }
516
517 void rpadlpar_io_exit(void)
518 {
519         dlpar_sysfs_exit();
520         return;
521 }
522
523 module_init(rpadlpar_io_init);
524 module_exit(rpadlpar_io_exit);
525 MODULE_LICENSE("GPL");