2 * Interface for Dynamic Logical Partitioning of I/O Slots on
3 * RPA-compliant PPC64 platform.
5 * John Rose <johnrose@austin.ibm.com>
6 * Linda Xie <lxie@us.ibm.com>
10 * Copyright (C) 2003 IBM.
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.
17 #include <linux/init.h>
18 #include <linux/pci.h>
19 #include <asm/pci-bridge.h>
20 #include <asm/semaphore.h>
27 static DECLARE_MUTEX(rpadlpar_sem
);
29 #define NODE_TYPE_VIO 1
30 #define NODE_TYPE_SLOT 2
31 #define NODE_TYPE_PHB 3
33 static struct device_node
*find_vio_slot_node(char *drc_name
)
35 struct device_node
*parent
= of_find_node_by_name(NULL
, "vdevice");
36 struct device_node
*dn
= NULL
;
43 while ((dn
= of_get_next_child(parent
, dn
))) {
44 rc
= rpaphp_get_drc_props(dn
, NULL
, &name
, NULL
, NULL
);
45 if ((rc
== 0) && (!strcmp(drc_name
, name
)))
52 /* Find dlpar-capable pci node that contains the specified name and type */
53 static struct device_node
*find_php_slot_pci_node(char *drc_name
,
56 struct device_node
*np
= NULL
;
61 while ((np
= of_find_node_by_type(np
, "pci"))) {
62 rc
= rpaphp_get_drc_props(np
, NULL
, &name
, &type
, NULL
);
64 if (!strcmp(drc_name
, name
) && !strcmp(drc_type
, type
))
71 static struct device_node
*find_dlpar_node(char *drc_name
, int *node_type
)
73 struct device_node
*dn
;
75 dn
= find_php_slot_pci_node(drc_name
, "SLOT");
77 *node_type
= NODE_TYPE_SLOT
;
81 dn
= find_php_slot_pci_node(drc_name
, "PHB");
83 *node_type
= NODE_TYPE_PHB
;
87 dn
= find_vio_slot_node(drc_name
);
89 *node_type
= NODE_TYPE_VIO
;
96 static struct slot
*find_slot(char *drc_name
)
98 struct list_head
*tmp
, *n
;
101 list_for_each_safe(tmp
, n
, &rpaphp_slot_head
) {
102 slot
= list_entry(tmp
, struct slot
, rpaphp_slot_list
);
103 if (strcmp(slot
->location
, drc_name
) == 0)
110 static void rpadlpar_claim_one_bus(struct pci_bus
*b
)
112 struct list_head
*ld
;
113 struct pci_bus
*child_bus
;
115 for (ld
= b
->devices
.next
; ld
!= &b
->devices
; ld
= ld
->next
) {
116 struct pci_dev
*dev
= pci_dev_b(ld
);
119 for (i
= 0; i
< PCI_NUM_RESOURCES
; i
++) {
120 struct resource
*r
= &dev
->resource
[i
];
122 if (r
->parent
|| !r
->start
|| !r
->flags
)
124 rpaphp_claim_resource(dev
, i
);
128 list_for_each_entry(child_bus
, &b
->children
, node
)
129 rpadlpar_claim_one_bus(child_bus
);
132 static int pci_add_secondary_bus(struct device_node
*dn
,
133 struct pci_dev
*bridge_dev
)
135 struct pci_controller
*hose
= dn
->phb
;
136 struct pci_bus
*child
;
139 /* Get busno of downstream bus */
140 pci_read_config_byte(bridge_dev
, PCI_SECONDARY_BUS
, &sec_busno
);
142 /* Allocate and add to children of bridge_dev->bus */
143 child
= pci_add_new_bus(bridge_dev
->bus
, bridge_dev
, sec_busno
);
145 printk(KERN_ERR
"%s: could not add secondary bus\n", __FUNCTION__
);
149 sprintf(child
->name
, "PCI Bus #%02x", child
->number
);
151 /* Fixup subordinate bridge bases and resources */
152 pcibios_fixup_bus(child
);
154 /* Claim new bus resources */
155 rpadlpar_claim_one_bus(bridge_dev
->bus
);
157 if (hose
->last_busno
< child
->number
)
158 hose
->last_busno
= child
->number
;
160 dn
->bussubno
= child
->number
;
162 /* ioremap() for child bus, which may or may not succeed */
163 remap_bus_range(child
);
168 static struct pci_dev
*dlpar_pci_add_bus(struct device_node
*dn
)
170 struct pci_controller
*hose
= dn
->phb
;
171 struct pci_dev
*dev
= NULL
;
173 /* Scan phb bus for EADS device, adding new one to bus->devices */
174 if (!pci_scan_single_device(hose
->bus
, dn
->devfn
)) {
175 printk(KERN_ERR
"%s: found no device on bus\n", __FUNCTION__
);
179 /* Add new devices to global lists. Register in proc, sysfs. */
180 pci_bus_add_devices(hose
->bus
);
182 /* Confirm new bridge dev was created */
183 dev
= rpaphp_find_pci_dev(dn
);
185 printk(KERN_ERR
"%s: failed to add pci device\n", __FUNCTION__
);
189 if (dev
->hdr_type
!= PCI_HEADER_TYPE_BRIDGE
) {
190 printk(KERN_ERR
"%s: unexpected header type %d\n",
191 __FUNCTION__
, dev
->hdr_type
);
195 if (pci_add_secondary_bus(dn
, dev
))
201 static int dlpar_pci_remove_bus(struct pci_dev
*bridge_dev
)
203 struct pci_bus
*secondary_bus
;
206 printk(KERN_ERR
"%s: unexpected null device\n",
211 secondary_bus
= bridge_dev
->subordinate
;
213 if (unmap_bus_range(secondary_bus
)) {
214 printk(KERN_ERR
"%s: failed to unmap bus range\n",
219 pci_remove_bus_device(bridge_dev
);
223 static inline int dlpar_add_pci_slot(char *drc_name
, struct device_node
*dn
)
228 dev
= dlpar_pci_add_bus(dn
);
230 printk(KERN_ERR
"%s: unable to add bus %s\n", __FUNCTION__
,
235 /* Add hotplug slot */
236 if (rpaphp_add_slot(dn
)) {
237 printk(KERN_ERR
"%s: unable to add hotplug slot %s\n",
238 __FUNCTION__
, drc_name
);
244 static int dlpar_remove_root_bus(struct pci_controller
*phb
)
246 struct pci_bus
*phb_bus
;
250 if (!(list_empty(&phb_bus
->children
) &&
251 list_empty(&phb_bus
->devices
))) {
255 rc
= pcibios_remove_root_bus(phb
);
259 device_unregister(phb_bus
->bridge
);
260 pci_remove_bus(phb_bus
);
265 static int dlpar_remove_phb(struct slot
*slot
)
267 struct pci_controller
*phb
;
268 struct device_node
*dn
;
273 printk(KERN_ERR
"%s: unexpected NULL slot device node\n",
280 printk(KERN_ERR
"%s: unexpected NULL phb pointer\n",
285 if (rpaphp_remove_slot(slot
)) {
286 printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
287 __FUNCTION__
, slot
->location
);
291 rc
= dlpar_remove_root_bus(phb
);
298 static int dlpar_add_phb(char *drc_name
, struct device_node
*dn
)
300 struct pci_controller
*phb
;
302 phb
= init_phb_dynamic(dn
);
306 if (rpaphp_add_slot(dn
)) {
307 printk(KERN_ERR
"%s: unable to add hotplug slot %s\n",
308 __FUNCTION__
, drc_name
);
315 * dlpar_add_slot - DLPAR add an I/O Slot
316 * @drc_name: drc-name of newly added slot
318 * Make the hotplug module and the kernel aware
319 * of a newly added I/O Slot.
322 * -ENODEV Not a valid drc_name
323 * -EINVAL Slot already added
324 * -ERESTARTSYS Signalled before obtaining lock
325 * -EIO Internal PCI Error
327 int dlpar_add_slot(char *drc_name
)
329 struct device_node
*dn
= NULL
;
333 if (down_interruptible(&rpadlpar_sem
))
336 /* Check for existing hotplug slot */
337 if (find_slot(drc_name
)) {
342 /* Find newly added node */
343 dn
= find_dlpar_node(drc_name
, &node_type
);
352 if (!vio_register_device_node(dn
)) {
354 "%s: failed to register vio node %s\n",
355 __FUNCTION__
, drc_name
);
360 rc
= dlpar_add_pci_slot(drc_name
, dn
);
365 rc
= dlpar_add_phb(drc_name
, dn
);
370 printk("%s: unexpected node type\n", __FUNCTION__
);
381 * dlpar_remove_vio_slot - DLPAR remove a virtual I/O Slot
382 * @drc_name: drc-name of newly added slot
384 * Remove the kernel and hotplug representations
388 * -EIO Internal Error
390 static int dlpar_remove_vio_slot(struct device_node
*dn
, char *drc_name
)
392 struct vio_dev
*vio_dev
;
394 vio_dev
= vio_find_node(dn
);
396 printk(KERN_ERR
"%s: %s does not correspond to a vio dev\n",
397 __FUNCTION__
, drc_name
);
401 vio_unregister_device(vio_dev
);
406 * dlpar_remove_slot - DLPAR remove a PCI I/O Slot
407 * @drc_name: drc-name of newly added slot
409 * Remove the kernel and hotplug representations
413 * -ENODEV Not a valid drc_name
414 * -EIO Internal PCI Error
416 int dlpar_remove_pci_slot(struct slot
*slot
, char *drc_name
)
418 struct pci_dev
*bridge_dev
;
420 bridge_dev
= slot
->bridge
;
422 printk(KERN_ERR
"%s: unexpected null bridge device\n",
427 /* Remove hotplug slot */
428 if (rpaphp_remove_slot(slot
)) {
429 printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
430 __FUNCTION__
, drc_name
);
436 if (dlpar_pci_remove_bus(bridge_dev
)) {
437 printk(KERN_ERR
"%s: unable to remove pci bus %s\n",
438 __FUNCTION__
, drc_name
);
445 * dlpar_remove_slot - DLPAR remove an I/O Slot
446 * @drc_name: drc-name of newly added slot
448 * Remove the kernel and hotplug representations
452 * -ENODEV Not a valid drc_name
453 * -EINVAL Slot already removed
454 * -ERESTARTSYS Signalled before obtaining lock
455 * -EIO Internal Error
457 int dlpar_remove_slot(char *drc_name
)
459 struct device_node
*dn
;
464 if (down_interruptible(&rpadlpar_sem
))
467 dn
= find_dlpar_node(drc_name
, &node_type
);
473 if (node_type
== NODE_TYPE_VIO
) {
474 rc
= dlpar_remove_vio_slot(dn
, drc_name
);
476 slot
= find_slot(drc_name
);
482 if (node_type
== NODE_TYPE_PHB
)
483 rc
= dlpar_remove_phb(slot
);
486 rc
= dlpar_remove_pci_slot(slot
, drc_name
);
494 static inline int is_dlpar_capable(void)
496 int rc
= rtas_token("ibm,configure-connector");
498 return (int) (rc
!= RTAS_UNKNOWN_SERVICE
);
501 int __init
rpadlpar_io_init(void)
505 if (!is_dlpar_capable()) {
506 printk(KERN_WARNING
"%s: partition not DLPAR capable\n",
511 rc
= dlpar_sysfs_init();
515 void rpadlpar_io_exit(void)
521 module_init(rpadlpar_io_init
);
522 module_exit(rpadlpar_io_exit
);
523 MODULE_LICENSE("GPL");
This page took 0.041027 seconds and 6 git commands to generate.