aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPrarit Bhargava <prarit@sgi.com>2005-07-06 18:29:53 -0400
committerTony Luck <tony.luck@intel.com>2005-07-06 18:29:53 -0400
commit6f354b014b51716166f13f68b29212d3c44ed2c4 (patch)
tree396c09a5d519630a53652a1187bb85fceba82cee /arch
parent283c7f6ac6adb57e7dd13cdbc8d60b6ea4de6faf (diff)
[IA64] hotplug/ia64: SN Hotplug Driver - SN Hotplug Driver code
This patch is the SGI hotplug driver and additional changes required for the driver. These modifications include changes to the SN io_init.c code for memory management, the inclusion of new SAL calls to enable and disable PCI slots, and a hotplug-style driver. Signed-off-by: Prarit Bhargava <prarit@sgi.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/sn/kernel/io_init.c134
-rw-r--r--arch/ia64/sn/kernel/irq.c6
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c37
3 files changed, 129 insertions, 48 deletions
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 041c4be02b2a..a67f39e448cb 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -23,6 +23,14 @@
23 23
24nasid_t master_nasid = INVALID_NASID; /* Partition Master */ 24nasid_t master_nasid = INVALID_NASID; /* Partition Master */
25 25
26static struct list_head sn_sysdata_list;
27
28/* sysdata list struct */
29struct sysdata_el {
30 struct list_head entry;
31 void *sysdata;
32};
33
26struct slab_info { 34struct slab_info {
27 struct hubdev_info hubdev; 35 struct hubdev_info hubdev;
28}; 36};
@@ -137,23 +145,6 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
137} 145}
138 146
139/* 147/*
140 * sn_alloc_pci_sysdata() - This routine allocates a pci controller
141 * which is expected as the pci_dev and pci_bus sysdata by the Linux
142 * PCI infrastructure.
143 */
144static inline struct pci_controller *sn_alloc_pci_sysdata(void)
145{
146 struct pci_controller *pci_sysdata;
147
148 pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
149 if (!pci_sysdata)
150 BUG();
151
152 memset(pci_sysdata, 0, sizeof(*pci_sysdata));
153 return pci_sysdata;
154}
155
156/*
157 * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for 148 * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for
158 * each node in the system. 149 * each node in the system.
159 */ 150 */
@@ -220,6 +211,15 @@ static void sn_fixup_ionodes(void)
220 211
221} 212}
222 213
214void sn_pci_unfixup_slot(struct pci_dev *dev)
215{
216 struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
217
218 sn_irq_unfixup(dev);
219 pci_dev_put(host_pci_dev);
220 pci_dev_put(dev);
221}
222
223/* 223/*
224 * sn_pci_fixup_slot() - This routine sets up a slot's resources 224 * sn_pci_fixup_slot() - This routine sets up a slot's resources
225 * consistent with the Linux PCI abstraction layer. Resources acquired 225 * consistent with the Linux PCI abstraction layer. Resources acquired
@@ -238,6 +238,7 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
238 unsigned long size; 238 unsigned long size;
239 unsigned int bus_no, devfn; 239 unsigned int bus_no, devfn;
240 240
241 pci_dev_get(dev); /* for the sysdata pointer */
241 dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); 242 dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
242 if (SN_PCIDEV_INFO(dev) <= 0) 243 if (SN_PCIDEV_INFO(dev) <= 0)
243 BUG(); /* Cannot afford to run out of memory */ 244 BUG(); /* Cannot afford to run out of memory */
@@ -276,7 +277,8 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
276 dev->resource[idx].parent = &iomem_resource; 277 dev->resource[idx].parent = &iomem_resource;
277 } 278 }
278 279
279 /* Using the PROMs values for the PCI host bus, get the Linux 280 /*
281 * Using the PROMs values for the PCI host bus, get the Linux
280 * PCI host_pci_dev struct and set up host bus linkages 282 * PCI host_pci_dev struct and set up host bus linkages
281 */ 283 */
282 284
@@ -313,55 +315,57 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
313 * sn_pci_controller_fixup() - This routine sets up a bus's resources 315 * sn_pci_controller_fixup() - This routine sets up a bus's resources
314 * consistent with the Linux PCI abstraction layer. 316 * consistent with the Linux PCI abstraction layer.
315 */ 317 */
316static void sn_pci_controller_fixup(int segment, int busnum) 318void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
317{ 319{
318 int status = 0; 320 int status = 0;
319 int nasid, cnode; 321 int nasid, cnode;
320 struct pci_bus *bus;
321 struct pci_controller *controller; 322 struct pci_controller *controller;
322 struct pcibus_bussoft *prom_bussoft_ptr; 323 struct pcibus_bussoft *prom_bussoft_ptr;
323 struct hubdev_info *hubdev_info; 324 struct hubdev_info *hubdev_info;
324 void *provider_soft; 325 void *provider_soft;
325 struct sn_pcibus_provider *provider; 326 struct sn_pcibus_provider *provider;
326 327
327 status = 328 status = sal_get_pcibus_info((u64) segment, (u64) busnum,
328 sal_get_pcibus_info((u64) segment, (u64) busnum, 329 (u64) ia64_tpa(&prom_bussoft_ptr));
329 (u64) ia64_tpa(&prom_bussoft_ptr)); 330 if (status > 0)
330 if (status > 0) { 331 return; /*bus # does not exist */
331 return; /* bus # does not exist */
332 }
333
334 prom_bussoft_ptr = __va(prom_bussoft_ptr); 332 prom_bussoft_ptr = __va(prom_bussoft_ptr);
335 controller = sn_alloc_pci_sysdata();
336 /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
337 333
338 bus = pci_scan_bus(busnum, &pci_root_ops, controller); 334 controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
335 if (!controller)
336 BUG();
337
339 if (bus == NULL) { 338 if (bus == NULL) {
340 return; /* error, or bus already scanned */ 339 bus = pci_scan_bus(busnum, &pci_root_ops, controller);
340 if (bus == NULL)
341 return; /* error, or bus already scanned */
342 bus->sysdata = NULL;
341 } 343 }
342 344
345 if (bus->sysdata)
346 goto error_return; /* sysdata already alloc'd */
347
343 /* 348 /*
344 * Per-provider fixup. Copies the contents from prom to local 349 * Per-provider fixup. Copies the contents from prom to local
345 * area and links SN_PCIBUS_BUSSOFT(). 350 * area and links SN_PCIBUS_BUSSOFT().
346 */ 351 */
347 352
348 if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { 353 if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
349 return; /* unsupported asic type */ 354 return; /* unsupported asic type */
350 } 355
356 if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
357 goto error_return; /* no further fixup necessary */
351 358
352 provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; 359 provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
353 if (provider == NULL) { 360 if (provider == NULL)
354 return; /* no provider registerd for this asic */ 361 return; /* no provider registerd for this asic */
355 }
356 362
357 provider_soft = NULL; 363 provider_soft = NULL;
358 if (provider->bus_fixup) { 364 if (provider->bus_fixup)
359 provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); 365 provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr);
360 }
361 366
362 if (provider_soft == NULL) { 367 if (provider_soft == NULL)
363 return; /* fixup failed or not applicable */ 368 return; /* fixup failed or not applicable */
364 }
365 369
366 /* 370 /*
367 * Generic bus fixup goes here. Don't reference prom_bussoft_ptr 371 * Generic bus fixup goes here. Don't reference prom_bussoft_ptr
@@ -370,12 +374,47 @@ static void sn_pci_controller_fixup(int segment, int busnum)
370 374
371 bus->sysdata = controller; 375 bus->sysdata = controller;
372 PCI_CONTROLLER(bus)->platform_data = provider_soft; 376 PCI_CONTROLLER(bus)->platform_data = provider_soft;
373
374 nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); 377 nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
375 cnode = nasid_to_cnodeid(nasid); 378 cnode = nasid_to_cnodeid(nasid);
376 hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); 379 hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
377 SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = 380 SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
378 &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]); 381 &(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
382
383 return;
384
385error_return:
386
387 kfree(controller);
388 return;
389}
390
391void sn_bus_store_sysdata(struct pci_dev *dev)
392{
393 struct sysdata_el *element;
394
395 element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
396 if (!element) {
397 dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
398 return;
399 }
400 element->sysdata = dev->sysdata;
401 list_add(&element->entry, &sn_sysdata_list);
402}
403
404void sn_bus_free_sysdata(void)
405{
406 struct sysdata_el *element;
407 struct list_head *list;
408
409sn_sysdata_free_start:
410 list_for_each(list, &sn_sysdata_list) {
411 element = list_entry(list, struct sysdata_el, entry);
412 list_del(&element->entry);
413 kfree(element->sysdata);
414 kfree(element);
415 goto sn_sysdata_free_start;
416 }
417 return;
379} 418}
380 419
381/* 420/*
@@ -413,15 +452,16 @@ static int __init sn_pci_init(void)
413 ia64_max_iommu_merge_mask = ~PAGE_MASK; 452 ia64_max_iommu_merge_mask = ~PAGE_MASK;
414 sn_fixup_ionodes(); 453 sn_fixup_ionodes();
415 sn_irq_lh_init(); 454 sn_irq_lh_init();
455 INIT_LIST_HEAD(&sn_sysdata_list);
416 sn_init_cpei_timer(); 456 sn_init_cpei_timer();
417 457
418#ifdef CONFIG_PROC_FS 458#ifdef CONFIG_PROC_FS
419 register_sn_procfs(); 459 register_sn_procfs();
420#endif 460#endif
421 461
422 for (i = 0; i < PCI_BUSES_TO_SCAN; i++) { 462 /* busses are not known yet ... */
423 sn_pci_controller_fixup(0, i); 463 for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
424 } 464 sn_pci_controller_fixup(0, i, NULL);
425 465
426 /* 466 /*
427 * Generic Linux PCI Layer has created the pci_bus and pci_dev 467 * Generic Linux PCI Layer has created the pci_bus and pci_dev
@@ -430,9 +470,8 @@ static int __init sn_pci_init(void)
430 */ 470 */
431 471
432 while ((pci_dev = 472 while ((pci_dev =
433 pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { 473 pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
434 sn_pci_fixup_slot(pci_dev); 474 sn_pci_fixup_slot(pci_dev);
435 }
436 475
437 sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ 476 sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */
438 477
@@ -474,3 +513,8 @@ cnodeid_get_geoid(cnodeid_t cnode)
474} 513}
475 514
476subsys_initcall(sn_pci_init); 515subsys_initcall(sn_pci_init);
516EXPORT_SYMBOL(sn_pci_fixup_slot);
517EXPORT_SYMBOL(sn_pci_unfixup_slot);
518EXPORT_SYMBOL(sn_pci_controller_fixup);
519EXPORT_SYMBOL(sn_bus_store_sysdata);
520EXPORT_SYMBOL(sn_bus_free_sysdata);
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index cf4dbf9645f1..84d276a14ecb 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -284,7 +284,6 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
284 int cpu = nasid_slice_to_cpuid(nasid, slice); 284 int cpu = nasid_slice_to_cpuid(nasid, slice);
285 285
286 pci_dev_get(pci_dev); 286 pci_dev_get(pci_dev);
287
288 sn_irq_info->irq_cpuid = cpu; 287 sn_irq_info->irq_cpuid = cpu;
289 sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev); 288 sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
290 289
@@ -305,15 +304,16 @@ void sn_irq_unfixup(struct pci_dev *pci_dev)
305 return; 304 return;
306 305
307 sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info; 306 sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info;
308 if (!sn_irq_info || !sn_irq_info->irq_irq) 307 if (!sn_irq_info || !sn_irq_info->irq_irq) {
308 kfree(sn_irq_info);
309 return; 309 return;
310 }
310 311
311 unregister_intr_pda(sn_irq_info); 312 unregister_intr_pda(sn_irq_info);
312 spin_lock(&sn_irq_info_lock); 313 spin_lock(&sn_irq_info_lock);
313 list_del_rcu(&sn_irq_info->list); 314 list_del_rcu(&sn_irq_info->list);
314 spin_unlock(&sn_irq_info_lock); 315 spin_unlock(&sn_irq_info_lock);
315 call_rcu(&sn_irq_info->rcu, sn_irq_info_free); 316 call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
316
317 pci_dev_put(pci_dev); 317 pci_dev_put(pci_dev);
318} 318}
319 319
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 9bc4de4a3ec0..9813da56d311 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -18,6 +18,40 @@
18#include "xtalk/xwidgetdev.h" 18#include "xtalk/xwidgetdev.h"
19#include "xtalk/hubdev.h" 19#include "xtalk/hubdev.h"
20 20
21int
22sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
23{
24 struct ia64_sal_retval ret_stuff;
25 uint64_t busnum;
26
27 ret_stuff.status = 0;
28 ret_stuff.v0 = 0;
29
30 busnum = soft->pbi_buscommon.bs_persist_busnum;
31 SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, (u64) busnum,
32 (u64) device, (u64) resp, 0, 0, 0, 0);
33
34 return (int)ret_stuff.v0;
35}
36
37int
38sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action,
39 void *resp)
40{
41 struct ia64_sal_retval ret_stuff;
42 uint64_t busnum;
43
44 ret_stuff.status = 0;
45 ret_stuff.v0 = 0;
46
47 busnum = soft->pbi_buscommon.bs_persist_busnum;
48 SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE,
49 (u64) busnum, (u64) device, (u64) action,
50 (u64) resp, 0, 0, 0);
51
52 return (int)ret_stuff.v0;
53}
54
21static int sal_pcibr_error_interrupt(struct pcibus_info *soft) 55static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
22{ 56{
23 struct ia64_sal_retval ret_stuff; 57 struct ia64_sal_retval ret_stuff;
@@ -187,3 +221,6 @@ pcibr_init_provider(void)
187 221
188 return 0; 222 return 0;
189} 223}
224
225EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);
226EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);