Skip to content

Commit

Permalink
[SPARC64]: Use in-kernel PROM tree for EBUS and ISA.
Browse files Browse the repository at this point in the history
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 24, 2006
1 parent de8d28b commit 690c8fd
Show file tree
Hide file tree
Showing 21 changed files with 440 additions and 450 deletions.
2 changes: 1 addition & 1 deletion arch/sparc64/kernel/auxio.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void __init auxio_probe(void)

for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "auxio"))
if (!strcmp(edev->prom_node->name, "auxio"))
goto ebus_done;
}
}
Expand Down
141 changes: 75 additions & 66 deletions arch/sparc64/kernel/ebus.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,36 +285,38 @@ static inline void *ebus_alloc(size_t size)

static void __init ebus_ranges_init(struct linux_ebus *ebus)
{
int success;
struct linux_prom_ebus_ranges *rngs;
int len;

ebus->num_ebus_ranges = 0;
success = prom_getproperty(ebus->prom_node, "ranges",
(char *)ebus->ebus_ranges,
sizeof(ebus->ebus_ranges));
if (success != -1)
ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
rngs = of_get_property(ebus->prom_node, "ranges", &len);
if (rngs) {
memcpy(ebus->ebus_ranges, rngs, len);
ebus->num_ebus_ranges =
(len / sizeof(struct linux_prom_ebus_ranges));
}
}

static void __init ebus_intmap_init(struct linux_ebus *ebus)
{
int success;
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmask *imask;
int len;

ebus->num_ebus_intmap = 0;
success = prom_getproperty(ebus->prom_node, "interrupt-map",
(char *)ebus->ebus_intmap,
sizeof(ebus->ebus_intmap));
if (success == -1)
imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
if (!imap)
return;

ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
memcpy(ebus->ebus_intmap, imap, len);
ebus->num_ebus_intmap = (len / sizeof(struct linux_prom_ebus_intmap));

success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
(char *)&ebus->ebus_intmask,
sizeof(ebus->ebus_intmask));
if (success == -1) {
prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
imask = of_get_property(ebus->prom_node, "interrupt-map-mask", &len);
if (!imask) {
prom_printf("EBUS: can't get interrupt-map-mask\n");
prom_halt();
}
memcpy(&ebus->ebus_intmask, imask, sizeof(ebus->ebus_intmask));
}

int __init ebus_intmap_match(struct linux_ebus *ebus,
Expand All @@ -341,19 +343,23 @@ int __init ebus_intmap_match(struct linux_ebus *ebus,
return -1;
}

void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct linux_ebus_child *dev, int non_standard_regs)
void __init fill_ebus_child(struct device_node *dp,
struct linux_prom_registers *preg,
struct linux_ebus_child *dev,
int non_standard_regs)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
int *regs;
int *irqs;
int i, len;

dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" (%s)", dev->prom_name);
dev->prom_node = dp;
printk(" (%s)", dp->name);

len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
dev->num_addrs = len / sizeof(regs[0]);
regs = of_get_property(dp, "reg", &len);
if (!regs)
dev->num_addrs = 0;
else
dev->num_addrs = len / sizeof(regs[0]);

if (non_standard_regs) {
/* This is to handle reg properties which are not
Expand All @@ -370,30 +376,30 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
int rnum = regs[i];
if (rnum >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
dev->prom_name, len, dev->parent->num_addrs);
panic(__FUNCTION__);
dp->name, len, dev->parent->num_addrs);
prom_halt();
}
dev->resource[i].start = dev->parent->resource[i].start;
dev->resource[i].end = dev->parent->resource[i].end;
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dp->name;
}
}

for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;

len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
/*
* Oh, well, some PROMs don't export interrupts
* property to children of EBus devices...
*
* Be smart about PS/2 keyboard and mouse.
*/
if (!strcmp(dev->parent->prom_name, "8042")) {
if (!strcmp(dev->prom_name, "kb_ps2")) {
if (!strcmp(dev->parent->prom_node->name, "8042")) {
if (!strcmp(dev->prom_node->name, "kb_ps2")) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
} else {
Expand Down Expand Up @@ -423,32 +429,32 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,

static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
{
if (!strcmp(dev->prom_name, "i2c") ||
!strcmp(dev->prom_name, "SUNW,lombus"))
if (!strcmp(dev->prom_node->name, "i2c") ||
!strcmp(dev->prom_node->name, "SUNW,lombus"))
return 1;
return 0;
}

void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_prom_registers *regs;
struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
int *irqs;
int i, n, len;

dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" [%s", dev->prom_name);
dev->prom_node = dp;

len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len == -1) {
printk(" [%s", dp->name);

regs = of_get_property(dp, "reg", &len);
if (!regs) {
dev->num_addrs = 0;
goto probe_interrupts;
}

if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
prom_halt();
}
Expand All @@ -466,7 +472,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->resource[i].end =
(dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dev->prom_node->name;
request_resource(&dev->bus->self->resource[n],
&dev->resource[i]);
}
Expand All @@ -475,8 +481,8 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;

len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
Expand All @@ -497,26 +503,27 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
}
}

if ((node = prom_getchild(node))) {
dp = dp->child;
if (dp) {
printk(" ->");
dev->children = ebus_alloc(sizeof(struct linux_ebus_child));

child = dev->children;
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0],
child, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));

while ((node = prom_getsibling(node)) != 0) {
while ((dp = dp->sibling) != NULL) {
child->next = ebus_alloc(sizeof(struct linux_ebus_child));

child = child->next;
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0],
child, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));
}
}
printk("]");
Expand All @@ -543,7 +550,8 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
int nd, ebusnd, is_rio;
struct device_node *dp;
int is_rio;
int num_ebus = 0;

pdev = find_next_ebus(NULL, &is_rio);
Expand All @@ -553,20 +561,22 @@ void __init ebus_init(void)
}

cookie = pdev->sysdata;
ebusnd = cookie->prom_node->node;
dp = cookie->prom_node;

ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
ebus->is_rio = is_rio;

while (ebusnd) {
while (dp) {
struct device_node *child;

/* SUNW,pci-qfe uses four empty ebuses on it.
I think we should not consider them here,
as they have half of the properties this
code expects and once we do PCI hot-plug,
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
if (!prom_getchild (ebusnd)) {
if (!dp->child) {
pdev = find_next_ebus(pdev, &is_rio);
if (!pdev) {
if (ebus == ebus_chain) {
Expand All @@ -578,22 +588,21 @@ void __init ebus_init(void)
}
ebus->is_rio = is_rio;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node->node;
dp = cookie->prom_node;
continue;
}
printk("ebus%d:", num_ebus);

prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
ebus->index = num_ebus;
ebus->prom_node = ebusnd;
ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;

ebus_ranges_init(ebus);
ebus_intmap_init(ebus);

nd = prom_getchild(ebusnd);
if (!nd)
child = dp->child;
if (!child)
goto next_ebus;

ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
Expand All @@ -602,16 +611,16 @@ void __init ebus_init(void)
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);

while ((nd = prom_getsibling(nd)) != 0) {
while ((child = child->sibling) != NULL) {
dev->next = ebus_alloc(sizeof(struct linux_ebus_device));

dev = dev->next;
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);
}

next_ebus:
Expand All @@ -622,7 +631,7 @@ void __init ebus_init(void)
break;

cookie = pdev->sysdata;
ebusnd = cookie->prom_node->node;
dp = cookie->prom_node;

ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
Expand Down
Loading

0 comments on commit 690c8fd

Please sign in to comment.