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

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

[PATCH] powerpc: Update OF address parsers



This updates the OF address parsers to return the IO flags
indicating the type of address obtained. It also adds a PCI
call for converting physical addresses that hit IO space into
into IO tokens, and add routines that return the translated
addresses into struct resource

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent bb6b9b28
Loading
Loading
Loading
Loading
+3 −2
Original line number Original line Diff line number Diff line
@@ -146,6 +146,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
{
{
	phys_addr_t addr, base;
	phys_addr_t addr, base;
	u32 *addrp;
	u32 *addrp;
	unsigned int flags;
	int iotype, index = -1, lindex = 0;
	int iotype, index = -1, lindex = 0;


	/* We only support ports that have a clock frequency properly
	/* We only support ports that have a clock frequency properly
@@ -159,12 +160,12 @@ static int __init add_legacy_pci_port(struct device_node *np,
		return -1;
		return -1;


	/* Get the PCI address. Assume BAR 0 */
	/* Get the PCI address. Assume BAR 0 */
	addrp = of_get_pci_address(pci_dev, 0, NULL);
	addrp = of_get_pci_address(pci_dev, 0, NULL, &flags);
	if (addrp == NULL)
	if (addrp == NULL)
		return -1;
		return -1;


	/* We only support BAR 0 for now */
	/* We only support BAR 0 for now */
	iotype = (addrp[0] & 0x02000000) ? UPIO_MEM : UPIO_PORT;
	iotype = (flags & IORESOURCE_MEM) ? UPIO_MEM : UPIO_PORT;
	addr = of_translate_address(pci_dev, addrp);
	addr = of_translate_address(pci_dev, addrp);


	/* Set the IO base to the same as the translated address for MMIO,
	/* Set the IO base to the same as the translated address for MMIO,
+14 −0
Original line number Original line Diff line number Diff line
@@ -1181,6 +1181,20 @@ void phbs_remap_io(void)
		remap_bus_range(hose->bus);
		remap_bus_range(hose->bus);
}
}


unsigned int pci_address_to_pio(phys_addr_t address)
{
	struct pci_controller *hose, *tmp;

	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
		if (address >= hose->io_base_phys &&
		    address < (hose->io_base_phys + hose->pci_io_size))
			return (unsigned int)hose->io_base_virt +
				(address - hose->io_base_phys);
	}
	return (unsigned int)-1;
}
EXPORT_SYMBOL_GPL(pci_address_to_pio);

static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
{
{
	struct pci_controller *hose = pci_bus_to_host(dev->bus);
	struct pci_controller *hose = pci_bus_to_host(dev->bus);
+146 −19
Original line number Original line Diff line number Diff line
@@ -4,7 +4,9 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/pci_regs.h>
#include <linux/pci_regs.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <asm/prom.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>


#ifdef DEBUG
#ifdef DEBUG
#define DBG(fmt...) do { printk(fmt); } while(0)
#define DBG(fmt...) do { printk(fmt); } while(0)
@@ -54,6 +56,7 @@ struct of_bus {
				       int *addrc, int *sizec);
				       int *addrc, int *sizec);
	u64		(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
	u64		(*map)(u32 *addr, u32 *range, int na, int ns, int pna);
	int		(*translate)(u32 *addr, u64 offset, int na);
	int		(*translate)(u32 *addr, u64 offset, int na);
	unsigned int	(*get_flags)(u32 *addr);
};
};




@@ -61,7 +64,7 @@ struct of_bus {
 * Default translator (generic bus)
 * Default translator (generic bus)
 */
 */


static void of_default_count_cells(struct device_node *dev,
static void of_bus_default_count_cells(struct device_node *dev,
				       int *addrc, int *sizec)
				       int *addrc, int *sizec)
{
{
	if (addrc)
	if (addrc)
@@ -70,7 +73,7 @@ static void of_default_count_cells(struct device_node *dev,
		*sizec = prom_n_size_cells(dev);
		*sizec = prom_n_size_cells(dev);
}
}


static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
{
{
	u64 cp, s, da;
	u64 cp, s, da;


@@ -86,7 +89,7 @@ static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
	return da - cp;
	return da - cp;
}
}


static int of_default_translate(u32 *addr, u64 offset, int na)
static int of_bus_default_translate(u32 *addr, u64 offset, int na)
{
{
	u64 a = of_read_addr(addr, na);
	u64 a = of_read_addr(addr, na);
	memset(addr, 0, na * 4);
	memset(addr, 0, na * 4);
@@ -98,6 +101,11 @@ static int of_default_translate(u32 *addr, u64 offset, int na)
	return 0;
	return 0;
}
}


static unsigned int of_bus_default_get_flags(u32 *addr)
{
	return IORESOURCE_MEM;
}



/*
/*
 * PCI bus specific translator
 * PCI bus specific translator
@@ -139,7 +147,24 @@ static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)


static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
{
{
	return of_default_translate(addr + 1, offset, na - 1);
	return of_bus_default_translate(addr + 1, offset, na - 1);
}

static unsigned int of_bus_pci_get_flags(u32 *addr)
{
	unsigned int flags = 0;
	u32 w = addr[0];

	switch((w >> 24) & 0x03) {
	case 0x01:
		flags |= IORESOURCE_IO;
	case 0x02: /* 32 bits */
	case 0x03: /* 64 bits */
		flags |= IORESOURCE_MEM;
	}
	if (w & 0x40000000)
		flags |= IORESOURCE_PREFETCH;
	return flags;
}
}


/*
/*
@@ -182,9 +207,22 @@ static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)


static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
{
{
	return of_default_translate(addr + 1, offset, na - 1);
	return of_bus_default_translate(addr + 1, offset, na - 1);
}
}


static unsigned int of_bus_isa_get_flags(u32 *addr)
{
	unsigned int flags = 0;
	u32 w = addr[0];

	if (w & 1)
		flags |= IORESOURCE_IO;
	else
		flags |= IORESOURCE_MEM;
	return flags;
}


/*
/*
 * Array of bus specific translators
 * Array of bus specific translators
 */
 */
@@ -198,6 +236,7 @@ static struct of_bus of_busses[] = {
		.count_cells = of_bus_pci_count_cells,
		.count_cells = of_bus_pci_count_cells,
		.map = of_bus_pci_map,
		.map = of_bus_pci_map,
		.translate = of_bus_pci_translate,
		.translate = of_bus_pci_translate,
		.get_flags = of_bus_pci_get_flags,
	},
	},
	/* ISA */
	/* ISA */
	{
	{
@@ -207,15 +246,17 @@ static struct of_bus of_busses[] = {
		.count_cells = of_bus_isa_count_cells,
		.count_cells = of_bus_isa_count_cells,
		.map = of_bus_isa_map,
		.map = of_bus_isa_map,
		.translate = of_bus_isa_translate,
		.translate = of_bus_isa_translate,
		.get_flags = of_bus_isa_get_flags,
	},
	},
	/* Default */
	/* Default */
	{
	{
		.name = "default",
		.name = "default",
		.addresses = "reg",
		.addresses = "reg",
		.match = NULL,
		.match = NULL,
		.count_cells = of_default_count_cells,
		.count_cells = of_bus_default_count_cells,
		.map = of_default_map,
		.map = of_bus_default_map,
		.translate = of_default_translate,
		.translate = of_bus_default_translate,
		.get_flags = of_bus_default_get_flags,
	},
	},
};
};


@@ -254,7 +295,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
	ranges = (u32 *)get_property(parent, "ranges", &rlen);
	ranges = (u32 *)get_property(parent, "ranges", &rlen);
	if (ranges == NULL || rlen == 0) {
	if (ranges == NULL || rlen == 0) {
		offset = of_read_addr(addr, na);
		offset = of_read_addr(addr, na);
		memset(addr, 0, pna);
		memset(addr, 0, pna * 4);
		DBG("OF: no ranges, 1:1 translation\n");
		goto finish;
		goto finish;
	}
	}


@@ -370,7 +412,8 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr)
}
}
EXPORT_SYMBOL(of_translate_address);
EXPORT_SYMBOL(of_translate_address);


u32 *of_get_address(struct device_node *dev, int index, u64 *size)
u32 *of_get_address(struct device_node *dev, int index, u64 *size,
		    unsigned int *flags)
{
{
	u32 *prop;
	u32 *prop;
	unsigned int psize;
	unsigned int psize;
@@ -399,22 +442,106 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size)
		if (i == index) {
		if (i == index) {
			if (size)
			if (size)
				*size = of_read_addr(prop + na, ns);
				*size = of_read_addr(prop + na, ns);
			if (flags)
				*flags = bus->get_flags(prop);
			return prop;
			return prop;
		}
		}
	return NULL;
	return NULL;
}
}
EXPORT_SYMBOL(of_get_address);
EXPORT_SYMBOL(of_get_address);


u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size)
u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
			unsigned int *flags)
{
{
	u32 *addr;
	u32 *prop;
	int index;
	unsigned int psize;
	struct device_node *parent;
	struct of_bus *bus;
	int onesize, i, na, ns;


	for (index = 0; (addr = of_get_address(dev, index, size)) != NULL;
	/* Get parent & match bus type */
	     index++) {
	parent = of_get_parent(dev);
		if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))
	if (parent == NULL)
			return addr;
		return NULL;
	bus = of_match_bus(parent);
	if (strcmp(bus->name, "pci"))
		return NULL;
	bus->count_cells(dev, &na, &ns);
	of_node_put(parent);
	if (!OF_CHECK_COUNTS(na, ns))
		return NULL;

	/* Get "reg" or "assigned-addresses" property */
	prop = (u32 *)get_property(dev, bus->addresses, &psize);
	if (prop == NULL)
		return NULL;
	psize /= 4;

	onesize = na + ns;
	for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
		if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
			if (size)
				*size = of_read_addr(prop + na, ns);
			if (flags)
				*flags = bus->get_flags(prop);
			return prop;
		}
		}
	return NULL;
	return NULL;
}
}
EXPORT_SYMBOL(of_get_pci_address);
EXPORT_SYMBOL(of_get_pci_address);

static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
				    u64 size, unsigned int flags,
				    struct resource *r)
{
	u64 taddr;

	if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
		return -EINVAL;
	taddr = of_translate_address(dev, addrp);
	if (taddr == OF_BAD_ADDR)
		return -EINVAL;
	memset(r, 0, sizeof(struct resource));
	if (flags & IORESOURCE_IO) {
		unsigned int port;
		port = pci_address_to_pio(taddr);
		if (port == (unsigned int)-1)
			return -EINVAL;
		r->start = port;
		r->end = port + size - 1;
	} else {
		r->start = taddr;
		r->end = taddr + size - 1;
	}
	r->flags = flags;
	r->name = dev->name;
	return 0;
}

int of_address_to_resource(struct device_node *dev, int index,
			   struct resource *r)
{
	u32		*addrp;
	u64		size;
	unsigned int	flags;

	addrp = of_get_address(dev, index, &size, &flags);
	if (addrp == NULL)
		return -EINVAL;
	return __of_address_to_resource(dev, addrp, size, flags, r);
}
EXPORT_SYMBOL_GPL(of_address_to_resource);

int of_pci_address_to_resource(struct device_node *dev, int bar,
			       struct resource *r)
{
	u32		*addrp;
	u64		size;
	unsigned int	flags;

	addrp = of_get_pci_address(dev, bar, &size, &flags);
	if (addrp == NULL)
		return -EINVAL;
	return __of_address_to_resource(dev, addrp, size, flags, r);
}
EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
+1 −1
Original line number Original line Diff line number Diff line
@@ -2683,7 +2683,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
		return;
		return;
	}
	}
	addrp = of_get_pci_address(node, 0, &size);
	addrp = of_get_pci_address(node, 0, &size, NULL);
	if (addrp == NULL) {
	if (addrp == NULL) {
		printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
		printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
		       node->full_name);
		       node->full_name);
+15 −0
Original line number Original line Diff line number Diff line
@@ -1805,6 +1805,21 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);
EXPORT_SYMBOL(pci_iounmap);


unsigned int pci_address_to_pio(phys_addr_t address)
{
	struct pci_controller* hose = hose_head;

	for (; hose; hose = hose->next) {
		unsigned int size = hose->io_resource.end -
			hose->io_resource.start + 1;
		if (address >= hose->io_base_phys &&
		    address < (hose->io_base_phys + size))
			return (unsigned int)hose->io_base_virt +
				(address - hose->io_base_phys);
	}
	return (unsigned int)-1;
}
EXPORT_SYMBOL(pci_address_to_pio);


/*
/*
 * Null PCI config access functions, for the case when we can't
 * Null PCI config access functions, for the case when we can't
Loading