Commit 50c9bc2f authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 3fd94c6b
...@@ -190,6 +190,20 @@ int pci_read_irq_line(struct pci_dev *pci_dev) ...@@ -190,6 +190,20 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
struct of_irq oirq; struct of_irq oirq;
unsigned int virq; 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)); DBG("Try to map irq for %s...\n", pci_name(pci_dev));
#ifdef DEBUG #ifdef DEBUG
...@@ -946,7 +960,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) ...@@ -946,7 +960,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
|| res->start > res->end) || res->start > res->end)
continue; continue;
if (bus->parent == NULL) if (bus->parent == NULL)
pr = (res->flags & IORESOURCE_IO)? pr = (res->flags & IORESOURCE_IO) ?
&ioport_resource : &iomem_resource; &ioport_resource : &iomem_resource;
else { else {
/* Don't bother with non-root busses when /* Don't bother with non-root busses when
......
...@@ -359,7 +359,7 @@ void __devinit scan_phb(struct pci_controller *hose) ...@@ -359,7 +359,7 @@ void __devinit scan_phb(struct pci_controller *hose)
int i, mode; int i, mode;
struct resource *res; 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 */ /* Create an empty bus for the toplevel */
bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node);
...@@ -375,9 +375,22 @@ void __devinit scan_phb(struct pci_controller *hose) ...@@ -375,9 +375,22 @@ void __devinit scan_phb(struct pci_controller *hose)
pcibios_map_io_space(bus); pcibios_map_io_space(bus);
/* Wire up PHB bus resources */ /* Wire up PHB bus resources */
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; bus->resource[0] = res = &hose->io_resource;
for (i = 0; i < 3; ++i) }
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]; 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 */ /* Get probe mode and perform scan */
mode = PCI_PROBE_NORMAL; mode = PCI_PROBE_NORMAL;
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#undef DEBUG
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -58,6 +61,7 @@ static int limit_pci_retries = 1; /* Set Retry Error on. */ ...@@ -58,6 +61,7 @@ static int limit_pci_retries = 1; /* Set Retry Error on. */
#define IOMM_TABLE_MAX_ENTRIES 1024 #define IOMM_TABLE_MAX_ENTRIES 1024
#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL
#define BASE_IO_MEMORY 0xE000000000000000UL #define BASE_IO_MEMORY 0xE000000000000000UL
#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL
static unsigned long max_io_memory = BASE_IO_MEMORY; static unsigned long max_io_memory = BASE_IO_MEMORY;
static long current_iomm_table_entry; static long current_iomm_table_entry;
...@@ -68,7 +72,6 @@ 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 struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
static u8 iobar_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); static DEFINE_SPINLOCK(iomm_table_lock);
/* /*
...@@ -279,7 +282,7 @@ static int __init iseries_get_location_code(u16 bus, HvAgentId agent, ...@@ -279,7 +282,7 @@ static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
* PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
* controller * controller
*/ */
static void __init iseries_device_information(struct pci_dev *pdev, int count, static void __init iseries_device_information(struct pci_dev *pdev,
u16 bus, HvSubBusNumber subbus) u16 bus, HvSubBusNumber subbus)
{ {
u8 frame = 0; u8 frame = 0;
...@@ -290,10 +293,9 @@ static void __init iseries_device_information(struct pci_dev *pdev, int count, ...@@ -290,10 +293,9 @@ static void __init iseries_device_information(struct pci_dev *pdev, int count,
ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
if (iseries_get_location_code(bus, agent, &frame, card)) { if (iseries_get_location_code(bus, agent, &frame, card)) {
printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, " printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
"Card %4s 0x%04X\n", count, bus, "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor,
PCI_SLOT(pdev->devfn), pdev->vendor, frame, frame, card, (int)(pdev->class >> 8));
card, (int)(pdev->class >> 8));
} }
} }
...@@ -323,7 +325,6 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) ...@@ -323,7 +325,6 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
* Set Resource values. * Set Resource values.
*/ */
spin_lock(&iomm_table_lock); spin_lock(&iomm_table_lock);
bar_res->name = pci_io_text;
bar_res->start = BASE_IO_MEMORY + bar_res->start = BASE_IO_MEMORY +
IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
bar_res->end = bar_res->start + bar_size - 1; bar_res->end = bar_res->start + bar_size - 1;
...@@ -393,40 +394,35 @@ static struct device_node *find_device_node(int bus, int devfn) ...@@ -393,40 +394,35 @@ 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;
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 *agent;
const u32 *sub_bus; const u32 *sub_bus;
unsigned char bus = pdev->bus->number; unsigned char bus = pdev->bus->number;
struct device_node *node;
int i;
node = find_device_node(bus, pdev->devfn); node = find_device_node(bus, pdev->devfn);
printk("pci dev %p (%x.%x), node %p\n", pdev, bus, pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
pdev->devfn, node); pci_name(pdev), pdev, node);
if (!node) { if (!node) {
printk("PCI: Device Tree not found for 0x%016lX\n", printk("PCI: %s disabled, device tree entry not found !\n",
(unsigned long)pdev); pci_name(pdev));
continue; for (i = 0; i <= PCI_ROM_RESOURCE; i++)
pdev->resource[i].flags = 0;
return;
} }
agent = of_get_property(node, "linux,agent-id", NULL);
sub_bus = of_get_property(node, "linux,subbus", NULL); sub_bus = of_get_property(node, "linux,subbus", NULL);
agent = of_get_property(node, "linux,agent-id", NULL);
if (agent && sub_bus) { if (agent && sub_bus) {
u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
int err; int err;
err = HvCallXm_connectBusUnit(bus, *sub_bus, err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
*agent, irq);
if (err) if (err)
pci_log_error("Connect Bus Unit", pci_log_error("Connect Bus Unit",
bus, *sub_bus, *agent, err); bus, *sub_bus, *agent, err);
...@@ -441,13 +437,20 @@ void __init iSeries_pci_final_fixup(void) ...@@ -441,13 +437,20 @@ void __init iSeries_pci_final_fixup(void)
} }
} }
num_dev++;
pdev->sysdata = node; pdev->sysdata = node;
PCI_DN(node)->pcidev = pdev; PCI_DN(node)->pcidev = pdev;
allocate_device_bars(pdev); allocate_device_bars(pdev);
iseries_device_information(pdev, num_dev, bus, *sub_bus); iseries_device_information(pdev, bus, *sub_bus);
iommu_devnode_init_iSeries(pdev, node); 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(); iSeries_activate_IRQs();
mf_display_src(0xC9000200); mf_display_src(0xC9000200);
} }
...@@ -894,10 +897,18 @@ void __init iSeries_pcibios_init(void) ...@@ -894,10 +897,18 @@ void __init iSeries_pcibios_init(void)
/* All legacy iSeries PHBs are in domain zero */ /* All legacy iSeries PHBs are in domain zero */
phb->global_number = 0; phb->global_number = 0;
phb->pci_mem_offset = bus;
phb->first_busno = bus; phb->first_busno = bus;
phb->last_busno = bus; phb->last_busno = bus;
phb->ops = &iSeries_pci_ops; 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); of_node_put(root);
......
...@@ -43,12 +43,16 @@ ...@@ -43,12 +43,16 @@
#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7)
#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7)
struct pci_dev;
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
extern void iSeries_pcibios_init(void); extern void iSeries_pcibios_init(void);
extern void iSeries_pci_final_fixup(void); extern void iSeries_pci_final_fixup(void);
extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);
#else #else
static inline void iSeries_pcibios_init(void) { } static inline void iSeries_pcibios_init(void) { }
static inline void iSeries_pci_final_fixup(void) { } static inline void iSeries_pci_final_fixup(void) { }
static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {}
#endif #endif
#endif /* _PLATFORMS_ISERIES_PCI_H */ #endif /* _PLATFORMS_ISERIES_PCI_H */
...@@ -646,6 +646,7 @@ define_machine(iseries) { ...@@ -646,6 +646,7 @@ define_machine(iseries) {
.get_irq = iSeries_get_irq, .get_irq = iSeries_get_irq,
.init_early = iSeries_init_early, .init_early = iSeries_init_early,
.pcibios_fixup = iSeries_pci_final_fixup, .pcibios_fixup = iSeries_pci_final_fixup,
.pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
.restart = mf_reboot, .restart = mf_reboot,
.power_off = mf_power_off, .power_off = mf_power_off,
.halt = mf_power_off, .halt = mf_power_off,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment