diff options
-rw-r--r-- | arch/ia64/sn/kernel/io_init.c | 153 | ||||
-rw-r--r-- | include/asm-ia64/sn/pcidev.h | 20 |
2 files changed, 148 insertions, 25 deletions
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 05e4ea889981..318087e35b66 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/bootmem.h> | 9 | #include <linux/bootmem.h> |
@@ -147,6 +147,24 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, | |||
147 | } | 147 | } |
148 | 148 | ||
149 | /* | 149 | /* |
150 | * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified | ||
151 | * device. | ||
152 | */ | ||
153 | inline struct pcidev_info * | ||
154 | sn_pcidev_info_get(struct pci_dev *dev) | ||
155 | { | ||
156 | struct pcidev_info *pcidev; | ||
157 | |||
158 | list_for_each_entry(pcidev, | ||
159 | &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) { | ||
160 | if (pcidev->pdi_linux_pcidev == dev) { | ||
161 | return pcidev; | ||
162 | } | ||
163 | } | ||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | /* | ||
150 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for | 168 | * sn_fixup_ionodes() - This routine initializes the HUB data strcuture for |
151 | * each node in the system. | 169 | * each node in the system. |
152 | */ | 170 | */ |
@@ -229,6 +247,50 @@ static void sn_fixup_ionodes(void) | |||
229 | 247 | ||
230 | } | 248 | } |
231 | 249 | ||
250 | /* | ||
251 | * sn_pci_window_fixup() - Create a pci_window for each device resource. | ||
252 | * Until ACPI support is added, we need this code | ||
253 | * to setup pci_windows for use by | ||
254 | * pcibios_bus_to_resource(), | ||
255 | * pcibios_resource_to_bus(), etc. | ||
256 | */ | ||
257 | static void | ||
258 | sn_pci_window_fixup(struct pci_dev *dev, unsigned int count, | ||
259 | int64_t * pci_addrs) | ||
260 | { | ||
261 | struct pci_controller *controller = PCI_CONTROLLER(dev->bus); | ||
262 | unsigned int i; | ||
263 | unsigned int idx; | ||
264 | unsigned int new_count; | ||
265 | struct pci_window *new_window; | ||
266 | |||
267 | if (count == 0) | ||
268 | return; | ||
269 | idx = controller->windows; | ||
270 | new_count = controller->windows + count; | ||
271 | new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL); | ||
272 | if (new_window == NULL) | ||
273 | BUG(); | ||
274 | if (controller->window) { | ||
275 | memcpy(new_window, controller->window, | ||
276 | sizeof(struct pci_window) * controller->windows); | ||
277 | kfree(controller->window); | ||
278 | } | ||
279 | |||
280 | /* Setup a pci_window for each device resource. */ | ||
281 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) { | ||
282 | if (pci_addrs[i] == -1) | ||
283 | continue; | ||
284 | |||
285 | new_window[idx].offset = dev->resource[i].start - pci_addrs[i]; | ||
286 | new_window[idx].resource = dev->resource[i]; | ||
287 | idx++; | ||
288 | } | ||
289 | |||
290 | controller->windows = new_count; | ||
291 | controller->window = new_window; | ||
292 | } | ||
293 | |||
232 | void sn_pci_unfixup_slot(struct pci_dev *dev) | 294 | void sn_pci_unfixup_slot(struct pci_dev *dev) |
233 | { | 295 | { |
234 | struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; | 296 | struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev; |
@@ -246,21 +308,23 @@ void sn_pci_unfixup_slot(struct pci_dev *dev) | |||
246 | */ | 308 | */ |
247 | void sn_pci_fixup_slot(struct pci_dev *dev) | 309 | void sn_pci_fixup_slot(struct pci_dev *dev) |
248 | { | 310 | { |
311 | unsigned int count = 0; | ||
249 | int idx; | 312 | int idx; |
250 | int segment = pci_domain_nr(dev->bus); | 313 | int segment = pci_domain_nr(dev->bus); |
251 | int status = 0; | 314 | int status = 0; |
252 | struct pcibus_bussoft *bs; | 315 | struct pcibus_bussoft *bs; |
253 | struct pci_bus *host_pci_bus; | 316 | struct pci_bus *host_pci_bus; |
254 | struct pci_dev *host_pci_dev; | 317 | struct pci_dev *host_pci_dev; |
318 | struct pcidev_info *pcidev_info; | ||
319 | int64_t pci_addrs[PCI_ROM_RESOURCE + 1]; | ||
255 | struct sn_irq_info *sn_irq_info; | 320 | struct sn_irq_info *sn_irq_info; |
256 | unsigned long size; | 321 | unsigned long size; |
257 | unsigned int bus_no, devfn; | 322 | unsigned int bus_no, devfn; |
258 | 323 | ||
259 | pci_dev_get(dev); /* for the sysdata pointer */ | 324 | pci_dev_get(dev); /* for the sysdata pointer */ |
260 | dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL); | 325 | pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL); |
261 | if (SN_PCIDEV_INFO(dev) <= 0) | 326 | if (pcidev_info <= 0) |
262 | BUG(); /* Cannot afford to run out of memory */ | 327 | BUG(); /* Cannot afford to run out of memory */ |
263 | memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info)); | ||
264 | 328 | ||
265 | sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | 329 | sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL); |
266 | if (sn_irq_info <= 0) | 330 | if (sn_irq_info <= 0) |
@@ -270,22 +334,34 @@ void sn_pci_fixup_slot(struct pci_dev *dev) | |||
270 | /* Call to retrieve pci device information needed by kernel. */ | 334 | /* Call to retrieve pci device information needed by kernel. */ |
271 | status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, | 335 | status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number, |
272 | dev->devfn, | 336 | dev->devfn, |
273 | (u64) __pa(SN_PCIDEV_INFO(dev)), | 337 | (u64) __pa(pcidev_info), |
274 | (u64) __pa(sn_irq_info)); | 338 | (u64) __pa(sn_irq_info)); |
275 | if (status) | 339 | if (status) |
276 | BUG(); /* Cannot get platform pci device information */ | 340 | BUG(); /* Cannot get platform pci device information */ |
277 | 341 | ||
342 | /* Add pcidev_info to list in sn_pci_controller struct */ | ||
343 | list_add_tail(&pcidev_info->pdi_list, | ||
344 | &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info)); | ||
345 | |||
278 | /* Copy over PIO Mapped Addresses */ | 346 | /* Copy over PIO Mapped Addresses */ |
279 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { | 347 | for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) { |
280 | unsigned long start, end, addr; | 348 | unsigned long start, end, addr; |
281 | 349 | ||
282 | if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx]) | 350 | if (!pcidev_info->pdi_pio_mapped_addr[idx]) { |
351 | pci_addrs[idx] = -1; | ||
283 | continue; | 352 | continue; |
353 | } | ||
284 | 354 | ||
285 | start = dev->resource[idx].start; | 355 | start = dev->resource[idx].start; |
286 | end = dev->resource[idx].end; | 356 | end = dev->resource[idx].end; |
287 | size = end - start; | 357 | size = end - start; |
288 | addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx]; | 358 | if (size == 0) { |
359 | pci_addrs[idx] = -1; | ||
360 | continue; | ||
361 | } | ||
362 | pci_addrs[idx] = start; | ||
363 | count++; | ||
364 | addr = pcidev_info->pdi_pio_mapped_addr[idx]; | ||
289 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; | 365 | addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET; |
290 | dev->resource[idx].start = addr; | 366 | dev->resource[idx].start = addr; |
291 | dev->resource[idx].end = addr + size; | 367 | dev->resource[idx].end = addr + size; |
@@ -294,23 +370,27 @@ void sn_pci_fixup_slot(struct pci_dev *dev) | |||
294 | else | 370 | else |
295 | dev->resource[idx].parent = &iomem_resource; | 371 | dev->resource[idx].parent = &iomem_resource; |
296 | } | 372 | } |
373 | /* Create a pci_window in the pci_controller struct for | ||
374 | * each device resource. | ||
375 | */ | ||
376 | if (count > 0) | ||
377 | sn_pci_window_fixup(dev, count, pci_addrs); | ||
297 | 378 | ||
298 | /* | 379 | /* |
299 | * Using the PROMs values for the PCI host bus, get the Linux | 380 | * Using the PROMs values for the PCI host bus, get the Linux |
300 | * PCI host_pci_dev struct and set up host bus linkages | 381 | * PCI host_pci_dev struct and set up host bus linkages |
301 | */ | 382 | */ |
302 | 383 | ||
303 | bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff; | 384 | bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff; |
304 | devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff; | 385 | devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff; |
305 | host_pci_bus = pci_find_bus(segment, bus_no); | 386 | host_pci_bus = pci_find_bus(segment, bus_no); |
306 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); | 387 | host_pci_dev = pci_get_slot(host_pci_bus, devfn); |
307 | 388 | ||
308 | SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev; | 389 | pcidev_info->host_pci_dev = host_pci_dev; |
309 | SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info = | 390 | pcidev_info->pdi_linux_pcidev = dev; |
310 | SN_PCIDEV_INFO(host_pci_dev); | 391 | pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev); |
311 | SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev; | ||
312 | bs = SN_PCIBUS_BUSSOFT(dev->bus); | 392 | bs = SN_PCIBUS_BUSSOFT(dev->bus); |
313 | SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs; | 393 | pcidev_info->pdi_pcibus_info = bs; |
314 | 394 | ||
315 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { | 395 | if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) { |
316 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; | 396 | SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type]; |
@@ -320,11 +400,11 @@ void sn_pci_fixup_slot(struct pci_dev *dev) | |||
320 | 400 | ||
321 | /* Only set up IRQ stuff if this device has a host bus context */ | 401 | /* Only set up IRQ stuff if this device has a host bus context */ |
322 | if (bs && sn_irq_info->irq_irq) { | 402 | if (bs && sn_irq_info->irq_irq) { |
323 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info; | 403 | pcidev_info->pdi_sn_irq_info = sn_irq_info; |
324 | dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq; | 404 | dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq; |
325 | sn_irq_fixup(dev, sn_irq_info); | 405 | sn_irq_fixup(dev, sn_irq_info); |
326 | } else { | 406 | } else { |
327 | SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL; | 407 | pcidev_info->pdi_sn_irq_info = NULL; |
328 | kfree(sn_irq_info); | 408 | kfree(sn_irq_info); |
329 | } | 409 | } |
330 | } | 410 | } |
@@ -338,6 +418,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
338 | int status = 0; | 418 | int status = 0; |
339 | int nasid, cnode; | 419 | int nasid, cnode; |
340 | struct pci_controller *controller; | 420 | struct pci_controller *controller; |
421 | struct sn_pci_controller *sn_controller; | ||
341 | struct pcibus_bussoft *prom_bussoft_ptr; | 422 | struct pcibus_bussoft *prom_bussoft_ptr; |
342 | struct hubdev_info *hubdev_info; | 423 | struct hubdev_info *hubdev_info; |
343 | void *provider_soft = NULL; | 424 | void *provider_soft = NULL; |
@@ -349,10 +430,15 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
349 | return; /*bus # does not exist */ | 430 | return; /*bus # does not exist */ |
350 | prom_bussoft_ptr = __va(prom_bussoft_ptr); | 431 | prom_bussoft_ptr = __va(prom_bussoft_ptr); |
351 | 432 | ||
352 | controller = kzalloc(sizeof(struct pci_controller), GFP_KERNEL); | 433 | /* Allocate a sn_pci_controller, which has a pci_controller struct |
434 | * as the first member. | ||
435 | */ | ||
436 | sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL); | ||
437 | if (!sn_controller) | ||
438 | BUG(); | ||
439 | INIT_LIST_HEAD(&sn_controller->pcidev_info); | ||
440 | controller = &sn_controller->pci_controller; | ||
353 | controller->segment = segment; | 441 | controller->segment = segment; |
354 | if (!controller) | ||
355 | BUG(); | ||
356 | 442 | ||
357 | if (bus == NULL) { | 443 | if (bus == NULL) { |
358 | bus = pci_scan_bus(busnum, &pci_root_ops, controller); | 444 | bus = pci_scan_bus(busnum, &pci_root_ops, controller); |
@@ -390,6 +476,29 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
390 | } | 476 | } |
391 | 477 | ||
392 | /* | 478 | /* |
479 | * Setup pci_windows for legacy IO and MEM space. | ||
480 | * (Temporary until ACPI support is in place.) | ||
481 | */ | ||
482 | controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL); | ||
483 | if (controller->window == NULL) | ||
484 | BUG(); | ||
485 | controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io; | ||
486 | controller->window[0].resource.name = "legacy_io"; | ||
487 | controller->window[0].resource.flags = IORESOURCE_IO; | ||
488 | controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io; | ||
489 | controller->window[0].resource.end = | ||
490 | controller->window[0].resource.start + 0xffff; | ||
491 | controller->window[0].resource.parent = &ioport_resource; | ||
492 | controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem; | ||
493 | controller->window[1].resource.name = "legacy_mem"; | ||
494 | controller->window[1].resource.flags = IORESOURCE_MEM; | ||
495 | controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem; | ||
496 | controller->window[1].resource.end = | ||
497 | controller->window[1].resource.start + (1024 * 1024) - 1; | ||
498 | controller->window[1].resource.parent = &iomem_resource; | ||
499 | controller->windows = 2; | ||
500 | |||
501 | /* | ||
393 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr | 502 | * Generic bus fixup goes here. Don't reference prom_bussoft_ptr |
394 | * after this point. | 503 | * after this point. |
395 | */ | 504 | */ |
@@ -421,7 +530,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus) | |||
421 | 530 | ||
422 | error_return: | 531 | error_return: |
423 | 532 | ||
424 | kfree(controller); | 533 | kfree(sn_controller); |
425 | return; | 534 | return; |
426 | } | 535 | } |
427 | 536 | ||
@@ -434,7 +543,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev) | |||
434 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); | 543 | dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__); |
435 | return; | 544 | return; |
436 | } | 545 | } |
437 | element->sysdata = dev->sysdata; | 546 | element->sysdata = SN_PCIDEV_INFO(dev); |
438 | list_add(&element->entry, &sn_sysdata_list); | 547 | list_add(&element->entry, &sn_sysdata_list); |
439 | } | 548 | } |
440 | 549 | ||
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h index 49711d00ad04..f65d222ca5e8 100644 --- a/include/asm-ia64/sn/pcidev.h +++ b/include/asm-ia64/sn/pcidev.h | |||
@@ -3,15 +3,27 @@ | |||
3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. | 4 | * for more details. |
5 | * | 5 | * |
6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | #ifndef _ASM_IA64_SN_PCI_PCIDEV_H | 8 | #ifndef _ASM_IA64_SN_PCI_PCIDEV_H |
9 | #define _ASM_IA64_SN_PCI_PCIDEV_H | 9 | #define _ASM_IA64_SN_PCI_PCIDEV_H |
10 | 10 | ||
11 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
12 | 12 | ||
13 | #define SN_PCIDEV_INFO(pci_dev) \ | 13 | /* |
14 | ((struct pcidev_info *)(pci_dev)->sysdata) | 14 | * In ia64, pci_dev->sysdata must be a *pci_controller. To provide access to |
15 | * the pcidev_info structs for all devices under a controller, we extend the | ||
16 | * definition of pci_controller, via sn_pci_controller, to include a list | ||
17 | * of pcidev_info. | ||
18 | */ | ||
19 | struct sn_pci_controller { | ||
20 | struct pci_controller pci_controller; | ||
21 | struct list_head pcidev_info; | ||
22 | }; | ||
23 | |||
24 | #define SN_PCI_CONTROLLER(dev) ((struct sn_pci_controller *) dev->sysdata) | ||
25 | |||
26 | #define SN_PCIDEV_INFO(dev) sn_pcidev_info_get(dev) | ||
15 | 27 | ||
16 | #define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \ | 28 | #define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \ |
17 | (struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data)) | 29 | (struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data)) |
@@ -53,11 +65,13 @@ struct pcidev_info { | |||
53 | struct sn_irq_info *pdi_sn_irq_info; | 65 | struct sn_irq_info *pdi_sn_irq_info; |
54 | struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ | 66 | struct sn_pcibus_provider *pdi_provider; /* sn pci ops */ |
55 | struct pci_dev *host_pci_dev; /* host bus link */ | 67 | struct pci_dev *host_pci_dev; /* host bus link */ |
68 | struct list_head pdi_list; /* List of pcidev_info */ | ||
56 | }; | 69 | }; |
57 | 70 | ||
58 | extern void sn_irq_fixup(struct pci_dev *pci_dev, | 71 | extern void sn_irq_fixup(struct pci_dev *pci_dev, |
59 | struct sn_irq_info *sn_irq_info); | 72 | struct sn_irq_info *sn_irq_info); |
60 | extern void sn_irq_unfixup(struct pci_dev *pci_dev); | 73 | extern void sn_irq_unfixup(struct pci_dev *pci_dev); |
74 | extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *); | ||
61 | extern void sn_pci_controller_fixup(int segment, int busnum, | 75 | extern void sn_pci_controller_fixup(int segment, int busnum, |
62 | struct pci_bus *bus); | 76 | struct pci_bus *bus); |
63 | extern void sn_bus_store_sysdata(struct pci_dev *dev); | 77 | extern void sn_bus_store_sysdata(struct pci_dev *dev); |