aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/ia64/sn/kernel/io_init.c153
-rw-r--r--include/asm-ia64/sn/pcidev.h20
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 */
153inline struct pcidev_info *
154sn_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 */
257static void
258sn_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
232void sn_pci_unfixup_slot(struct pci_dev *dev) 294void 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 */
247void sn_pci_fixup_slot(struct pci_dev *dev) 309void 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
422error_return: 531error_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 */
19struct 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
58extern void sn_irq_fixup(struct pci_dev *pci_dev, 71extern 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);
60extern void sn_irq_unfixup(struct pci_dev *pci_dev); 73extern void sn_irq_unfixup(struct pci_dev *pci_dev);
74extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
61extern void sn_pci_controller_fixup(int segment, int busnum, 75extern void sn_pci_controller_fixup(int segment, int busnum,
62 struct pci_bus *bus); 76 struct pci_bus *bus);
63extern void sn_bus_store_sysdata(struct pci_dev *dev); 77extern void sn_bus_store_sysdata(struct pci_dev *dev);