提交 50c9bc2f 编写于 作者: B Benjamin Herrenschmidt 提交者: 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: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: NPaul Mackerras <paulus@samba.org>
上级 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 */
bus->resource[0] = res = &hose->io_resource; if (hose->io_resource.flags) {
for (i = 0; i < 3; ++i) 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]; 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,8 +282,8 @@ static int __init iseries_get_location_code(u16 bus, HvAgentId agent, ...@@ -279,8 +282,8 @@ 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;
char card[4]; char card[4];
...@@ -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,61 +394,63 @@ static struct device_node *find_device_node(int bus, int devfn) ...@@ -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; struct device_node *node;
int num_dev = 0; int i;
/* Fix up at the device node and pci_dev relationship */ node = find_device_node(bus, pdev->devfn);
mf_display_src(0xC9000100); pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
pci_name(pdev), pdev, node);
printk("pcibios_final_fixup\n"); if (!node) {
for_each_pci_dev(pdev) { printk("PCI: %s disabled, device tree entry not found !\n",
const u32 *agent; pci_name(pdev));
const u32 *sub_bus; for (i = 0; i <= PCI_ROM_RESOURCE; i++)
unsigned char bus = pdev->bus->number; pdev->resource[i].flags = 0;
return;
node = find_device_node(bus, pdev->devfn); }
printk("pci dev %p (%x.%x), node %p\n", pdev, bus, sub_bus = of_get_property(node, "linux,subbus", NULL);
pdev->devfn, node); agent = of_get_property(node, "linux,agent-id", NULL);
if (!node) { if (agent && sub_bus) {
printk("PCI: Device Tree not found for 0x%016lX\n", u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
(unsigned long)pdev); int err;
continue;
} err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
if (err)
agent = of_get_property(node, "linux,agent-id", NULL); pci_log_error("Connect Bus Unit",
sub_bus = of_get_property(node, "linux,subbus", NULL); bus, *sub_bus, *agent, err);
if (agent && sub_bus) { else {
u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); err = HvCallPci_configStore8(bus, *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); *agent, PCI_INTERRUPT_LINE, irq);
if (err) if (err)
pci_log_error("PciCfgStore Irq Failed!", pci_log_error("PciCfgStore Irq Failed!",
bus, *sub_bus, *agent, err); bus, *sub_bus, *agent, err);
else else
pdev->irq = irq; 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(); 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 */
...@@ -639,24 +639,25 @@ static int __init iseries_probe(void) ...@@ -639,24 +639,25 @@ static int __init iseries_probe(void)
} }
define_machine(iseries) { define_machine(iseries) {
.name = "iSeries", .name = "iSeries",
.setup_arch = iSeries_setup_arch, .setup_arch = iSeries_setup_arch,
.show_cpuinfo = iSeries_show_cpuinfo, .show_cpuinfo = iSeries_show_cpuinfo,
.init_IRQ = iSeries_init_IRQ, .init_IRQ = iSeries_init_IRQ,
.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,
.restart = mf_reboot, .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
.power_off = mf_power_off, .restart = mf_reboot,
.halt = mf_power_off, .power_off = mf_power_off,
.get_boot_time = iSeries_get_boot_time, .halt = mf_power_off,
.set_rtc_time = iSeries_set_rtc_time, .get_boot_time = iSeries_get_boot_time,
.get_rtc_time = iSeries_get_rtc_time, .set_rtc_time = iSeries_set_rtc_time,
.calibrate_decr = generic_calibrate_decr, .get_rtc_time = iSeries_get_rtc_time,
.progress = iSeries_progress, .calibrate_decr = generic_calibrate_decr,
.probe = iseries_probe, .progress = iSeries_progress,
.ioremap = iseries_ioremap, .probe = iseries_probe,
.iounmap = iseries_iounmap, .ioremap = iseries_ioremap,
.iounmap = iseries_iounmap,
/* XXX Implement enable_pmcs for iSeries */ /* XXX Implement enable_pmcs for iSeries */
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册