* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
*/
static DEFINE_RWLOCK(devtree_lock);
-int of_device_is_compatible(struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = (char *) of_get_property(device, "compatible", &cplen);
+ cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
}
EXPORT_SYMBOL(of_find_compatible_node);
-struct property *of_find_property(struct device_node *np, const char *name,
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcmp(pp->name, name) == 0) {
+ if (strcasecmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
* Find a property with a given name for a given node
* and return the value.
*/
-void *of_get_property(struct device_node *np, const char *name, int *lenp)
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
int of_n_addr_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
int of_n_size_cells(struct device_node *np)
{
- int* ip;
+ const int* ip;
do {
if (np->parent)
np = np->parent;
while (*prevp) {
struct property *prop = *prevp;
- if (!strcmp(prop->name, name)) {
+ if (!strcasecmp(prop->name, name)) {
void *old_val = prop->value;
int ret;
/*0x2f*/ PSYCHO_IMAP_CE,
/*0x30*/ PSYCHO_IMAP_A_ERR,
/*0x31*/ PSYCHO_IMAP_B_ERR,
-/*0x32*/ PSYCHO_IMAP_PMGMT
+/*0x32*/ PSYCHO_IMAP_PMGMT,
+/*0x33*/ PSYCHO_IMAP_GFX,
+/*0x34*/ PSYCHO_IMAP_EUPA,
};
#define PSYCHO_ONBOARD_IRQ_BASE 0x20
-#define PSYCHO_ONBOARD_IRQ_LAST 0x32
+#define PSYCHO_ONBOARD_IRQ_LAST 0x34
#define psycho_onboard_imap_offset(__ino) \
__psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
- imap += 4;
iclr_off = psycho_iclr_offset(ino);
iclr = controller_regs + iclr_off;
- iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
static void psycho_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = psycho_irq_build;
/*0x2e*/ SABRE_IMAP_UE,
/*0x2f*/ SABRE_IMAP_CE,
/*0x30*/ SABRE_IMAP_PCIERR,
+/*0x31*/ 0 /* reserved */,
+/*0x32*/ 0 /* reserved */,
+/*0x33*/ SABRE_IMAP_GFX,
+/*0x34*/ SABRE_IMAP_EUPA,
};
#define SABRE_ONBOARD_IRQ_BASE 0x20
#define SABRE_ONBOARD_IRQ_LAST 0x30
static int sabre_device_needs_wsync(struct device_node *dp)
{
struct device_node *parent = dp->parent;
- char *parent_model, *parent_compat;
+ const char *parent_model, *parent_compat;
/* This traversal up towards the root is meant to
* handle two cases:
{
struct sabre_irq_data *irq_data = _data;
unsigned long controller_regs = irq_data->controller_regs;
- struct linux_prom_pci_registers *regs;
+ const struct linux_prom_pci_registers *regs;
unsigned long imap, iclr;
unsigned long imap_off, iclr_off;
int inofixup = 0;
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
- imap += 4;
iclr_off = sabre_iclr_offset(ino);
iclr = controller_regs + iclr_off;
- iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
static void sabre_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
struct sabre_irq_data *irq_data;
- u32 *busrange;
+ const u32 *busrange;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sabre_irq_build;
static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
unsigned int ino)
{
- return pbm_regs + schizo_iclr_offset(ino) + 4;
+
+ return pbm_regs + schizo_iclr_offset(ino);
}
static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
unsigned int ino)
{
- return pbm_regs + schizo_imap_offset(ino) + 4;
+ return pbm_regs + schizo_imap_offset(ino);
}
#define schizo_read(__reg) \
return virt_irq;
}
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
struct schizo_irq_data *irq_data;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->data = irq_data;
irq_data->pbm_regs = regs[0].phys_addr;
- irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+ if (is_tomatillo)
+ irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
+ else
+ irq_data->sync_reg = 0UL;
irq_data->portid = of_getintprop_default(dp, "portid", 0);
irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
}
+static void schizo_irq_trans_init(struct device_node *dp)
+{
+ __schizo_irq_trans_init(dp, 0);
+}
+
+static void tomatillo_irq_trans_init(struct device_node *dp)
+{
+ __schizo_irq_trans_init(dp, 1);
+}
+
static unsigned int pci_sun4v_irq_build(struct device_node *dp,
unsigned int devino,
void *_data)
static void pci_sun4v_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = pci_sun4v_irq_build;
dp->irq_trans->data = (void *) (unsigned long)
((regs->phys_addr >> 32UL) & 0x0fffffff);
}
+
+struct fire_irq_data {
+ unsigned long pbm_regs;
+ u32 portid;
+};
+
+#define FIRE_IMAP_BASE 0x001000
+#define FIRE_ICLR_BASE 0x001400
+
+static unsigned long fire_imap_offset(unsigned long ino)
+{
+ return FIRE_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_iclr_offset(unsigned long ino)
+{
+ return FIRE_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + fire_iclr_offset(ino);
+}
+
+static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + fire_imap_offset(ino);
+}
+
+static unsigned int fire_irq_build(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ struct fire_irq_data *irq_data = _data;
+ unsigned long pbm_regs = irq_data->pbm_regs;
+ unsigned long imap, iclr;
+ unsigned long int_ctrlr;
+
+ ino &= 0x3f;
+
+ /* Now build the IRQ bucket. */
+ imap = fire_ino_to_imap(pbm_regs, ino);
+ iclr = fire_ino_to_iclr(pbm_regs, ino);
+
+ /* Set the interrupt controller number. */
+ int_ctrlr = 1 << 6;
+ upa_writeq(int_ctrlr, imap);
+
+ /* The interrupt map registers do not have an INO field
+ * like other chips do. They return zero in the INO
+ * field, and the interrupt controller number is controlled
+ * in bits 6 thru 9. So in order for build_irq() to get
+ * the INO right we pass it in as part of the fixup
+ * which will get added to the map register zero value
+ * read by build_irq().
+ */
+ ino |= (irq_data->portid << 6);
+ ino -= int_ctrlr;
+ return build_irq(ino, iclr, imap);
+}
+
+static void fire_irq_trans_init(struct device_node *dp)
+{
+ const struct linux_prom64_registers *regs;
+ struct fire_irq_data *irq_data;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = fire_irq_build;
+
+ irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = irq_data;
+
+ irq_data->pbm_regs = regs[0].phys_addr;
+ irq_data->portid = of_getintprop_default(dp, "portid", 0);
+}
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
SYSIO_IMAP_CE,
SYSIO_IMAP_SBERR,
SYSIO_IMAP_PMGMT,
+ SYSIO_IMAP_GFX,
+ SYSIO_IMAP_EUPA,
};
#undef bogon
void *_data)
{
unsigned long reg_base = (unsigned long) _data;
- struct linux_prom_registers *regs;
+ const struct linux_prom_registers *regs;
unsigned long imap, iclr;
int sbus_slot = 0;
int sbus_level = 0;
static void sbus_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sbus_of_build_irq;
{ "pci108e,8001", schizo_irq_trans_init },
{ "SUNW,schizo+", schizo_irq_trans_init },
{ "pci108e,8002", schizo_irq_trans_init },
- { "SUNW,tomatillo", schizo_irq_trans_init },
- { "pci108e,a801", schizo_irq_trans_init },
+ { "SUNW,tomatillo", tomatillo_irq_trans_init },
+ { "pci108e,a801", tomatillo_irq_trans_init },
{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+ { "pciex108e,80f0", fire_irq_trans_init },
};
#endif
static void sun4v_vdev_irq_trans_init(struct device_node *dp)
{
- struct linux_prom64_registers *regs;
+ const struct linux_prom64_registers *regs;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = sun4v_vdev_irq_build;
static void irq_trans_init(struct device_node *dp)
{
- const char *model;
#ifdef CONFIG_PCI
+ const char *model;
int i;
#endif
+#ifdef CONFIG_PCI
model = of_get_property(dp, "model", NULL);
if (!model)
model = of_get_property(dp, "compatible", NULL);
- if (!model)
- return;
-
-#ifdef CONFIG_PCI
- for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
- struct irq_trans *t = &pci_irq_trans_table[i];
+ if (model) {
+ for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
+ struct irq_trans *t = &pci_irq_trans_table[i];
- if (!strcmp(model, t->name))
- return t->init(dp);
+ if (!strcmp(model, t->name))
+ return t->init(dp);
+ }
}
#endif
#ifdef CONFIG_SBUS
!strcmp(dp->name, "sbi"))
return sbus_irq_trans_init(dp);
#endif
- if (!strcmp(dp->name, "central"))
- return central_irq_trans_init(dp->child);
+ if (!strcmp(dp->name, "fhc") &&
+ !strcmp(dp->parent->name, "central"))
+ return central_irq_trans_init(dp);
if (!strcmp(dp->name, "virtual-devices"))
return sun4v_vdev_irq_trans_init(dp);
}
return buf;
}
-static struct device_node * __init create_node(phandle node)
+static struct device_node * __init create_node(phandle node, struct device_node *parent)
{
struct device_node *dp;
dp = prom_early_alloc(sizeof(*dp));
dp->unique_id = unique_id++;
+ dp->parent = parent;
kref_init(&dp->kref);
{
struct device_node *dp;
- dp = create_node(node);
+ dp = create_node(node, parent);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
- dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
{
struct device_node **nextp;
- allnodes = create_node(prom_root_node);
+ allnodes = create_node(prom_root_node, NULL);
allnodes->path_component_name = "";
allnodes->full_name = "/";