int *addrc, int *sizec);
int (*map)(u32 *addr, const u32 *range,
int na, int ns, int pna);
- unsigned int (*get_flags)(u32 *addr);
+ unsigned int (*get_flags)(const u32 *addr);
};
/*
return 0;
}
-static unsigned int of_bus_default_get_flags(u32 *addr)
+static unsigned int of_bus_default_get_flags(const u32 *addr)
{
return IORESOURCE_MEM;
}
static int of_bus_pci_match(struct device_node *np)
{
if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+ const char *model = of_get_property(np, "model", NULL);
+
+ if (model && !strcmp(model, "SUNW,simba"))
+ return 0;
+
/* Do not do PCI specific frobbing if the
* PCI bridge lacks a ranges property. We
* want to pass it through up to the next
return 0;
}
+static int of_bus_simba_match(struct device_node *np)
+{
+ const char *model = of_get_property(np, "model", NULL);
+
+ if (model && !strcmp(model, "SUNW,simba"))
+ return 1;
+
+ /* Treat PCI busses lacking ranges property just like
+ * simba.
+ */
+ if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) {
+ if (!of_find_property(np, "ranges", NULL))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int of_bus_simba_map(u32 *addr, const u32 *range,
+ int na, int ns, int pna)
+{
+ return 0;
+}
+
static void of_bus_pci_count_cells(struct device_node *np,
int *addrc, int *sizec)
{
return 0;
}
-static unsigned int of_bus_pci_get_flags(u32 *addr)
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
{
unsigned int flags = 0;
u32 w = addr[0];
.map = of_bus_pci_map,
.get_flags = of_bus_pci_get_flags,
},
+ /* SIMBA */
+ {
+ .name = "simba",
+ .addr_prop_name = "assigned-addresses",
+ .match = of_bus_simba_match,
+ .count_cells = of_bus_pci_count_cells,
+ .map = of_bus_simba_map,
+ .get_flags = of_bus_pci_get_flags,
+ },
/* SBUS */
{
.name = "sbus",
u32 *addr,
int na, int ns, int pna)
{
- u32 *ranges;
+ const u32 *ranges;
unsigned int rlen;
int rone;
return 0;
}
+ /* When we miss an I/O space match on PCI, just pass it up
+ * to the next PCI bridge and/or controller.
+ */
+ if (!strcmp(bus->name, "pci") &&
+ (addr[0] & 0x03000000) == 0x01000000)
+ return 0;
+
return 1;
}
static int __init use_1to1_mapping(struct device_node *pp)
{
- char *model;
-
/* If this is on the PMU bus, don't try to translate it even
* if a ranges property exists.
*/
if (!strcmp(pp->name, "dma"))
return 0;
- /* Similarly for Simba PCI bridges. */
- model = of_get_property(pp, "model", NULL);
- if (model && !strcmp(model, "SUNW,simba"))
+ /* Similarly for all PCI bridges, if we get this far
+ * it lacks a ranges property, and this will include
+ * cases like Simba.
+ */
+ if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex"))
return 0;
return 1;
struct of_bus *bus;
int na, ns;
int index, num_reg;
- void *preg;
+ const void *preg;
if (!parent)
return;
/* Convert to num-entries. */
num_reg /= na + ns;
- /* Prevent overruning the op->resources[] array. */
+ /* Prevent overrunning the op->resources[] array. */
if (num_reg > PROMREG_MAX) {
printk(KERN_WARNING "%s: Too many regs (%d), "
"limiting to %d.\n",
for (index = 0; index < num_reg; index++) {
struct resource *r = &op->resource[index];
u32 addr[OF_MAX_ADDR_CELLS];
- u32 *reg = (preg + (index * ((na + ns) * 4)));
+ const u32 *reg = (preg + (index * ((na + ns) * 4)));
struct device_node *dp = op->node;
struct device_node *pp = p_op->node;
- struct of_bus *pbus;
+ struct of_bus *pbus, *dbus;
u64 size, result = OF_BAD_ADDR;
unsigned long flags;
int dna, dns;
dna = na;
dns = ns;
+ dbus = bus;
while (1) {
dp = pp;
pbus = of_match_bus(pp);
pbus->count_cells(dp, &pna, &pns);
- if (build_one_resource(dp, bus, pbus, addr,
+ if (build_one_resource(dp, dbus, pbus, addr,
dna, dns, pna))
break;
dna = pna;
dns = pns;
- bus = pbus;
+ dbus = pbus;
}
build_res:
r->start = result;
r->end = result + size - 1;
r->flags = flags;
- } else {
- r->start = ~0UL;
- r->end = ~0UL;
}
r->name = op->node->name;
}
static struct device_node * __init
apply_interrupt_map(struct device_node *dp, struct device_node *pp,
- u32 *imap, int imlen, u32 *imask,
+ const u32 *imap, int imlen, const u32 *imask,
unsigned int *irq_p)
{
struct device_node *cp;
unsigned int irq = *irq_p;
struct of_bus *bus;
phandle handle;
- u32 *reg;
+ const u32 *reg;
int na, num_reg, i;
bus = of_match_bus(pp);
struct device_node *pp,
unsigned int irq)
{
- struct linux_prom_pci_registers *regs;
- unsigned int devfn, slot, ret;
+ const struct linux_prom_pci_registers *regs;
+ unsigned int bus, devfn, slot, ret;
if (irq < 1 || irq > 4)
return irq;
if (!regs)
return irq;
+ bus = (regs->phys_hi >> 16) & 0xff;
devfn = (regs->phys_hi >> 8) & 0xff;
slot = (devfn >> 3) & 0x1f;
- ret = ((irq - 1 + (slot & 3)) & 3) + 1;
+ if (pp->irq_trans) {
+ /* Derived from Table 8-3, U2P User's Manual. This branch
+ * is handling a PCI controller that lacks a proper set of
+ * interrupt-map and interrupt-map-mask properties. The
+ * Ultra-E450 is one example.
+ *
+ * The bit layout is BSSLL, where:
+ * B: 0 on bus A, 1 on bus B
+ * D: 2-bit slot number, derived from PCI device number as
+ * (dev - 1) for bus A, or (dev - 2) for bus B
+ * L: 2-bit line number
+ */
+ if (bus & 0x80) {
+ /* PBM-A */
+ bus = 0x00;
+ slot = (slot - 1) << 2;
+ } else {
+ /* PBM-B */
+ bus = 0x10;
+ slot = (slot - 2) << 2;
+ }
+ irq -= 1;
+
+ ret = (bus | slot | irq);
+ } else {
+ /* Going through a PCI-PCI bridge that lacks a set of
+ * interrupt-map and interrupt-map-mask properties.
+ */
+ ret = ((irq - 1 + (slot & 3)) & 3) + 1;
+ }
return ret;
}
pp = dp->parent;
ip = NULL;
while (pp) {
- void *imap, *imsk;
+ const void *imap, *imsk;
int imlen;
imap = of_get_property(pp, "interrupt-map", &imlen);
struct device *parent)
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
- unsigned int *irq;
+ const unsigned int *irq;
int len, i;
if (!op)
op->num_irqs = 0;
}
- /* Prevent overruning the op->irqs[] array. */
+ /* Prevent overrunning the op->irqs[] array. */
if (op->num_irqs > PROMINTR_MAX) {
printk(KERN_WARNING "%s: Too many irqs (%d), "
"limiting to %d.\n",