Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc1 316 lines 7.5 kB view raw
1/* sbus.c: SBus support routines. 2 * 3 * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) 4 */ 5 6#include <linux/kernel.h> 7#include <linux/slab.h> 8#include <linux/init.h> 9#include <linux/device.h> 10 11#include <asm/system.h> 12#include <asm/sbus.h> 13#include <asm/dma.h> 14#include <asm/oplib.h> 15#include <asm/prom.h> 16#include <asm/of_device.h> 17#include <asm/bpp.h> 18#include <asm/irq.h> 19 20static ssize_t 21show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf) 22{ 23 struct sbus_dev *sbus; 24 25 sbus = to_sbus_device(dev); 26 27 return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name); 28} 29 30static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL); 31 32struct sbus_bus *sbus_root; 33 34static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev) 35{ 36 struct dev_archdata *sd; 37 unsigned long base; 38 const void *pval; 39 int len, err; 40 41 sdev->prom_node = dp->node; 42 strcpy(sdev->prom_name, dp->name); 43 44 pval = of_get_property(dp, "reg", &len); 45 sdev->num_registers = 0; 46 if (pval) { 47 memcpy(sdev->reg_addrs, pval, len); 48 49 sdev->num_registers = 50 len / sizeof(struct linux_prom_registers); 51 52 base = (unsigned long) sdev->reg_addrs[0].phys_addr; 53 54 /* Compute the slot number. */ 55 if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) 56 sdev->slot = sbus_dev_slot(base); 57 else 58 sdev->slot = sdev->reg_addrs[0].which_io; 59 } 60 61 pval = of_get_property(dp, "ranges", &len); 62 sdev->num_device_ranges = 0; 63 if (pval) { 64 memcpy(sdev->device_ranges, pval, len); 65 sdev->num_device_ranges = 66 len / sizeof(struct linux_prom_ranges); 67 } 68 69 sbus_fill_device_irq(sdev); 70 71 sd = &sdev->ofdev.dev.archdata; 72 sd->prom_node = dp; 73 sd->op = &sdev->ofdev; 74 75 sdev->ofdev.node = dp; 76 if (sdev->parent) 77 sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev; 78 else 79 sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev; 80 sdev->ofdev.dev.bus = &sbus_bus_type; 81 sprintf(sdev->ofdev.dev.bus_id, "sbus[%08x]", dp->node); 82 83 if (of_device_register(&sdev->ofdev) != 0) 84 printk(KERN_DEBUG "sbus: device registration error for %s!\n", 85 dp->path_component_name); 86 87 /* WE HAVE BEEN INVADED BY ALIENS! */ 88 err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr); 89} 90 91static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus) 92{ 93 const void *pval; 94 int len; 95 96 pval = of_get_property(dp, "ranges", &len); 97 sbus->num_sbus_ranges = 0; 98 if (pval) { 99 memcpy(sbus->sbus_ranges, pval, len); 100 sbus->num_sbus_ranges = 101 len / sizeof(struct linux_prom_ranges); 102 103 sbus_arch_bus_ranges_init(dp->parent, sbus); 104 } 105} 106 107static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, 108 int num_ranges, 109 struct linux_prom_registers *regs, 110 int num_regs) 111{ 112 if (num_ranges) { 113 int regnum; 114 115 for (regnum = 0; regnum < num_regs; regnum++) { 116 int rngnum; 117 118 for (rngnum = 0; rngnum < num_ranges; rngnum++) { 119 if (regs[regnum].which_io == ranges[rngnum].ot_child_space) 120 break; 121 } 122 if (rngnum == num_ranges) { 123 /* We used to flag this as an error. Actually 124 * some devices do not report the regs as we expect. 125 * For example, see SUNW,pln device. In that case 126 * the reg property is in a format internal to that 127 * node, ie. it is not in the SBUS register space 128 * per se. -DaveM 129 */ 130 return; 131 } 132 regs[regnum].which_io = ranges[rngnum].ot_parent_space; 133 regs[regnum].phys_addr -= ranges[rngnum].ot_child_base; 134 regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; 135 } 136 } 137} 138 139static void __init __fixup_regs_sdev(struct sbus_dev *sdev) 140{ 141 if (sdev->num_registers != 0) { 142 struct sbus_dev *parent = sdev->parent; 143 int i; 144 145 while (parent != NULL) { 146 __apply_ranges_to_regs(parent->device_ranges, 147 parent->num_device_ranges, 148 sdev->reg_addrs, 149 sdev->num_registers); 150 151 parent = parent->parent; 152 } 153 154 __apply_ranges_to_regs(sdev->bus->sbus_ranges, 155 sdev->bus->num_sbus_ranges, 156 sdev->reg_addrs, 157 sdev->num_registers); 158 159 for (i = 0; i < sdev->num_registers; i++) { 160 struct resource *res = &sdev->resource[i]; 161 162 res->start = sdev->reg_addrs[i].phys_addr; 163 res->end = (res->start + 164 (unsigned long)sdev->reg_addrs[i].reg_size - 1UL); 165 res->flags = IORESOURCE_IO | 166 (sdev->reg_addrs[i].which_io & 0xff); 167 } 168 } 169} 170 171static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) 172{ 173 struct sbus_dev *sdev; 174 175 for (sdev = first_sdev; sdev; sdev = sdev->next) { 176 if (sdev->child) 177 sbus_fixup_all_regs(sdev->child); 178 __fixup_regs_sdev(sdev); 179 } 180} 181 182/* We preserve the "probe order" of these bus and device lists to give 183 * the same ordering as the old code. 184 */ 185static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root) 186{ 187 while (*root) 188 root = &(*root)->next; 189 *root = sbus; 190 sbus->next = NULL; 191} 192 193static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root) 194{ 195 while (*root) 196 root = &(*root)->next; 197 *root = sdev; 198 sdev->next = NULL; 199} 200 201static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus) 202{ 203 dp = dp->child; 204 while (dp) { 205 struct sbus_dev *sdev; 206 207 sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); 208 if (sdev) { 209 sdev_insert(sdev, &parent->child); 210 211 sdev->bus = sbus; 212 sdev->parent = parent; 213 sdev->ofdev.dev.archdata.iommu = 214 sbus->ofdev.dev.archdata.iommu; 215 sdev->ofdev.dev.archdata.stc = 216 sbus->ofdev.dev.archdata.stc; 217 218 fill_sbus_device(dp, sdev); 219 220 walk_children(dp, sdev, sbus); 221 } 222 dp = dp->sibling; 223 } 224} 225 226static void __init build_one_sbus(struct device_node *dp, int num_sbus) 227{ 228 struct sbus_bus *sbus; 229 unsigned int sbus_clock; 230 struct device_node *dev_dp; 231 232 sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC); 233 if (!sbus) 234 return; 235 236 sbus_insert(sbus, &sbus_root); 237 sbus->prom_node = dp->node; 238 239 sbus_setup_iommu(sbus, dp); 240 241 printk("sbus%d: ", num_sbus); 242 243 sbus_clock = of_getintprop_default(dp, "clock-frequency", 244 (25*1000*1000)); 245 sbus->clock_freq = sbus_clock; 246 247 printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), 248 (int) (((sbus_clock/1000)%1000 != 0) ? 249 (((sbus_clock/1000)%1000) + 1000) : 0)); 250 251 strcpy(sbus->prom_name, dp->name); 252 253 sbus_setup_arch_props(sbus, dp); 254 255 sbus_bus_ranges_init(dp, sbus); 256 257 sbus->ofdev.node = dp; 258 sbus->ofdev.dev.parent = NULL; 259 sbus->ofdev.dev.bus = &sbus_bus_type; 260 sprintf(sbus->ofdev.dev.bus_id, "sbus%d", num_sbus); 261 262 if (of_device_register(&sbus->ofdev) != 0) 263 printk(KERN_DEBUG "sbus: device registration error for %s!\n", 264 sbus->ofdev.dev.bus_id); 265 266 dev_dp = dp->child; 267 while (dev_dp) { 268 struct sbus_dev *sdev; 269 270 sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC); 271 if (sdev) { 272 sdev_insert(sdev, &sbus->devices); 273 274 sdev->bus = sbus; 275 sdev->parent = NULL; 276 sdev->ofdev.dev.archdata.iommu = 277 sbus->ofdev.dev.archdata.iommu; 278 sdev->ofdev.dev.archdata.stc = 279 sbus->ofdev.dev.archdata.stc; 280 281 fill_sbus_device(dev_dp, sdev); 282 283 walk_children(dev_dp, sdev, sbus); 284 } 285 dev_dp = dev_dp->sibling; 286 } 287 288 sbus_fixup_all_regs(sbus->devices); 289 290 dvma_init(sbus); 291} 292 293static int __init sbus_init(void) 294{ 295 struct device_node *dp; 296 const char *sbus_name = "sbus"; 297 int num_sbus = 0; 298 299 if (sbus_arch_preinit()) 300 return 0; 301 302 if (sparc_cpu_model == sun4d) 303 sbus_name = "sbi"; 304 305 for_each_node_by_name(dp, sbus_name) { 306 build_one_sbus(dp, num_sbus); 307 num_sbus++; 308 309 } 310 311 sbus_arch_postinit(); 312 313 return 0; 314} 315 316subsys_initcall(sbus_init);