Commit cc5d0189 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[PATCH] powerpc: Remove device_node addrs/n_addr

The pre-parsed addrs/n_addrs fields in struct device_node are finally
gone. Remove the dodgy heuristics that did that parsing at boot and
remove the fields themselves since we now have a good replacement with
the new OF parsing code. This patch also fixes a bunch of drivers to use
the new code instead, so that at least pmac32, pseries, iseries and g5
defconfigs build.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 9cf84d7c
......@@ -211,8 +211,6 @@ int __init btext_find_display(int allow_nonstdout)
struct device_node *np = NULL;
int rc = -ENODEV;
printk("trying to initialize btext ...\n");
name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
if (name != NULL) {
np = of_find_node_by_path(name);
......
......@@ -896,6 +896,25 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned long phb_io_base_phys,
void __iomem * phb_io_base_virt)
{
/* Remove these asap */
struct pci_address {
u32 a_hi;
u32 a_mid;
u32 a_lo;
};
struct isa_address {
u32 a_hi;
u32 a_lo;
};
struct isa_range {
struct isa_address isa_addr;
struct pci_address pci_addr;
unsigned int size;
};
struct isa_range *range;
unsigned long pci_addr;
unsigned int isa_addr;
......@@ -1330,8 +1349,9 @@ unsigned int pci_address_to_pio(phys_addr_t address)
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)
((unsigned long)hose->io_base_virt +
(address - hose->io_base_phys));
}
return (unsigned int)-1;
}
......
......@@ -57,21 +57,6 @@
#define DBG(fmt...)
#endif
struct pci_reg_property {
struct pci_address addr;
u32 size_hi;
u32 size_lo;
};
struct isa_reg_property {
u32 space;
u32 address;
u32 size;
};
typedef int interpret_func(struct device_node *, unsigned long *,
int, int, int);
static int __initdata dt_root_addr_cells;
static int __initdata dt_root_size_cells;
......@@ -410,237 +395,19 @@ static int __devinit finish_node_interrupts(struct device_node *np,
return 0;
}
static int __devinit interpret_pci_props(struct device_node *np,
unsigned long *mem_start,
int naddrc, int nsizec,
int measure_only)
{
struct address_range *adr;
struct pci_reg_property *pci_addrs;
int i, l, n_addrs;
pci_addrs = (struct pci_reg_property *)
get_property(np, "assigned-addresses", &l);
if (!pci_addrs)
return 0;
n_addrs = l / sizeof(*pci_addrs);
adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
if (!adr)
return -ENOMEM;
if (measure_only)
return 0;
np->addrs = adr;
np->n_addrs = n_addrs;
for (i = 0; i < n_addrs; i++) {
adr[i].space = pci_addrs[i].addr.a_hi;
adr[i].address = pci_addrs[i].addr.a_lo |
((u64)pci_addrs[i].addr.a_mid << 32);
adr[i].size = pci_addrs[i].size_lo;
}
return 0;
}
static int __init interpret_dbdma_props(struct device_node *np,
unsigned long *mem_start,
int naddrc, int nsizec,
int measure_only)
{
struct reg_property32 *rp;
struct address_range *adr;
unsigned long base_address;
int i, l;
struct device_node *db;
base_address = 0;
if (!measure_only) {
for (db = np->parent; db != NULL; db = db->parent) {
if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
base_address = db->addrs[0].address;
break;
}
}
}
rp = (struct reg_property32 *) get_property(np, "reg", &l);
if (rp != 0 && l >= sizeof(struct reg_property32)) {
i = 0;
adr = (struct address_range *) (*mem_start);
while ((l -= sizeof(struct reg_property32)) >= 0) {
if (!measure_only) {
adr[i].space = 2;
adr[i].address = rp[i].address + base_address;
adr[i].size = rp[i].size;
}
++i;
}
np->addrs = adr;
np->n_addrs = i;
(*mem_start) += i * sizeof(struct address_range);
}
return 0;
}
static int __init interpret_macio_props(struct device_node *np,
unsigned long *mem_start,
int naddrc, int nsizec,
int measure_only)
{
struct reg_property32 *rp;
struct address_range *adr;
unsigned long base_address;
int i, l;
struct device_node *db;
base_address = 0;
if (!measure_only) {
for (db = np->parent; db != NULL; db = db->parent) {
if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
base_address = db->addrs[0].address;
break;
}
}
}
rp = (struct reg_property32 *) get_property(np, "reg", &l);
if (rp != 0 && l >= sizeof(struct reg_property32)) {
i = 0;
adr = (struct address_range *) (*mem_start);
while ((l -= sizeof(struct reg_property32)) >= 0) {
if (!measure_only) {
adr[i].space = 2;
adr[i].address = rp[i].address + base_address;
adr[i].size = rp[i].size;
}
++i;
}
np->addrs = adr;
np->n_addrs = i;
(*mem_start) += i * sizeof(struct address_range);
}
return 0;
}
static int __init interpret_isa_props(struct device_node *np,
unsigned long *mem_start,
int naddrc, int nsizec,
int measure_only)
{
struct isa_reg_property *rp;
struct address_range *adr;
int i, l;
rp = (struct isa_reg_property *) get_property(np, "reg", &l);
if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
i = 0;
adr = (struct address_range *) (*mem_start);
while ((l -= sizeof(struct isa_reg_property)) >= 0) {
if (!measure_only) {
adr[i].space = rp[i].space;
adr[i].address = rp[i].address;
adr[i].size = rp[i].size;
}
++i;
}
np->addrs = adr;
np->n_addrs = i;
(*mem_start) += i * sizeof(struct address_range);
}
return 0;
}
static int __init interpret_root_props(struct device_node *np,
unsigned long *mem_start,
int naddrc, int nsizec,
int measure_only)
{
struct address_range *adr;
int i, l;
unsigned int *rp;
int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
rp = (unsigned int *) get_property(np, "linux,usable-memory", &l);
if (rp == NULL)
rp = (unsigned int *) get_property(np, "reg", &l);
if (rp != 0 && l >= rpsize) {
i = 0;
adr = (struct address_range *) (*mem_start);
while ((l -= rpsize) >= 0) {
if (!measure_only) {
adr[i].space = 0;
adr[i].address = rp[naddrc - 1];
adr[i].size = rp[naddrc + nsizec - 1];
}
++i;
rp += naddrc + nsizec;
}
np->addrs = adr;
np->n_addrs = i;
(*mem_start) += i * sizeof(struct address_range);
}
return 0;
}
static int __devinit finish_node(struct device_node *np,
unsigned long *mem_start,
interpret_func *ifunc,
int naddrc, int nsizec,
int measure_only)
{
struct device_node *child;
int *ip, rc = 0;
/* get the device addresses and interrupts */
if (ifunc != NULL)
rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
if (rc)
goto out;
int rc = 0;
rc = finish_node_interrupts(np, mem_start, measure_only);
if (rc)
goto out;
/* Look for #address-cells and #size-cells properties. */
ip = (int *) get_property(np, "#address-cells", NULL);
if (ip != NULL)
naddrc = *ip;
ip = (int *) get_property(np, "#size-cells", NULL);
if (ip != NULL)
nsizec = *ip;
if (!strcmp(np->name, "device-tree") || np->parent == NULL)
ifunc = interpret_root_props;
else if (np->type == 0)
ifunc = NULL;
else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
ifunc = interpret_pci_props;
else if (!strcmp(np->type, "dbdma"))
ifunc = interpret_dbdma_props;
else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
ifunc = interpret_macio_props;
else if (!strcmp(np->type, "isa"))
ifunc = interpret_isa_props;
else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
ifunc = interpret_root_props;
else if (!((ifunc == interpret_dbdma_props
|| ifunc == interpret_macio_props)
&& (!strcmp(np->type, "escc")
|| !strcmp(np->type, "media-bay"))))
ifunc = NULL;
for (child = np->child; child != NULL; child = child->sibling) {
rc = finish_node(child, mem_start, ifunc,
naddrc, nsizec, measure_only);
rc = finish_node(child, mem_start, measure_only);
if (rc)
goto out;
}
......@@ -702,10 +469,10 @@ void __init finish_device_tree(void)
* reason and then remove those additional 16 bytes
*/
size = 16;
finish_node(allnodes, &size, NULL, 0, 0, 1);
finish_node(allnodes, &size, 1);
size -= 16;
end = start = (unsigned long) __va(lmb_alloc(size, 128));
finish_node(allnodes, &end, NULL, 0, 0, 0);
finish_node(allnodes, &end, 0);
BUG_ON(end != start + size);
DBG(" <- finish_device_tree\n");
......@@ -1822,7 +1589,6 @@ static void of_node_release(struct kref *kref)
prop = next;
}
kfree(node->intrs);
kfree(node->addrs);
kfree(node->full_name);
kfree(node->data);
kfree(node);
......@@ -1904,9 +1670,7 @@ void of_detach_node(const struct device_node *np)
* This should probably be split up into smaller chunks.
*/
static int of_finish_dynamic_node(struct device_node *node,
unsigned long *unused1, int unused2,
int unused3, int unused4)
static int of_finish_dynamic_node(struct device_node *node)
{
struct device_node *parent = of_get_parent(node);
int err = 0;
......@@ -1927,7 +1691,8 @@ static int of_finish_dynamic_node(struct device_node *node,
return -ENODEV;
/* fix up new node's linux_phandle field */
if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
if ((ibm_phandle = (unsigned int *)get_property(node,
"ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
out:
......@@ -1942,7 +1707,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
switch (action) {
case PSERIES_RECONFIG_ADD:
err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
err = of_finish_dynamic_node(node);
if (!err)
finish_node(node, NULL, 0);
if (err < 0) {
printk(KERN_ERR "finish_node returned %d\n", err);
err = NOTIFY_BAD;
......@@ -2016,175 +1783,4 @@ int prom_add_property(struct device_node* np, struct property* prop)
return 0;
}
/* I quickly hacked that one, check against spec ! */
static inline unsigned long
bus_space_to_resource_flags(unsigned int bus_space)
{
u8 space = (bus_space >> 24) & 0xf;
if (space == 0)
space = 0x02;
if (space == 0x02)
return IORESOURCE_MEM;
else if (space == 0x01)
return IORESOURCE_IO;
else {
printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
bus_space);
return 0;
}
}
#ifdef CONFIG_PCI
static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
struct address_range *range)
{
unsigned long mask;
int i;
/* Check this one */
mask = bus_space_to_resource_flags(range->space);
for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
if ((pdev->resource[i].flags & mask) == mask &&
pdev->resource[i].start <= range->address &&
pdev->resource[i].end > range->address) {
if ((range->address + range->size - 1) > pdev->resource[i].end) {
/* Add better message */
printk(KERN_WARNING "PCI/OF resource overlap !\n");
return NULL;
}
break;
}
}
if (i == DEVICE_COUNT_RESOURCE)
return NULL;
return &pdev->resource[i];
}
/*
* Request an OF device resource. Currently handles child of PCI devices,
* or other nodes attached to the root node. Ultimately, put some
* link to resources in the OF node.
*/
struct resource *request_OF_resource(struct device_node* node, int index,
const char* name_postfix)
{
struct pci_dev* pcidev;
u8 pci_bus, pci_devfn;
unsigned long iomask;
struct device_node* nd;
struct resource* parent;
struct resource *res = NULL;
int nlen, plen;
if (index >= node->n_addrs)
goto fail;
/* Sanity check on bus space */
iomask = bus_space_to_resource_flags(node->addrs[index].space);
if (iomask & IORESOURCE_MEM)
parent = &iomem_resource;
else if (iomask & IORESOURCE_IO)
parent = &ioport_resource;
else
goto fail;
/* Find a PCI parent if any */
nd = node;
pcidev = NULL;
while (nd) {
if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
pcidev = pci_find_slot(pci_bus, pci_devfn);
if (pcidev) break;
nd = nd->parent;
}
if (pcidev)
parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
if (!parent) {
printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
node->name);
goto fail;
}
res = __request_region(parent, node->addrs[index].address,
node->addrs[index].size, NULL);
if (!res)
goto fail;
nlen = strlen(node->name);
plen = name_postfix ? strlen(name_postfix) : 0;
res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
if (res->name) {
strcpy((char *)res->name, node->name);
if (plen)
strcpy((char *)res->name+nlen, name_postfix);
}
return res;
fail:
return NULL;
}
EXPORT_SYMBOL(request_OF_resource);
int release_OF_resource(struct device_node *node, int index)
{
struct pci_dev* pcidev;
u8 pci_bus, pci_devfn;
unsigned long iomask, start, end;
struct device_node* nd;
struct resource* parent;
struct resource *res = NULL;
if (index >= node->n_addrs)
return -EINVAL;
/* Sanity check on bus space */
iomask = bus_space_to_resource_flags(node->addrs[index].space);
if (iomask & IORESOURCE_MEM)
parent = &iomem_resource;
else if (iomask & IORESOURCE_IO)
parent = &ioport_resource;
else
return -EINVAL;
/* Find a PCI parent if any */
nd = node;
pcidev = NULL;
while(nd) {
if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
pcidev = pci_find_slot(pci_bus, pci_devfn);
if (pcidev) break;
nd = nd->parent;
}
if (pcidev)
parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
if (!parent) {
printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
node->name);
return -ENODEV;
}
/* Find us in the parent and its childs */
res = parent->child;
start = node->addrs[index].address;
end = start + node->addrs[index].size - 1;
while (res) {
if (res->start == start && res->end == end &&
(res->flags & IORESOURCE_BUSY))
break;
if (res->start <= start && res->end >= end)
res = res->child;
else
res = res->sibling;
}
if (!res)
return -ENODEV;
if (res->name) {
kfree(res->name);
res->name = NULL;
}
release_resource(res);
kfree(res);
return 0;
}
EXPORT_SYMBOL(release_OF_resource);
#endif /* CONFIG_PCI */
......@@ -558,7 +558,8 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
static void __init early_cmdline_parse(void)
{
struct prom_t *_prom = &RELOC(prom);
char *opt, *p;
const char *opt;
char *p;
int l = 0;
RELOC(prom_cmd_line[0]) = 0;
......
......@@ -188,39 +188,19 @@ int is_python(struct device_node *dev)
return 0;
}
static int get_phb_reg_prop(struct device_node *dev,
unsigned int addr_size_words,
struct reg_property64 *reg)
static void python_countermeasures(struct device_node *dev)
{
unsigned int *ui_ptr = NULL, len;
/* Found a PHB, now figure out where his registers are mapped. */
ui_ptr = (unsigned int *)get_property(dev, "reg", &len);
if (ui_ptr == NULL)
return 1;
if (addr_size_words == 1) {
reg->address = ((struct reg_property32 *)ui_ptr)->address;
reg->size = ((struct reg_property32 *)ui_ptr)->size;
} else {
*reg = *((struct reg_property64 *)ui_ptr);
}
return 0;
}
static void python_countermeasures(struct device_node *dev,
unsigned int addr_size_words)
{
struct reg_property64 reg_struct;
struct resource registers;
void __iomem *chip_regs;
volatile u32 val;
if (get_phb_reg_prop(dev, addr_size_words, &reg_struct))
if (of_address_to_resource(dev, 0, &registers)) {
printk(KERN_ERR "Can't get address for Python workarounds !\n");
return;
}
/* Python's register file is 1 MB in size. */
chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000);
chip_regs = ioremap(registers.start & ~(0xfffffUL), 0x100000);
/*
* Firmware doesn't always clear this bit which is critical
......@@ -301,11 +281,10 @@ static int phb_set_bus_ranges(struct device_node *dev,
}
static int __devinit setup_phb(struct device_node *dev,
struct pci_controller *phb,
unsigned int addr_size_words)