[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>
This commit is contained in:
parent
3fd94c6b1a
commit
50c9bc2fc8
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 @@ static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
|
||||
* 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;
|
||||
@ -392,62 +393,64 @@ static struct device_node *find_device_node(int bus, int devfn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* iSeries_pcibios_fixup_resources
|
||||
*
|
||||
* Fixes up all resources for devices
|
||||
*/
|
||||
void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
|
||||
{
|
||||
const u32 *agent;
|
||||
const u32 *sub_bus;
|
||||
unsigned char bus = pdev->bus->number;
|
||||
struct device_node *node;
|
||||
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!",
|
||||
bus, *sub_bus, *agent, err);
|
||||
else
|
||||
pdev->irq = irq;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 *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,
|
||||
*agent, PCI_INTERRUPT_LINE, irq);
|
||||
if (err)
|
||||
pci_log_error("PciCfgStore Irq Failed!",
|
||||
bus, *sub_bus, *agent, err);
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user