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); |
