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