static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) { unsigned long address, base; int len; sdev->prom_node = prom_node; prom_getstring(prom_node, "name", sdev->prom_name, sizeof(sdev->prom_name)); address = prom_getint(prom_node, "address"); len = prom_getproperty(prom_node, "reg", (char *) sdev->reg_addrs, sizeof(sdev->reg_addrs)); if (len == -1) { sdev->num_registers = 0; goto no_regs; } if (len % sizeof(struct linux_prom_registers)) { prom_printf("fill_sbus_device: proplen for regs of %s " " was %d, need multiple of %d\n", sdev->prom_name, len, (int) sizeof(struct linux_prom_registers)); prom_halt(); } if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) { prom_printf("fill_sbus_device: Too many register properties " "for device %s, len=%d\n", sdev->prom_name, len); prom_halt(); } sdev->num_registers = len / sizeof(struct linux_prom_registers); sdev->ranges_applied = 0; base = (unsigned long) sdev->reg_addrs[0].phys_addr; /* Compute the slot number. */ if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) { sdev->slot = sbus_dev_slot(base); } else { sdev->slot = sdev->reg_addrs[0].which_io; } no_regs: len = prom_getproperty(prom_node, "ranges", (char *)sdev->device_ranges, sizeof(sdev->device_ranges)); if (len == -1) { sdev->num_device_ranges = 0; goto no_ranges; } if (len % sizeof(struct linux_prom_ranges)) { prom_printf("fill_sbus_device: proplen for ranges of %s " " was %d, need multiple of %d\n", sdev->prom_name, len, (int) sizeof(struct linux_prom_ranges)); prom_halt(); } if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) { prom_printf("fill_sbus_device: Too many range properties " "for device %s, len=%d\n", sdev->prom_name, len); prom_halt(); } sdev->num_device_ranges = len / sizeof(struct linux_prom_ranges); no_ranges: /* XXX Unfortunately, IRQ issues are very arch specific. * XXX Pull this crud out into an arch specific area * XXX at some point. -DaveM */ #ifdef __sparc_v9__ len = prom_getproperty(prom_node, "interrupts", (char *) irqs, sizeof(irqs)); if (len == -1 || len == 0) { sdev->irqs[0] = 0; sdev->num_irqs = 0; } else { unsigned int pri = irqs[0].pri; sdev->num_irqs = 1; if (pri < 0x20) pri += sdev->slot * 8; sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); } #else len = prom_getproperty(prom_node, "intr", (char *)irqs, sizeof(irqs)); if (len == -1) len = 0; sdev->num_irqs = len / 8; if (sdev->num_irqs == 0) { sdev->irqs[0] = 0; } else if (sparc_cpu_model == sun4d) { extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); for (len = 0; len < sdev->num_irqs; len++) sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri); } else { for (len = 0; len < sdev->num_irqs; len++) sdev->irqs[len] = irqs[len].pri; } #endif /* !__sparc_v9__ */ }
__initfunc(static void fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev)) { int grrr, len; unsigned long dev_base_addr, base; sbus_dev->prom_node = nd; prom_getstring(nd, "name", lbuf, sizeof(lbuf)); strcpy(sbus_dev->prom_name, lbuf); dev_base_addr = prom_getint(nd, "address"); if(dev_base_addr != -1) sbus_dev->sbus_addr = dev_base_addr; len = prom_getproperty(nd, "reg", (void *) sbus_dev->reg_addrs, sizeof(sbus_dev->reg_addrs)); if(len == -1) goto no_regs; if(len%sizeof(struct linux_prom_registers)) { prom_printf("WHOOPS: proplen for %s was %d, need multiple of %d\n", sbus_dev->prom_name, len, (int) sizeof(struct linux_prom_registers)); panic("fill_sbus_device"); } sbus_dev->num_registers = (len/sizeof(struct linux_prom_registers)); sbus_dev->ranges_applied = 0; base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; if(base>=SUN_SBUS_BVADDR || (sparc_cpu_model != sun4c && sparc_cpu_model != sun4)) { /* Ahh, we can determine the slot and offset */ if(sparc_cpu_model == sun4u) { /* A bit tricky on the SYSIO. */ sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; sbus_dev->offset = sbus_dev_offset(base); } else if (sparc_cpu_model == sun4d) { sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; sbus_dev->offset = base; } else { sbus_dev->slot = sbus_dev_slot(base); sbus_dev->offset = sbus_dev_offset(base); } } else { /* Grrr, gotta do calculations to fix things up */ sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; sbus_dev->offset = base; sbus_dev->reg_addrs[0].phys_addr = sbus_devaddr(sbus_dev->slot, base); for(grrr=1; grrr<sbus_dev->num_registers; grrr++) { base = (unsigned long) sbus_dev->reg_addrs[grrr].phys_addr; sbus_dev->reg_addrs[grrr].phys_addr = sbus_devaddr(sbus_dev->slot, base); } /* That surely sucked */ } sbus_dev->sbus_addr = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; if(len>(sizeof(struct linux_prom_registers)*PROMREG_MAX)) { prom_printf("WHOOPS: I got too many register addresses for %s len=%d\n", sbus_dev->prom_name, len); panic("sbus device register overflow"); } no_regs: len = prom_getproperty(nd, "address", (void *) sbus_dev->sbus_vaddrs, sizeof(sbus_dev->sbus_vaddrs)); if(len == -1) len=0; if(len&3) { prom_printf("Grrr, I didn't get a multiple of 4 proplen " "for device %s got %d\n", sbus_dev->prom_name, len); len=0; } sbus_dev->num_vaddrs = (len/4); #ifdef __sparc_v9__ len = prom_getproperty(nd, "interrupts", (void *)irqs, sizeof(irqs)); if((len == -1) || (len == 0)) { sbus_dev->irqs[0] = 0; sbus_dev->num_irqs = 0; } else { sbus_dev->num_irqs = 1; if (irqs[0].pri < 0x20) sbus_dev->irqs[0] = sbus_build_irq(sbus_dev->my_bus, irqs[0].pri + (sbus_dev->slot * 8)); else sbus_dev->irqs[0] = sbus_build_irq(sbus_dev->my_bus, irqs[0].pri); } #else len = prom_getproperty(nd, "intr", (void *)irqs, sizeof(irqs)); if (len == -1) len=0; if (len&7) { prom_printf("Grrr, I didn't get a multiple of 8 proplen for " "device %s got %d\n", sbus_dev->prom_name, len); len=0; } if (len > 4 * 8) { prom_printf("Device %s has more than 4 interrupts\n", sbus_dev->prom_name); len = 4 * 8; } sbus_dev->num_irqs=(len/8); if(sbus_dev->num_irqs == 0) sbus_dev->irqs[0]=0; else if (sparc_cpu_model != sun4d) for (len = 0; len < sbus_dev->num_irqs; len++) sbus_dev->irqs[len] = irqs[len].pri; else { extern unsigned int sun4d_build_irq(struct linux_sbus_device *sdev, int irq); for (len = 0; len < sbus_dev->num_irqs; len++) sbus_dev->irqs[len] = sun4d_build_irq(sbus_dev, irqs[len].pri); } #endif #ifdef DEBUG_FILL #ifdef __sparc_v9__ prom_printf("Found %s at SBUS slot %x offset %016lx ", sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset); if (sbus_dev->irqs[0]) prom_printf("irq %s\n", __irq_itoa(sbus_dev->irqs[0])); else prom_printf("\n"); prom_printf("Base address %016lx\n", sbus_dev->sbus_addr); #else prom_printf("Found %s at SBUS slot %x offset %08lx irq-level %d\n", sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset, sbus_dev->irqs[0]); prom_printf("Base address %08lx\n", sbus_dev->sbus_addr); #endif prom_printf("REGISTERS: Probed %d register(s)\n", sbus_dev->num_registers); for(len=0; len<sbus_dev->num_registers; len++) #ifdef __sparc_v9__ prom_printf("Regs<%d> at address<%08lx> IO-space<%d> size<%d " "bytes, %d words>\n", (int) len, (unsigned long) sbus_dev->reg_addrs[len].phys_addr, sbus_dev->reg_addrs[len].which_io, sbus_dev->reg_addrs[len].reg_size, (sbus_dev->reg_addrs[len].reg_size/4)); #else prom_printf("Regs<%d> at address<%016lx> IO-space<%d> size<%d " "bytes, %d words>\n", (int) len, (unsigned long) sbus_dev->reg_addrs[len].phys_addr, sbus_dev->reg_addrs[len].which_io, sbus_dev->reg_addrs[len].reg_size, (sbus_dev->reg_addrs[len].reg_size/4)); #endif #endif }