Skip to content

Commit

Permalink
[PATCH] powerpc: Update OF address parsers
Browse files Browse the repository at this point in the history
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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Benjamin Herrenschmidt authored and Paul Mackerras committed Jan 9, 2006
1 parent bb6b9b2 commit d2dd482
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 36 deletions.
5 changes: 3 additions & 2 deletions arch/powerpc/kernel/legacy_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
{
phys_addr_t addr, base;
u32 *addrp;
unsigned int flags;
int iotype, index = -1, lindex = 0;

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

/* 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)
return -1;

/* 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);

/* Set the IO base to the same as the translated address for MMIO,
Expand Down
14 changes: 14 additions & 0 deletions arch/powerpc/kernel/pci_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,20 @@ void phbs_remap_io(void)
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)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
Expand Down
165 changes: 146 additions & 19 deletions arch/powerpc/kernel/prom_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include <linux/string.h>
#include <linux/pci_regs.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>

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


/*
* Default translator (generic bus)
*/

static void of_default_count_cells(struct device_node *dev,
int *addrc, int *sizec)
static void of_bus_default_count_cells(struct device_node *dev,
int *addrc, int *sizec)
{
if (addrc)
*addrc = prom_n_addr_cells(dev);
if (sizec)
*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;

Expand All @@ -86,7 +89,7 @@ static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
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);
memset(addr, 0, na * 4);
Expand All @@ -98,6 +101,11 @@ static int of_default_translate(u32 *addr, u64 offset, int na)
return 0;
}

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


/*
* PCI bus specific translator
Expand Down Expand Up @@ -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)
{
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;
}

/*
Expand Down Expand Up @@ -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)
{
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
*/
Expand All @@ -198,6 +236,7 @@ static struct of_bus of_busses[] = {
.count_cells = of_bus_pci_count_cells,
.map = of_bus_pci_map,
.translate = of_bus_pci_translate,
.get_flags = of_bus_pci_get_flags,
},
/* ISA */
{
Expand All @@ -207,15 +246,17 @@ static struct of_bus of_busses[] = {
.count_cells = of_bus_isa_count_cells,
.map = of_bus_isa_map,
.translate = of_bus_isa_translate,
.get_flags = of_bus_isa_get_flags,
},
/* Default */
{
.name = "default",
.addresses = "reg",
.match = NULL,
.count_cells = of_default_count_cells,
.map = of_default_map,
.translate = of_default_translate,
.count_cells = of_bus_default_count_cells,
.map = of_bus_default_map,
.translate = of_bus_default_translate,
.get_flags = of_bus_default_get_flags,
},
};

Expand Down Expand Up @@ -254,7 +295,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
ranges = (u32 *)get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
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;
}

Expand Down Expand Up @@ -370,7 +412,8 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr)
}
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;
unsigned int psize;
Expand Down Expand Up @@ -399,22 +442,106 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size)
if (i == index) {
if (size)
*size = of_read_addr(prop + na, ns);
if (flags)
*flags = bus->get_flags(prop);
return prop;
}
return NULL;
}
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;
int index;
u32 *prop;
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;
index++) {
if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))
return addr;
}
/* Get parent & match bus type */
parent = of_get_parent(dev);
if (parent == NULL)
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;
}
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);
2 changes: 1 addition & 1 deletion arch/powerpc/platforms/powermac/feature.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
return;
}
addrp = of_get_pci_address(node, 0, &size);
addrp = of_get_pci_address(node, 0, &size, NULL);
if (addrp == NULL) {
printk(KERN_ERR "pmac_feature: %s: can't find base !\n",
node->full_name);
Expand Down
15 changes: 15 additions & 0 deletions arch/ppc/kernel/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,21 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
EXPORT_SYMBOL(pci_iomap);
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
Expand Down
12 changes: 4 additions & 8 deletions drivers/macintosh/macio_asic.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,18 +332,14 @@ static void macio_setup_resources(struct macio_dev *dev,
struct resource *parent_res)
{
struct device_node *np = dev->ofdev.node;
u32 *addr;
u64 size;
struct resource r;
int index;

for (index = 0; (addr = of_get_address(np, index, &size)) != NULL;
index++) {
for (index = 0; of_address_to_resource(np, index, &r) == 0; index++) {
struct resource *res = &dev->resource[index];
if (index >= MACIO_DEV_COUNT_RESOURCES)
break;
res->start = of_translate_address(np, addr);
res->end = res->start + (unsigned long)size - 1;
res->flags = IORESOURCE_MEM;
*res = r;
res->name = dev->ofdev.dev.bus_id;

if (macio_resource_quirks(np, res, index)) {
Expand All @@ -353,7 +349,7 @@ static void macio_setup_resources(struct macio_dev *dev,
/* Currently, we consider failure as harmless, this may
* change in the future, once I've found all the device
* tree bugs in older machines & worked around them
*/
l */
if (insert_resource(parent_res, res)) {
printk(KERN_WARNING "Can't request resource "
"%d for MacIO device %s\n",
Expand Down
9 changes: 9 additions & 0 deletions include/asm-powerpc/pci-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,15 @@ extern struct pci_controller *
pcibios_alloc_controller(struct device_node *dev);
extern void pcibios_free_controller(struct pci_controller *phb);

#ifdef CONFIG_PCI
extern unsigned int pci_address_to_pio(phys_addr_t address);
#else
static inline unsigned int pci_address_to_pio(phys_addr_t address)
{
return (unsigned int)-1;
}
#endif

/* Return values for ppc_md.pci_probe_mode function */
#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
Expand Down
Loading

0 comments on commit d2dd482

Please sign in to comment.