summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-20 14:54:55 +1100
committerPaul Mackerras <paulus@samba.org>2007-12-20 16:18:10 +1100
commit50c9bc2fc86fddd39eea6a12ceb81585bc2aafaa (patch)
treea6021e68bdc0477ada4bc81d04443e3316cdbb4f
parent3fd94c6b1a1158d3e0e505b0a00c3a707b5fcd40 (diff)
[POWERPC] fix iSeries PCI resource management
The way iSeries manages PCI IO and Memory resources is a bit strange and is based on overriding the content of those resources with home cooked ones afterward. This changes it a bit to better integrate with the new resource handling so that the "virtual" tokens that iSeries replaces resources with are done from the proper per-device fixup hook, and bridge resources are set to enclose that token space. This fixes various things such as the output of /proc/iomem & ioports, among others. This also fixes up various boot messages as well. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/kernel/pci-common.c16
-rw-r--r--arch/powerpc/kernel/pci_64.c19
-rw-r--r--arch/powerpc/platforms/iseries/pci.c125
-rw-r--r--arch/powerpc/platforms/iseries/pci.h4
-rw-r--r--arch/powerpc/platforms/iseries/setup.c37
5 files changed, 122 insertions, 79 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index d804c8d0be00..f706b7e83d7e 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -190,6 +190,20 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
struct of_irq oirq;
unsigned int virq;
+ /* The current device-tree that iSeries generates from the HV
+ * PCI informations doesn't contain proper interrupt routing,
+ * and all the fallback would do is print out crap, so we
+ * don't attempt to resolve the interrupts here at all, some
+ * iSeries specific fixup does it.
+ *
+ * In the long run, we will hopefully fix the generated device-tree
+ * instead.
+ */
+#ifdef CONFIG_PPC_ISERIES
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return -1;
+#endif
+
DBG("Try to map irq for %s...\n", pci_name(pci_dev));
#ifdef DEBUG
@@ -946,7 +960,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
|| res->start > res->end)
continue;
if (bus->parent == NULL)
- pr = (res->flags & IORESOURCE_IO)?
+ pr = (res->flags & IORESOURCE_IO) ?
&ioport_resource : &iomem_resource;
else {
/* Don't bother with non-root busses when
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 794359d8686b..2ec040b314d4 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -359,7 +359,7 @@ void __devinit scan_phb(struct pci_controller *hose)
int i, mode;
struct resource *res;
- DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
+ DBG("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>");
/* Create an empty bus for the toplevel */
bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
@@ -375,9 +375,22 @@ void __devinit scan_phb(struct pci_controller *hose)
pcibios_map_io_space(bus);
/* Wire up PHB bus resources */
- bus->resource[0] = res = &hose->io_resource;
- for (i = 0; i < 3; ++i)
+ if (hose->io_resource.flags) {
+ DBG("PCI: PHB IO resource = %016lx-%016lx [%lx]\n",
+ hose->io_resource.start, hose->io_resource.end,
+ hose->io_resource.flags);
+ bus->resource[0] = res = &hose->io_resource;
+ }
+ for (i = 0; i < 3; ++i) {
+ DBG("PCI: PHB MEM resource %d = %016lx-%016lx [%lx]\n", i,
+ hose->mem_resources[i].start,
+ hose->mem_resources[i].end,
+ hose->mem_resources[i].flags);
bus->resource[i+1] = &hose->mem_resources[i];
+ }
+ DBG("PCI: PHB MEM offset = %016lx\n", hose->pci_mem_offset);
+ DBG("PCI: PHB IO offset = %08lx\n",
+ (unsigned long)hose->io_base_virt - _IO_BASE);
/* Get probe mode and perform scan */
mode = PCI_PROBE_NORMAL;
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 68f248b4c696..30e3d992dc0d 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -20,6 +20,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
+#undef DEBUG
+
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
@@ -58,6 +61,7 @@ static int limit_pci_retries = 1; /* Set Retry Error on. */
#define IOMM_TABLE_MAX_ENTRIES 1024
#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL
#define BASE_IO_MEMORY 0xE000000000000000UL
+#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL
static unsigned long max_io_memory = BASE_IO_MEMORY;
static long current_iomm_table_entry;
@@ -68,7 +72,6 @@ static long current_iomm_table_entry;
static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
-static const char pci_io_text[] = "iSeries PCI I/O";
static DEFINE_SPINLOCK(iomm_table_lock);
/*
@@ -279,8 +282,8 @@ out_free:
* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
* controller
*/
-static void __init iseries_device_information(struct pci_dev *pdev, int count,
- u16 bus, HvSubBusNumber subbus)
+static void __init iseries_device_information(struct pci_dev *pdev,
+ u16 bus, HvSubBusNumber subbus)
{
u8 frame = 0;
char card[4];
@@ -290,10 +293,9 @@ static void __init iseries_device_information(struct pci_dev *pdev, int count,
ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
if (iseries_get_location_code(bus, agent, &frame, card)) {
- printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, "
- "Card %4s 0x%04X\n", count, bus,
- PCI_SLOT(pdev->devfn), pdev->vendor, frame,
- card, (int)(pdev->class >> 8));
+ printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
+ "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor,
+ frame, card, (int)(pdev->class >> 8));
}
}
@@ -323,7 +325,6 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
* Set Resource values.
*/
spin_lock(&iomm_table_lock);
- bar_res->name = pci_io_text;
bar_res->start = BASE_IO_MEMORY +
IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
bar_res->end = bar_res->start + bar_size - 1;
@@ -393,61 +394,63 @@ static struct device_node *find_device_node(int bus, int devfn)
}
/*
- * iSeries_pci_final_fixup(void)
+ * iSeries_pcibios_fixup_resources
+ *
+ * Fixes up all resources for devices
*/
-void __init iSeries_pci_final_fixup(void)
+void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
{
- struct pci_dev *pdev = NULL;
+ const u32 *agent;
+ const u32 *sub_bus;
+ unsigned char bus = pdev->bus->number;
struct device_node *node;
- int num_dev = 0;
-
- /* Fix up at the device node and pci_dev relationship */
- mf_display_src(0xC9000100);
-
- printk("pcibios_final_fixup\n");
- for_each_pci_dev(pdev) {
- const u32 *agent;
- const u32 *sub_bus;
- unsigned char bus = pdev->bus->number;
-
- node = find_device_node(bus, pdev->devfn);
- printk("pci dev %p (%x.%x), node %p\n", pdev, bus,
- pdev->devfn, node);
- if (!node) {
- printk("PCI: Device Tree not found for 0x%016lX\n",
- (unsigned long)pdev);
- continue;
- }
-
- agent = of_get_property(node, "linux,agent-id", NULL);
- sub_bus = of_get_property(node, "linux,subbus", NULL);
- if (agent && sub_bus) {
- u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
- int err;
-
- err = HvCallXm_connectBusUnit(bus, *sub_bus,
- *agent, irq);
- if (err)
- pci_log_error("Connect Bus Unit",
- bus, *sub_bus, *agent, err);
- else {
- err = HvCallPci_configStore8(bus, *sub_bus,
+ int i;
+
+ node = find_device_node(bus, pdev->devfn);
+ pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
+ pci_name(pdev), pdev, node);
+ if (!node) {
+ printk("PCI: %s disabled, device tree entry not found !\n",
+ pci_name(pdev));
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++)
+ pdev->resource[i].flags = 0;
+ return;
+ }
+ sub_bus = of_get_property(node, "linux,subbus", NULL);
+ agent = of_get_property(node, "linux,agent-id", NULL);
+ if (agent && sub_bus) {
+ u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
+ int err;
+
+ err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
+ if (err)
+ pci_log_error("Connect Bus Unit",
+ bus, *sub_bus, *agent, err);
+ else {
+ err = HvCallPci_configStore8(bus, *sub_bus,
*agent, PCI_INTERRUPT_LINE, irq);
- if (err)
- pci_log_error("PciCfgStore Irq Failed!",
+ if (err)
+ pci_log_error("PciCfgStore Irq Failed!",
bus, *sub_bus, *agent, err);
- else
- pdev->irq = irq;
- }
+ else
+ pdev->irq = irq;
}
-
- num_dev++;
- pdev->sysdata = node;
- PCI_DN(node)->pcidev = pdev;
- allocate_device_bars(pdev);
- iseries_device_information(pdev, num_dev, bus, *sub_bus);
- iommu_devnode_init_iSeries(pdev, node);
}
+
+ pdev->sysdata = node;
+ PCI_DN(node)->pcidev = pdev;
+ allocate_device_bars(pdev);
+ iseries_device_information(pdev, bus, *sub_bus);
+ iommu_devnode_init_iSeries(pdev, node);
+}
+
+/*
+ * iSeries_pci_final_fixup(void)
+ */
+void __init iSeries_pci_final_fixup(void)
+{
+ /* Fix up at the device node and pci_dev relationship */
+ mf_display_src(0xC9000100);
iSeries_activate_IRQs();
mf_display_src(0xC9000200);
}
@@ -894,10 +897,18 @@ void __init iSeries_pcibios_init(void)
/* All legacy iSeries PHBs are in domain zero */
phb->global_number = 0;
- phb->pci_mem_offset = bus;
phb->first_busno = bus;
phb->last_busno = bus;
phb->ops = &iSeries_pci_ops;
+ phb->io_base_virt = (void __iomem *)_IO_BASE;
+ phb->io_resource.flags = IORESOURCE_IO;
+ phb->io_resource.start = BASE_IO_MEMORY;
+ phb->io_resource.end = END_IO_MEMORY;
+ phb->io_resource.name = "iSeries PCI IO";
+ phb->mem_resources[0].flags = IORESOURCE_MEM;
+ phb->mem_resources[0].start = BASE_IO_MEMORY;
+ phb->mem_resources[0].end = END_IO_MEMORY;
+ phb->mem_resources[0].name = "Series PCI MEM";
}
of_node_put(root);
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h
index 180aa74afb2d..d9cf974c2718 100644
--- a/arch/powerpc/platforms/iseries/pci.h
+++ b/arch/powerpc/platforms/iseries/pci.h
@@ -43,12 +43,16 @@
#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
+struct pci_dev;
+
#ifdef CONFIG_PCI
extern void iSeries_pcibios_init(void);
extern void iSeries_pci_final_fixup(void);
+extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);
#else
static inline void iSeries_pcibios_init(void) { }
static inline void iSeries_pci_final_fixup(void) { }
+static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}
#endif
#endif /* _PLATFORMS_ISERIES_PCI_H */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 5616219a20d5..b72120751bbe 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -639,24 +639,25 @@ static int __init iseries_probe(void)
}
define_machine(iseries) {
- .name = "iSeries",
- .setup_arch = iSeries_setup_arch,
- .show_cpuinfo = iSeries_show_cpuinfo,
- .init_IRQ = iSeries_init_IRQ,
- .get_irq = iSeries_get_irq,
- .init_early = iSeries_init_early,
- .pcibios_fixup = iSeries_pci_final_fixup,
- .restart = mf_reboot,
- .power_off = mf_power_off,
- .halt = mf_power_off,
- .get_boot_time = iSeries_get_boot_time,
- .set_rtc_time = iSeries_set_rtc_time,
- .get_rtc_time = iSeries_get_rtc_time,
- .calibrate_decr = generic_calibrate_decr,
- .progress = iSeries_progress,
- .probe = iseries_probe,
- .ioremap = iseries_ioremap,
- .iounmap = iseries_iounmap,
+ .name = "iSeries",
+ .setup_arch = iSeries_setup_arch,
+ .show_cpuinfo = iSeries_show_cpuinfo,
+ .init_IRQ = iSeries_init_IRQ,
+ .get_irq = iSeries_get_irq,
+ .init_early = iSeries_init_early,
+ .pcibios_fixup = iSeries_pci_final_fixup,
+ .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
+ .restart = mf_reboot,
+ .power_off = mf_power_off,
+ .halt = mf_power_off,
+ .get_boot_time = iSeries_get_boot_time,
+ .set_rtc_time = iSeries_set_rtc_time,
+ .get_rtc_time = iSeries_get_rtc_time,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = iSeries_progress,
+ .probe = iseries_probe,
+ .ioremap = iseries_ioremap,
+ .iounmap = iseries_iounmap,
/* XXX Implement enable_pmcs for iSeries */
};