|
@@ -3,7 +3,7 @@
|
|
|
* License. See the file "COPYING" in the main directory of this archive
|
|
|
* for more details.
|
|
|
*
|
|
|
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
|
|
|
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
|
|
|
*/
|
|
|
|
|
|
#include <linux/bootmem.h>
|
|
@@ -146,6 +146,24 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
|
|
|
return ret_stuff.v0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
|
|
|
+ * device.
|
|
|
+ */
|
|
|
+inline struct pcidev_info *
|
|
|
+sn_pcidev_info_get(struct pci_dev *dev)
|
|
|
+{
|
|
|
+ struct pcidev_info *pcidev;
|
|
|
+
|
|
|
+ list_for_each_entry(pcidev,
|
|
|
+ &(SN_PCI_CONTROLLER(dev)->pcidev_info), pdi_list) {
|
|
|
+ if (pcidev->pdi_linux_pcidev == dev) {
|
|
|
+ return pcidev;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* sn_fixup_ionodes() - This routine initializes the HUB data strcuture for
|
|
|
* each node in the system.
|
|
@@ -229,6 +247,50 @@ static void sn_fixup_ionodes(void)
|
|
|
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * sn_pci_window_fixup() - Create a pci_window for each device resource.
|
|
|
+ * Until ACPI support is added, we need this code
|
|
|
+ * to setup pci_windows for use by
|
|
|
+ * pcibios_bus_to_resource(),
|
|
|
+ * pcibios_resource_to_bus(), etc.
|
|
|
+ */
|
|
|
+static void
|
|
|
+sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
|
|
|
+ int64_t * pci_addrs)
|
|
|
+{
|
|
|
+ struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
|
|
|
+ unsigned int i;
|
|
|
+ unsigned int idx;
|
|
|
+ unsigned int new_count;
|
|
|
+ struct pci_window *new_window;
|
|
|
+
|
|
|
+ if (count == 0)
|
|
|
+ return;
|
|
|
+ idx = controller->windows;
|
|
|
+ new_count = controller->windows + count;
|
|
|
+ new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
|
|
|
+ if (new_window == NULL)
|
|
|
+ BUG();
|
|
|
+ if (controller->window) {
|
|
|
+ memcpy(new_window, controller->window,
|
|
|
+ sizeof(struct pci_window) * controller->windows);
|
|
|
+ kfree(controller->window);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Setup a pci_window for each device resource. */
|
|
|
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
|
|
|
+ if (pci_addrs[i] == -1)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
|
|
|
+ new_window[idx].resource = dev->resource[i];
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+
|
|
|
+ controller->windows = new_count;
|
|
|
+ controller->window = new_window;
|
|
|
+}
|
|
|
+
|
|
|
void sn_pci_unfixup_slot(struct pci_dev *dev)
|
|
|
{
|
|
|
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)
|
|
|
*/
|
|
|
void sn_pci_fixup_slot(struct pci_dev *dev)
|
|
|
{
|
|
|
+ unsigned int count = 0;
|
|
|
int idx;
|
|
|
int segment = pci_domain_nr(dev->bus);
|
|
|
int status = 0;
|
|
|
struct pcibus_bussoft *bs;
|
|
|
struct pci_bus *host_pci_bus;
|
|
|
struct pci_dev *host_pci_dev;
|
|
|
+ struct pcidev_info *pcidev_info;
|
|
|
+ int64_t pci_addrs[PCI_ROM_RESOURCE + 1];
|
|
|
struct sn_irq_info *sn_irq_info;
|
|
|
unsigned long size;
|
|
|
unsigned int bus_no, devfn;
|
|
|
|
|
|
pci_dev_get(dev); /* for the sysdata pointer */
|
|
|
- dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
|
|
|
- if (SN_PCIDEV_INFO(dev) <= 0)
|
|
|
+ pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
|
|
|
+ if (pcidev_info <= 0)
|
|
|
BUG(); /* Cannot afford to run out of memory */
|
|
|
- memset(SN_PCIDEV_INFO(dev), 0, sizeof(struct pcidev_info));
|
|
|
|
|
|
sn_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
|
|
|
if (sn_irq_info <= 0)
|
|
@@ -270,22 +334,34 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
|
|
|
/* Call to retrieve pci device information needed by kernel. */
|
|
|
status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number,
|
|
|
dev->devfn,
|
|
|
- (u64) __pa(SN_PCIDEV_INFO(dev)),
|
|
|
+ (u64) __pa(pcidev_info),
|
|
|
(u64) __pa(sn_irq_info));
|
|
|
if (status)
|
|
|
BUG(); /* Cannot get platform pci device information */
|
|
|
|
|
|
+ /* Add pcidev_info to list in sn_pci_controller struct */
|
|
|
+ list_add_tail(&pcidev_info->pdi_list,
|
|
|
+ &(SN_PCI_CONTROLLER(dev->bus)->pcidev_info));
|
|
|
+
|
|
|
/* Copy over PIO Mapped Addresses */
|
|
|
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
|
|
|
unsigned long start, end, addr;
|
|
|
|
|
|
- if (!SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx])
|
|
|
+ if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
|
|
|
+ pci_addrs[idx] = -1;
|
|
|
continue;
|
|
|
+ }
|
|
|
|
|
|
start = dev->resource[idx].start;
|
|
|
end = dev->resource[idx].end;
|
|
|
size = end - start;
|
|
|
- addr = SN_PCIDEV_INFO(dev)->pdi_pio_mapped_addr[idx];
|
|
|
+ if (size == 0) {
|
|
|
+ pci_addrs[idx] = -1;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ pci_addrs[idx] = start;
|
|
|
+ count++;
|
|
|
+ addr = pcidev_info->pdi_pio_mapped_addr[idx];
|
|
|
addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
|
|
|
dev->resource[idx].start = addr;
|
|
|
dev->resource[idx].end = addr + size;
|
|
@@ -294,23 +370,27 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
|
|
|
else
|
|
|
dev->resource[idx].parent = &iomem_resource;
|
|
|
}
|
|
|
+ /* Create a pci_window in the pci_controller struct for
|
|
|
+ * each device resource.
|
|
|
+ */
|
|
|
+ if (count > 0)
|
|
|
+ sn_pci_window_fixup(dev, count, pci_addrs);
|
|
|
|
|
|
/*
|
|
|
* Using the PROMs values for the PCI host bus, get the Linux
|
|
|
* PCI host_pci_dev struct and set up host bus linkages
|
|
|
*/
|
|
|
|
|
|
- bus_no = (SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32) & 0xff;
|
|
|
- devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
|
|
|
+ bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
|
|
|
+ devfn = pcidev_info->pdi_slot_host_handle & 0xffffffff;
|
|
|
host_pci_bus = pci_find_bus(segment, bus_no);
|
|
|
host_pci_dev = pci_get_slot(host_pci_bus, devfn);
|
|
|
|
|
|
- SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
|
|
|
- SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
|
|
|
- SN_PCIDEV_INFO(host_pci_dev);
|
|
|
- SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
|
|
|
+ pcidev_info->host_pci_dev = host_pci_dev;
|
|
|
+ pcidev_info->pdi_linux_pcidev = dev;
|
|
|
+ pcidev_info->pdi_host_pcidev_info = SN_PCIDEV_INFO(host_pci_dev);
|
|
|
bs = SN_PCIBUS_BUSSOFT(dev->bus);
|
|
|
- SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
|
|
|
+ pcidev_info->pdi_pcibus_info = bs;
|
|
|
|
|
|
if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
|
|
|
SN_PCIDEV_BUSPROVIDER(dev) = sn_pci_provider[bs->bs_asic_type];
|
|
@@ -320,11 +400,11 @@ void sn_pci_fixup_slot(struct pci_dev *dev)
|
|
|
|
|
|
/* Only set up IRQ stuff if this device has a host bus context */
|
|
|
if (bs && sn_irq_info->irq_irq) {
|
|
|
- SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
|
|
|
- dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
|
|
|
+ pcidev_info->pdi_sn_irq_info = sn_irq_info;
|
|
|
+ dev->irq = pcidev_info->pdi_sn_irq_info->irq_irq;
|
|
|
sn_irq_fixup(dev, sn_irq_info);
|
|
|
} else {
|
|
|
- SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
|
|
|
+ pcidev_info->pdi_sn_irq_info = NULL;
|
|
|
kfree(sn_irq_info);
|
|
|
}
|
|
|
}
|
|
@@ -338,6 +418,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
|
|
|
int status = 0;
|
|
|
int nasid, cnode;
|
|
|
struct pci_controller *controller;
|
|
|
+ struct sn_pci_controller *sn_controller;
|
|
|
struct pcibus_bussoft *prom_bussoft_ptr;
|
|
|
struct hubdev_info *hubdev_info;
|
|
|
void *provider_soft = NULL;
|
|
@@ -349,10 +430,15 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
|
|
|
return; /*bus # does not exist */
|
|
|
prom_bussoft_ptr = __va(prom_bussoft_ptr);
|
|
|
|
|
|
- controller = kzalloc(sizeof(struct pci_controller), GFP_KERNEL);
|
|
|
+ /* Allocate a sn_pci_controller, which has a pci_controller struct
|
|
|
+ * as the first member.
|
|
|
+ */
|
|
|
+ sn_controller = kzalloc(sizeof(struct sn_pci_controller), GFP_KERNEL);
|
|
|
+ if (!sn_controller)
|
|
|
+ BUG();
|
|
|
+ INIT_LIST_HEAD(&sn_controller->pcidev_info);
|
|
|
+ controller = &sn_controller->pci_controller;
|
|
|
controller->segment = segment;
|
|
|
- if (!controller)
|
|
|
- BUG();
|
|
|
|
|
|
if (bus == NULL) {
|
|
|
bus = pci_scan_bus(busnum, &pci_root_ops, controller);
|
|
@@ -389,6 +475,29 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
|
|
|
goto error_return;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Setup pci_windows for legacy IO and MEM space.
|
|
|
+ * (Temporary until ACPI support is in place.)
|
|
|
+ */
|
|
|
+ controller->window = kcalloc(2, sizeof(struct pci_window), GFP_KERNEL);
|
|
|
+ if (controller->window == NULL)
|
|
|
+ BUG();
|
|
|
+ controller->window[0].offset = prom_bussoft_ptr->bs_legacy_io;
|
|
|
+ controller->window[0].resource.name = "legacy_io";
|
|
|
+ controller->window[0].resource.flags = IORESOURCE_IO;
|
|
|
+ controller->window[0].resource.start = prom_bussoft_ptr->bs_legacy_io;
|
|
|
+ controller->window[0].resource.end =
|
|
|
+ controller->window[0].resource.start + 0xffff;
|
|
|
+ controller->window[0].resource.parent = &ioport_resource;
|
|
|
+ controller->window[1].offset = prom_bussoft_ptr->bs_legacy_mem;
|
|
|
+ controller->window[1].resource.name = "legacy_mem";
|
|
|
+ controller->window[1].resource.flags = IORESOURCE_MEM;
|
|
|
+ controller->window[1].resource.start = prom_bussoft_ptr->bs_legacy_mem;
|
|
|
+ controller->window[1].resource.end =
|
|
|
+ controller->window[1].resource.start + (1024 * 1024) - 1;
|
|
|
+ controller->window[1].resource.parent = &iomem_resource;
|
|
|
+ controller->windows = 2;
|
|
|
+
|
|
|
/*
|
|
|
* Generic bus fixup goes here. Don't reference prom_bussoft_ptr
|
|
|
* after this point.
|
|
@@ -421,7 +530,7 @@ void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
|
|
|
|
|
|
error_return:
|
|
|
|
|
|
- kfree(controller);
|
|
|
+ kfree(sn_controller);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -434,7 +543,7 @@ void sn_bus_store_sysdata(struct pci_dev *dev)
|
|
|
dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
|
|
|
return;
|
|
|
}
|
|
|
- element->sysdata = dev->sysdata;
|
|
|
+ element->sysdata = SN_PCIDEV_INFO(dev);
|
|
|
list_add(&element->entry, &sn_sysdata_list);
|
|
|
}
|
|
|
|