Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -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
+16 −3
Original line number Diff line number Diff line
@@ -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 */
	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)
	}
	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;
+68 −57
Original line number Diff line number Diff line
@@ -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,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
 * 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)
{
	u8 frame = 0;
@@ -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,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 *sub_bus;
	unsigned char bus = pdev->bus->number;
	struct device_node *node;
	int i;

	node = find_device_node(bus, pdev->devfn);
		printk("pci dev %p (%x.%x), node %p\n", pdev, bus,
			pdev->devfn, node);
	pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
		 pci_name(pdev), pdev, node);
	if (!node) {
			printk("PCI: Device Tree not found for 0x%016lX\n",
					(unsigned long)pdev);
			continue;
		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;
	}

		agent = of_get_property(node, "linux,agent-id", NULL);
	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);
		err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
		if (err)
			pci_log_error("Connect Bus Unit",
				      bus, *sub_bus, *agent, err);
@@ -441,13 +437,20 @@ void __init iSeries_pci_final_fixup(void)
		}
	}

		num_dev++;
	pdev->sysdata = node;
	PCI_DN(node)->pcidev = 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);
}

/*
 * 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);
+4 −0
Original line number Diff line number Diff line
@@ -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 */
+19 −18
Original line number Diff line number Diff line
@@ -646,6 +646,7 @@ define_machine(iseries) {
	.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,