diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-07-13 16:23:51 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-07-13 16:23:51 -0400 |
commit | 327309e899662b482c58cf25f574513d38b5788c (patch) | |
tree | 069de438aa0e92dd9b6ba28e6b207e2cd07151a5 /arch/ia64/sn/kernel/io_init.c | |
parent | 0c168775709faa74c1b87f1e61046e0c51ade7f3 (diff) | |
parent | c32511e2718618f0b53479eb36e07439aa363a74 (diff) |
Merge upstream 2.6.13-rc3 into ieee80211 branch of netdev-2.6.
Diffstat (limited to 'arch/ia64/sn/kernel/io_init.c')
-rw-r--r-- | arch/ia64/sn/kernel/io_init.c | 185 |
1 files changed, 117 insertions, 68 deletions
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 783eb4323847..a67f39e448cb 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -9,21 +9,28 @@ | |||
9 | #include <linux/bootmem.h> | 9 | #include <linux/bootmem.h> |
10 | #include <linux/nodemask.h> | 10 | #include <linux/nodemask.h> |
11 | #include <asm/sn/types.h> | 11 | #include <asm/sn/types.h> |
12 | #include <asm/sn/sn_sal.h> | ||
13 | #include <asm/sn/addrs.h> | 12 | #include <asm/sn/addrs.h> |
14 | #include <asm/sn/pcibus_provider_defs.h> | ||
15 | #include <asm/sn/pcidev.h> | ||
16 | #include "pci/pcibr_provider.h" | ||
17 | #include "xtalk/xwidgetdev.h" | ||
18 | #include <asm/sn/geo.h> | 13 | #include <asm/sn/geo.h> |
19 | #include "xtalk/hubdev.h" | ||
20 | #include <asm/sn/io.h> | 14 | #include <asm/sn/io.h> |
15 | #include <asm/sn/pcibr_provider.h> | ||
16 | #include <asm/sn/pcibus_provider_defs.h> | ||
17 | #include <asm/sn/pcidev.h> | ||
21 | #include <asm/sn/simulator.h> | 18 | #include <asm/sn/simulator.h> |
19 | #include <asm/sn/sn_sal.h> | ||
22 | #include <asm/sn/tioca_provider.h> | 20 | #include <asm/sn/tioca_provider.h> |
21 | #include "xtalk/hubdev.h" | ||
22 | #include "xtalk/xwidgetdev.h" | ||
23 | 23 | ||
24 | char master_baseio_wid; | ||
25 | nasid_t master_nasid = INVALID_NASID; /* Partition Master */ | 24 | nasid_t master_nasid = INVALID_NASID; /* Partition Master */ |
26 | 25 | ||
26 | static struct list_head sn_sysdata_list; | ||
27 | |||
28 | /* sysdata list struct */ | ||
29 | struct sysdata_el { | ||
30 | struct list_head entry; | ||
31 | void *sysdata; | ||
32 | }; | ||
33 | |||
27 | struct slab_info { | 34 | struct slab_info { |
28 | struct hubdev_info hubdev; | 35 | struct hubdev_info hubdev; |
29 | }; | 36 | }; |
@@ -138,23 +145,6 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, | |||
138 | } | 145 | } |
139 | 146 | ||
140 | /* | 147 | /* |
141 | * sn_alloc_pci_sysdata() - This routine allocates a pci controller | ||
142 | * which is expected as the pci_dev and pci_bus sysdata by the Linux | ||
143 | * PCI infrastructure. | ||
144 | */ | ||
145 | static inline struct pci_controller *sn_alloc_pci_sysdata(void) | ||
146 | { | ||
147 | struct pci_controller *pci_sysdata; | ||
148 | |||
149 | pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL); | ||
150 | if (!pci_sysdata) | ||
151 | BUG(); | ||
152 | |||
153 | memset(pci_sysdata, 0, sizeof(*pci_sysdata)); | ||
154 | return pci_sysdata; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for | 148 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for |
159 | * each node in the system. | 149 | * each node in the system. |
160 | */ | 150 | */ |
@@ -221,22 +211,34 @@ static void sn_fixup_ionodes(void) | |||
221 | 211 | ||
222 | } | 212 | } |
223 | 213 | ||
214 | void 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 | |||
224 | /* | 223 | /* |
225 | * 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 |
226 | * consistent with the Linux PCI abstraction layer. Resources acquired | 225 | * consistent with the Linux PCI abstraction layer. Resources acquired |
227 | * from our PCI provider include PIO maps to BAR space and interrupt | 226 | * from our PCI provider include PIO maps to BAR space and interrupt |
228 | * objects. | 227 | * objects. |
229 | */ | 228 | */ |
230 | static void sn_pci_fixup_slot(struct pci_dev *dev) | 229 | void sn_pci_fixup_slot(struct pci_dev *dev) |
231 | { | 230 | { |
232 | int idx; | 231 | int idx; |
233 | int segment = 0; | 232 | int segment = 0; |
234 | uint64_t size; | ||
235 | struct sn_irq_info *sn_irq_info; | ||
236 | struct pci_dev *host_pci_dev; | ||
237 | int status = 0; | 233 | int status = 0; |
238 | struct pcibus_bussoft *bs; | 234 | struct pcibus_bussoft *bs; |
235 | struct pci_bus *host_pci_bus; | ||
236 | struct pci_dev *host_pci_dev; | ||
237 | struct sn_irq_info *sn_irq_info; | ||
238 | unsigned long size; | ||
239 | unsigned int bus_no, devfn; | ||
239 | 240 | ||
241 | pci_dev_get(dev); /* for the sysdata pointer */ | ||
240 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); | 242 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); |
241 | if (SN_PCIDEV_INFO(dev) <= 0) | 243 | if (SN_PCIDEV_INFO(dev) <= 0) |
242 | BUG(); /* Cannot afford to run out of memory */ | 244 | BUG(); /* Cannot afford to run out of memory */ |
@@ -253,7 +255,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
253 | (u64) __pa(SN_PCIDEV_INFO(dev)), | 255 | (u64) __pa(SN_PCIDEV_INFO(dev)), |
254 | (u64) __pa(sn_irq_info)); | 256 | (u64) __pa(sn_irq_info)); |
255 | if (status) | 257 | if (status) |
256 | BUG(); /* Cannot get platform pci device information information */ | 258 | BUG(); /* Cannot get platform pci device information */ |
257 | 259 | ||
258 | /* Copy over PIO Mapped Addresses */ | 260 | /* Copy over PIO Mapped Addresses */ |
259 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { | 261 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { |
@@ -275,15 +277,21 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
275 | dev->resource[idx].parent = &iomem_resource; | 277 | dev->resource[idx].parent = &iomem_resource; |
276 | } | 278 | } |
277 | 279 | ||
278 | /* set up host bus linkages */ | 280 | /* |
279 | bs = SN_PCIBUS_BUSSOFT(dev->bus); | 281 | * Using the PROMs values for the PCI host bus, get the Linux |
280 | host_pci_dev = | 282 | * PCI host_pci_dev struct and set up host bus linkages |
281 | pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32, | 283 | */ |
282 | SN_PCIDEV_INFO(dev)-> | 284 | |
283 | pdi_slot_host_handle & 0xffffffff); | 285 | bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32; |
286 | devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; | ||
287 | host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no); | ||
288 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); | ||
289 | |||
290 | SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; | ||
284 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = | 291 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = |
285 | SN_PCIDEV_INFO(host_pci_dev); | 292 | SN_PCIDEV_INFO(host_pci_dev); |
286 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; | 293 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; |
294 | bs = SN_PCIBUS_BUSSOFT(dev->bus); | ||
287 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; | 295 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; |
288 | 296 | ||
289 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { | 297 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { |
@@ -297,6 +305,9 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
297 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; | 305 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; |
298 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; | 306 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; |
299 | sn_irq_fixup(dev, sn_irq_info); | 307 | sn_irq_fixup(dev, sn_irq_info); |
308 | } else { | ||
309 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL; | ||
310 | kfree(sn_irq_info); | ||
300 | } | 311 | } |
301 | } | 312 | } |
302 | 313 | ||
@@ -304,55 +315,57 @@ static void sn_pci_fixup_slot(struct pci_dev *dev) | |||
304 | * 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 |
305 | * consistent with the Linux PCI abstraction layer. | 316 | * consistent with the Linux PCI abstraction layer. |
306 | */ | 317 | */ |
307 | static void sn_pci_controller_fixup(int segment, int busnum) | 318 | void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) |
308 | { | 319 | { |
309 | int status = 0; | 320 | int status = 0; |
310 | int nasid, cnode; | 321 | int nasid, cnode; |
311 | struct pci_bus *bus; | ||
312 | struct pci_controller *controller; | 322 | struct pci_controller *controller; |
313 | struct pcibus_bussoft *prom_bussoft_ptr; | 323 | struct pcibus_bussoft *prom_bussoft_ptr; |
314 | struct hubdev_info *hubdev_info; | 324 | struct hubdev_info *hubdev_info; |
315 | void *provider_soft; | 325 | void *provider_soft; |
316 | struct sn_pcibus_provider *provider; | 326 | struct sn_pcibus_provider *provider; |
317 | 327 | ||
318 | status = | 328 | status = sal_get_pcibus_info((u64) segment, (u64) busnum, |
319 | sal_get_pcibus_info((u64) segment, (u64) busnum, | 329 | (u64) ia64_tpa(&prom_bussoft_ptr)); |
320 | (u64) ia64_tpa(&prom_bussoft_ptr)); | 330 | if (status > 0) |
321 | if (status > 0) { | 331 | return; /*bus # does not exist */ |
322 | return; /* bus # does not exist */ | ||
323 | } | ||
324 | |||
325 | prom_bussoft_ptr = __va(prom_bussoft_ptr); | 332 | prom_bussoft_ptr = __va(prom_bussoft_ptr); |
326 | controller = sn_alloc_pci_sysdata(); | ||
327 | /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */ | ||
328 | 333 | ||
329 | 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 | |||
330 | if (bus == NULL) { | 338 | if (bus == NULL) { |
331 | 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; | ||
332 | } | 343 | } |
333 | 344 | ||
345 | if (bus->sysdata) | ||
346 | goto error_return; /* sysdata already alloc'd */ | ||
347 | |||
334 | /* | 348 | /* |
335 | * Per-provider fixup. Copies the contents from prom to local | 349 | * Per-provider fixup. Copies the contents from prom to local |
336 | * area and links SN_PCIBUS_BUSSOFT(). | 350 | * area and links SN_PCIBUS_BUSSOFT(). |
337 | */ | 351 | */ |
338 | 352 | ||
339 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) { | 353 | if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) |
340 | return; /* unsupported asic type */ | 354 | return; /* unsupported asic type */ |
341 | } | 355 | |
356 | if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB) | ||
357 | goto error_return; /* no further fixup necessary */ | ||
342 | 358 | ||
343 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; | 359 | provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type]; |
344 | if (provider == NULL) { | 360 | if (provider == NULL) |
345 | return; /* no provider registerd for this asic */ | 361 | return; /* no provider registerd for this asic */ |
346 | } | ||
347 | 362 | ||
348 | provider_soft = NULL; | 363 | provider_soft = NULL; |
349 | if (provider->bus_fixup) { | 364 | if (provider->bus_fixup) |
350 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); | 365 | provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr); |
351 | } | ||
352 | 366 | ||
353 | if (provider_soft == NULL) { | 367 | if (provider_soft == NULL) |
354 | return; /* fixup failed or not applicable */ | 368 | return; /* fixup failed or not applicable */ |
355 | } | ||
356 | 369 | ||
357 | /* | 370 | /* |
358 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr | 371 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr |
@@ -361,12 +374,47 @@ static void sn_pci_controller_fixup(int segment, int busnum) | |||
361 | 374 | ||
362 | bus->sysdata = controller; | 375 | bus->sysdata = controller; |
363 | PCI_CONTROLLER(bus)->platform_data = provider_soft; | 376 | PCI_CONTROLLER(bus)->platform_data = provider_soft; |
364 | |||
365 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); | 377 | nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base); |
366 | cnode = nasid_to_cnodeid(nasid); | 378 | cnode = nasid_to_cnodeid(nasid); |
367 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); | 379 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); |
368 | SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = | 380 | SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info = |
369 | &(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 | |||
385 | error_return: | ||
386 | |||
387 | kfree(controller); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | void 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 | |||
404 | void sn_bus_free_sysdata(void) | ||
405 | { | ||
406 | struct sysdata_el *element; | ||
407 | struct list_head *list; | ||
408 | |||
409 | sn_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; | ||
370 | } | 418 | } |
371 | 419 | ||
372 | /* | 420 | /* |
@@ -403,20 +451,17 @@ static int __init sn_pci_init(void) | |||
403 | */ | 451 | */ |
404 | ia64_max_iommu_merge_mask = ~PAGE_MASK; | 452 | ia64_max_iommu_merge_mask = ~PAGE_MASK; |
405 | sn_fixup_ionodes(); | 453 | sn_fixup_ionodes(); |
406 | sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL); | 454 | sn_irq_lh_init(); |
407 | if (sn_irq <= 0) | 455 | INIT_LIST_HEAD(&sn_sysdata_list); |
408 | BUG(); /* Canno afford to run out of memory. */ | ||
409 | memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS); | ||
410 | |||
411 | sn_init_cpei_timer(); | 456 | sn_init_cpei_timer(); |
412 | 457 | ||
413 | #ifdef CONFIG_PROC_FS | 458 | #ifdef CONFIG_PROC_FS |
414 | register_sn_procfs(); | 459 | register_sn_procfs(); |
415 | #endif | 460 | #endif |
416 | 461 | ||
417 | for (i = 0; i < PCI_BUSES_TO_SCAN; i++) { | 462 | /* busses are not known yet ... */ |
418 | sn_pci_controller_fixup(0, i); | 463 | for (i = 0; i < PCI_BUSES_TO_SCAN; i++) |
419 | } | 464 | sn_pci_controller_fixup(0, i, NULL); |
420 | 465 | ||
421 | /* | 466 | /* |
422 | * 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 |
@@ -425,9 +470,8 @@ static int __init sn_pci_init(void) | |||
425 | */ | 470 | */ |
426 | 471 | ||
427 | while ((pci_dev = | 472 | while ((pci_dev = |
428 | 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) |
429 | sn_pci_fixup_slot(pci_dev); | 474 | sn_pci_fixup_slot(pci_dev); |
430 | } | ||
431 | 475 | ||
432 | sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ | 476 | sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */ |
433 | 477 | ||
@@ -469,3 +513,8 @@ cnodeid_get_geoid(cnodeid_t cnode) | |||
469 | } | 513 | } |
470 | 514 | ||
471 | subsys_initcall(sn_pci_init); | 515 | subsys_initcall(sn_pci_init); |
516 | EXPORT_SYMBOL(sn_pci_fixup_slot); | ||
517 | EXPORT_SYMBOL(sn_pci_unfixup_slot); | ||
518 | EXPORT_SYMBOL(sn_pci_controller_fixup); | ||
519 | EXPORT_SYMBOL(sn_bus_store_sysdata); | ||
520 | EXPORT_SYMBOL(sn_bus_free_sysdata); | ||