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

Commit 690c8fd3 authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64]: Use in-kernel PROM tree for EBUS and ISA.

parent de8d28b1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ found_sdev:

		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;
			}
		}
+75 −66
Original line number Diff line number Diff line
@@ -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,
@@ -341,18 +343,22 @@ 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));
	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) {
@@ -370,21 +376,21 @@ 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
@@ -392,8 +398,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
		 *
		 * 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 {
@@ -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;

	printk(" [%s", dp->name);

	len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
	if (len == -1) {
	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();
	}
@@ -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]);
	}
@@ -475,8 +481,8 @@ probe_interrupts:
	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]);
@@ -497,7 +503,8 @@ probe_interrupts:
		}
	}

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

@@ -505,18 +512,18 @@ probe_interrupts:
		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("]");
@@ -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);
@@ -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) {
@@ -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));
@@ -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:
@@ -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;
+57 −87
Original line number Diff line number Diff line
@@ -15,23 +15,19 @@ static void __init fatal_err(const char *reason)
static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
{
	if (child)
		printk(" (%s)", isa_dev->prom_name);
		printk(" (%s)", isa_dev->prom_node->name);
	else
		printk(" [%s", isa_dev->prom_name);
		printk(" [%s", isa_dev->prom_node->name);
}

static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
					struct linux_prom_registers *pregs,
					int pregs_size)
static struct linux_prom_registers * __init
isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
	struct linux_prom_registers *pregs;
	unsigned long base, len;
	int prop_len;

	prop_len = prom_getproperty(isa_dev->prom_node, "reg",
				    (char *) pregs, pregs_size);

	if (prop_len <= 0)
		return;
	pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);

	/* Only the first one is interesting. */
	len = pregs[0].reg_size;
@@ -42,10 +38,12 @@ static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
	isa_dev->resource.start = base;
	isa_dev->resource.end   = (base + len - 1UL);
	isa_dev->resource.flags = IORESOURCE_IO;
	isa_dev->resource.name  = isa_dev->prom_name;
	isa_dev->resource.name  = isa_dev->prom_node->name;

	request_resource(&isa_dev->bus->parent->io_space,
			 &isa_dev->resource);

	return pregs;
}

/* I can't believe they didn't put a real INO in the isa device
@@ -98,7 +96,7 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
{
	int irq_prop;

	irq_prop = prom_getintdefault(isa_dev->prom_node,
	irq_prop = of_getintprop_default(isa_dev->prom_node,
					 "interrupts", -1);
	if (irq_prop <= 0) {
		goto no_irq;
@@ -141,16 +139,15 @@ no_irq:

static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
{
	int node = prom_getchild(parent_isa_dev->prom_node);
	struct device_node *dp = parent_isa_dev->prom_node->child;

	if (node == 0)
	if (!dp)
		return;

	printk(" ->");
	while (node != 0) {
		struct linux_prom_registers regs[PROMREG_MAX];
	while (dp) {
		struct linux_prom_registers *regs;
		struct sparc_isa_device *isa_dev;
		int prop_len;

		isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
		if (!isa_dev) {
@@ -165,40 +162,24 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
		parent_isa_dev->child = isa_dev;

		isa_dev->bus = parent_isa_dev->bus;
		isa_dev->prom_node = node;
		prop_len = prom_getproperty(node, "name",
					    (char *) isa_dev->prom_name,
					    sizeof(isa_dev->prom_name));
		if (prop_len <= 0) {
			fatal_err("cannot get child isa_dev OBP node name");
			prom_halt();
		}

		prop_len = prom_getproperty(node, "compatible",
					    (char *) isa_dev->compatible,
					    sizeof(isa_dev->compatible));

		/* Not having this is OK. */
		if (prop_len <= 0)
			isa_dev->compatible[0] = '\0';
		isa_dev->prom_node = dp;

		isa_dev_get_resource(isa_dev, regs, sizeof(regs));
		regs = isa_dev_get_resource(isa_dev);
		isa_dev_get_irq(isa_dev, regs);

		report_dev(isa_dev, 1);

		node = prom_getsibling(node);
		dp = dp->sibling;
	}
}

static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
{
	int node = prom_getchild(isa_br->prom_node);
	struct device_node *dp = isa_br->prom_node->child;

	while (node != 0) {
		struct linux_prom_registers regs[PROMREG_MAX];
	while (dp) {
		struct linux_prom_registers *regs;
		struct sparc_isa_device *isa_dev;
		int prop_len;

		isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
		if (!isa_dev) {
@@ -222,24 +203,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
		}

		isa_dev->bus = isa_br;
		isa_dev->prom_node = node;
		prop_len = prom_getproperty(node, "name",
					    (char *) isa_dev->prom_name,
					    sizeof(isa_dev->prom_name));
		if (prop_len <= 0) {
			fatal_err("cannot get isa_dev OBP node name");
			prom_halt();
		}

		prop_len = prom_getproperty(node, "compatible",
					    (char *) isa_dev->compatible,
					    sizeof(isa_dev->compatible));

		/* Not having this is OK. */
		if (prop_len <= 0)
			isa_dev->compatible[0] = '\0';
		isa_dev->prom_node = dp;

		isa_dev_get_resource(isa_dev, regs, sizeof(regs));
		regs = isa_dev_get_resource(isa_dev);
		isa_dev_get_irq(isa_dev, regs);

		report_dev(isa_dev, 0);
@@ -248,10 +214,40 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)

		printk("]");

		node = prom_getsibling(node);
		dp = dp->sibling;
	}
}

static void __init get_bridge_props(struct sparc_isa_bridge *isa_br)
{
	struct device_node *dp = isa_br->prom_node;
	void *pval;
	int len;

	pval = of_get_property(dp, "ranges", &len);
	if (pval) {
		memcpy(isa_br->isa_ranges, pval, len);
		isa_br->num_isa_ranges =
			len / sizeof(struct linux_prom_isa_ranges);
	} else {
		isa_br->num_isa_ranges = 0;
	}

	pval = of_get_property(dp, "interrupt-map", &len);
	if (pval) {
		memcpy(isa_br->isa_intmap, pval, len);
		isa_br->num_isa_intmap =
			(len / sizeof(struct linux_prom_isa_intmap));
	} else {
		isa_br->num_isa_intmap = 0;
	}

	pval = of_get_property(dp, "interrupt-map-mask", &len);
	if (pval)
		memcpy(&isa_br->isa_intmask, pval,
		       sizeof(isa_br->isa_intmask));
}

void __init isa_init(void)
{
	struct pci_dev *pdev;
@@ -266,7 +262,6 @@ void __init isa_init(void)
		struct pcidev_cookie *pdev_cookie;
		struct pci_pbm_info *pbm;
		struct sparc_isa_bridge *isa_br;
		int prop_len;

		pdev_cookie = pdev->sysdata;
		if (!pdev_cookie) {
@@ -291,34 +286,9 @@ void __init isa_init(void)
		isa_br->parent = pbm;
		isa_br->self = pdev;
		isa_br->index = index++;
		isa_br->prom_node = pdev_cookie->prom_node->node;
		strncpy(isa_br->prom_name, pdev_cookie->prom_node->name,
			sizeof(isa_br->prom_name));

		prop_len = prom_getproperty(isa_br->prom_node,
					    "ranges",
					    (char *) isa_br->isa_ranges,
					    sizeof(isa_br->isa_ranges));
		if (prop_len <= 0)
			isa_br->num_isa_ranges = 0;
		else
			isa_br->num_isa_ranges =
				(prop_len / sizeof(struct linux_prom_isa_ranges));
		isa_br->prom_node = pdev_cookie->prom_node;

		prop_len = prom_getproperty(isa_br->prom_node,
					    "interrupt-map",
					    (char *) isa_br->isa_intmap,
					    sizeof(isa_br->isa_intmap));
		if (prop_len <= 0)
			isa_br->num_isa_intmap = 0;
		else
			isa_br->num_isa_intmap =
				(prop_len / sizeof(struct linux_prom_isa_intmap));

		prop_len = prom_getproperty(isa_br->prom_node,
					    "interrupt-map-mask",
					    (char *) &(isa_br->isa_intmask),
					    sizeof(isa_br->isa_intmask));
		get_bridge_props(isa_br);

		printk("isa%d:", isa_br->index);

+10 −10
Original line number Diff line number Diff line
@@ -105,24 +105,24 @@ again:
	return 0;
}

static int __init has_button_interrupt(unsigned int irq, int prom_node)
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
	if (irq == PCI_IRQ_NONE)
		return 0;
	if (!prom_node_has_property(prom_node, "button"))
	if (!of_find_property(dp, "button", NULL))
		return 0;

	return 1;
}

static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p)
{
	struct linux_ebus *ebus;
	struct linux_ebus_device *edev;

	for_each_ebus(ebus) {
		for_each_ebusdev(edev, ebus) {
			if (!strcmp(edev->prom_name, "power")) {
			if (!strcmp(edev->prom_node->name, "power")) {
				*resp = &edev->resource[0];
				*irq_p = edev->irqs[0];
				*prom_node_p = edev->prom_node;
@@ -133,14 +133,14 @@ static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p,
	return -ENODEV;
}

static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, struct device_node **prom_node_p)
{
	struct sparc_isa_bridge *isa_bus;
	struct sparc_isa_device *isa_dev;

	for_each_isa(isa_bus) {
		for_each_isadev(isa_dev, isa_bus) {
			if (!strcmp(isa_dev->prom_name, "power")) {
			if (!strcmp(isa_dev->prom_node->name, "power")) {
				*resp = &isa_dev->resource;
				*irq_p = isa_dev->irq;
				*prom_node_p = isa_dev->prom_node;
@@ -155,17 +155,17 @@ void __init power_init(void)
{
	struct resource *res = NULL;
	unsigned int irq;
	int prom_node;
	struct device_node *dp;
	static int invoked;

	if (invoked)
		return;
	invoked = 1;

	if (!power_probe_ebus(&res, &irq, &prom_node))
	if (!power_probe_ebus(&res, &irq, &dp))
		goto found;

	if (!power_probe_isa(&res, &irq, &prom_node))
	if (!power_probe_isa(&res, &irq, &dp))
		goto found;

	return;
@@ -174,7 +174,7 @@ found:
	power_reg = ioremap(res->start, 0x4);
	printk("power: Control reg at %p ... ", power_reg);
	poweroff_method = machine_halt;  /* able to use the standard halt */
	if (has_button_interrupt(irq, prom_node)) {
	if (has_button_interrupt(irq, dp)) {
		if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
			printk("Failed to start power daemon.\n");
			return;
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ struct device_node *of_find_node_by_path(const char *path)

	return np;
}
EXPORT_SYMBOL(of_find_node_by_path);

struct device_node *of_find_node_by_phandle(phandle handle)
{
Loading