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.15 564 lines 15 kB view raw
1/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $ 2 * sbus.c: SBus support routines. 3 * 4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 5 */ 6 7#include <linux/kernel.h> 8#include <linux/slab.h> 9#include <linux/config.h> 10#include <linux/init.h> 11#include <linux/pci.h> 12 13#include <asm/system.h> 14#include <asm/sbus.h> 15#include <asm/dma.h> 16#include <asm/oplib.h> 17#include <asm/bpp.h> 18#include <asm/irq.h> 19 20struct sbus_bus *sbus_root = NULL; 21 22static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } }; 23#ifdef CONFIG_SPARC32 24static int interrupts[PROMINTR_MAX] __initdata = { 0 }; 25#endif 26 27#ifdef CONFIG_PCI 28extern int pcic_present(void); 29#endif 30 31/* Perhaps when I figure out more about the iommu we'll put a 32 * device registration routine here that probe_sbus() calls to 33 * setup the iommu for each Sbus. 34 */ 35 36/* We call this for each SBus device, and fill the structure based 37 * upon the prom device tree. We return the start of memory after 38 * the things we have allocated. 39 */ 40 41/* #define DEBUG_FILL */ 42 43static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) 44{ 45 unsigned long address, base; 46 int len; 47 48 sdev->prom_node = prom_node; 49 prom_getstring(prom_node, "name", 50 sdev->prom_name, sizeof(sdev->prom_name)); 51 address = prom_getint(prom_node, "address"); 52 len = prom_getproperty(prom_node, "reg", 53 (char *) sdev->reg_addrs, 54 sizeof(sdev->reg_addrs)); 55 if (len == -1) { 56 sdev->num_registers = 0; 57 goto no_regs; 58 } 59 60 if (len % sizeof(struct linux_prom_registers)) { 61 prom_printf("fill_sbus_device: proplen for regs of %s " 62 " was %d, need multiple of %d\n", 63 sdev->prom_name, len, 64 (int) sizeof(struct linux_prom_registers)); 65 prom_halt(); 66 } 67 if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) { 68 prom_printf("fill_sbus_device: Too many register properties " 69 "for device %s, len=%d\n", 70 sdev->prom_name, len); 71 prom_halt(); 72 } 73 sdev->num_registers = len / sizeof(struct linux_prom_registers); 74 sdev->ranges_applied = 0; 75 76 base = (unsigned long) sdev->reg_addrs[0].phys_addr; 77 78 /* Compute the slot number. */ 79 if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) { 80 sdev->slot = sbus_dev_slot(base); 81 } else { 82 sdev->slot = sdev->reg_addrs[0].which_io; 83 } 84 85no_regs: 86 len = prom_getproperty(prom_node, "ranges", 87 (char *)sdev->device_ranges, 88 sizeof(sdev->device_ranges)); 89 if (len == -1) { 90 sdev->num_device_ranges = 0; 91 goto no_ranges; 92 } 93 if (len % sizeof(struct linux_prom_ranges)) { 94 prom_printf("fill_sbus_device: proplen for ranges of %s " 95 " was %d, need multiple of %d\n", 96 sdev->prom_name, len, 97 (int) sizeof(struct linux_prom_ranges)); 98 prom_halt(); 99 } 100 if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) { 101 prom_printf("fill_sbus_device: Too many range properties " 102 "for device %s, len=%d\n", 103 sdev->prom_name, len); 104 prom_halt(); 105 } 106 sdev->num_device_ranges = 107 len / sizeof(struct linux_prom_ranges); 108 109no_ranges: 110 /* XXX Unfortunately, IRQ issues are very arch specific. 111 * XXX Pull this crud out into an arch specific area 112 * XXX at some point. -DaveM 113 */ 114#ifdef CONFIG_SPARC64 115 len = prom_getproperty(prom_node, "interrupts", 116 (char *) irqs, sizeof(irqs)); 117 if (len == -1 || len == 0) { 118 sdev->irqs[0] = 0; 119 sdev->num_irqs = 0; 120 } else { 121 unsigned int pri = irqs[0].pri; 122 123 sdev->num_irqs = 1; 124 if (pri < 0x20) 125 pri += sdev->slot * 8; 126 127 sdev->irqs[0] = sbus_build_irq(sdev->bus, pri); 128 } 129#endif /* CONFIG_SPARC64 */ 130 131#ifdef CONFIG_SPARC32 132 len = prom_getproperty(prom_node, "intr", 133 (char *)irqs, sizeof(irqs)); 134 if (len != -1) { 135 sdev->num_irqs = len / 8; 136 if (sdev->num_irqs == 0) { 137 sdev->irqs[0] = 0; 138 } else if (sparc_cpu_model == sun4d) { 139 extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); 140 141 for (len = 0; len < sdev->num_irqs; len++) 142 sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri); 143 } else { 144 for (len = 0; len < sdev->num_irqs; len++) 145 sdev->irqs[len] = irqs[len].pri; 146 } 147 } else { 148 /* No "intr" node found-- check for "interrupts" node. 149 * This node contains SBus interrupt levels, not IPLs 150 * as in "intr", and no vector values. We convert 151 * SBus interrupt levels to PILs (platform specific). 152 */ 153 len = prom_getproperty(prom_node, "interrupts", 154 (char *)interrupts, sizeof(interrupts)); 155 if (len == -1) { 156 sdev->irqs[0] = 0; 157 sdev->num_irqs = 0; 158 } else { 159 sdev->num_irqs = len / sizeof(int); 160 for (len = 0; len < sdev->num_irqs; len++) { 161 sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]); 162 } 163 } 164 } 165#endif /* CONFIG_SPARC32 */ 166} 167 168/* This routine gets called from whoever needs the sbus first, to scan 169 * the SBus device tree. Currently it just prints out the devices 170 * found on the bus and builds trees of SBUS structs and attached 171 * devices. 172 */ 173 174extern void iommu_init(int iommu_node, struct sbus_bus *sbus); 175extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus); 176void sun4_init(void); 177#ifdef CONFIG_SUN_AUXIO 178extern void auxio_probe(void); 179#endif 180 181static void __init sbus_do_child_siblings(int start_node, 182 struct sbus_dev *child, 183 struct sbus_dev *parent, 184 struct sbus_bus *sbus) 185{ 186 struct sbus_dev *this_dev = child; 187 int this_node = start_node; 188 189 /* Child already filled in, just need to traverse siblings. */ 190 child->child = NULL; 191 child->parent = parent; 192 while((this_node = prom_getsibling(this_node)) != 0) { 193 this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); 194 this_dev = this_dev->next; 195 this_dev->next = NULL; 196 this_dev->parent = parent; 197 198 this_dev->bus = sbus; 199 fill_sbus_device(this_node, this_dev); 200 201 if(prom_getchild(this_node)) { 202 this_dev->child = kmalloc(sizeof(struct sbus_dev), 203 GFP_ATOMIC); 204 this_dev->child->bus = sbus; 205 this_dev->child->next = NULL; 206 fill_sbus_device(prom_getchild(this_node), this_dev->child); 207 sbus_do_child_siblings(prom_getchild(this_node), 208 this_dev->child, this_dev, sbus); 209 } else { 210 this_dev->child = NULL; 211 } 212 } 213} 214 215/* 216 * XXX This functions appears to be a distorted version of 217 * prom_sbus_ranges_init(), with all sun4d stuff cut away. 218 * Ask DaveM what is going on here, how is sun4d supposed to work... XXX 219 */ 220/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ 221 222static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus) 223{ 224 int len; 225 226 len = prom_getproperty(sbus->prom_node, "ranges", 227 (char *) sbus->sbus_ranges, 228 sizeof(sbus->sbus_ranges)); 229 if (len == -1 || len == 0) { 230 sbus->num_sbus_ranges = 0; 231 return; 232 } 233 sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges); 234#ifdef CONFIG_SPARC32 235 if (sparc_cpu_model == sun4d) { 236 struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; 237 int num_iounit_ranges; 238 239 len = prom_getproperty(parent_node, "ranges", 240 (char *) iounit_ranges, 241 sizeof (iounit_ranges)); 242 if (len != -1) { 243 num_iounit_ranges = (len/sizeof(struct linux_prom_ranges)); 244 prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges); 245 } 246 } 247#endif 248} 249 250static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges, 251 int num_ranges, 252 struct linux_prom_registers *regs, 253 int num_regs) 254{ 255 if (num_ranges) { 256 int regnum; 257 258 for (regnum = 0; regnum < num_regs; regnum++) { 259 int rngnum; 260 261 for (rngnum = 0; rngnum < num_ranges; rngnum++) { 262 if (regs[regnum].which_io == ranges[rngnum].ot_child_space) 263 break; 264 } 265 if (rngnum == num_ranges) { 266 /* We used to flag this as an error. Actually 267 * some devices do not report the regs as we expect. 268 * For example, see SUNW,pln device. In that case 269 * the reg property is in a format internal to that 270 * node, ie. it is not in the SBUS register space 271 * per se. -DaveM 272 */ 273 return; 274 } 275 regs[regnum].which_io = ranges[rngnum].ot_parent_space; 276 regs[regnum].phys_addr -= ranges[rngnum].ot_child_base; 277 regs[regnum].phys_addr += ranges[rngnum].ot_parent_base; 278 } 279 } 280} 281 282static void __init __fixup_regs_sdev(struct sbus_dev *sdev) 283{ 284 if (sdev->num_registers != 0) { 285 struct sbus_dev *parent = sdev->parent; 286 int i; 287 288 while (parent != NULL) { 289 __apply_ranges_to_regs(parent->device_ranges, 290 parent->num_device_ranges, 291 sdev->reg_addrs, 292 sdev->num_registers); 293 294 parent = parent->parent; 295 } 296 297 __apply_ranges_to_regs(sdev->bus->sbus_ranges, 298 sdev->bus->num_sbus_ranges, 299 sdev->reg_addrs, 300 sdev->num_registers); 301 302 for (i = 0; i < sdev->num_registers; i++) { 303 struct resource *res = &sdev->resource[i]; 304 305 res->start = sdev->reg_addrs[i].phys_addr; 306 res->end = (res->start + 307 (unsigned long)sdev->reg_addrs[i].reg_size - 1UL); 308 res->flags = IORESOURCE_IO | 309 (sdev->reg_addrs[i].which_io & 0xff); 310 } 311 } 312} 313 314static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev) 315{ 316 struct sbus_dev *sdev; 317 318 for (sdev = first_sdev; sdev; sdev = sdev->next) { 319 if (sdev->child) 320 sbus_fixup_all_regs(sdev->child); 321 __fixup_regs_sdev(sdev); 322 } 323} 324 325extern void register_proc_sparc_ioport(void); 326extern void firetruck_init(void); 327 328#ifdef CONFIG_SUN4 329extern void sun4_dvma_init(void); 330#endif 331 332static int __init sbus_init(void) 333{ 334 int nd, this_sbus, sbus_devs, topnd, iommund; 335 unsigned int sbus_clock; 336 struct sbus_bus *sbus; 337 struct sbus_dev *this_dev; 338 int num_sbus = 0; /* How many did we find? */ 339 340#ifdef CONFIG_SPARC32 341 register_proc_sparc_ioport(); 342#endif 343 344#ifdef CONFIG_SUN4 345 sun4_dvma_init(); 346 return 0; 347#endif 348 349 topnd = prom_getchild(prom_root_node); 350 351 /* Finding the first sbus is a special case... */ 352 iommund = 0; 353 if(sparc_cpu_model == sun4u) { 354 nd = prom_searchsiblings(topnd, "sbus"); 355 if(nd == 0) { 356#ifdef CONFIG_PCI 357 if (!pcic_present()) { 358 prom_printf("Neither SBUS nor PCI found.\n"); 359 prom_halt(); 360 } else { 361#ifdef CONFIG_SPARC64 362 firetruck_init(); 363#endif 364 } 365 return 0; 366#else 367 prom_printf("YEEE, UltraSparc sbus not found\n"); 368 prom_halt(); 369#endif 370 } 371 } else if(sparc_cpu_model == sun4d) { 372 if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 || 373 (nd = prom_getchild(iommund)) == 0 || 374 (nd = prom_searchsiblings(nd, "sbi")) == 0) { 375 panic("sbi not found"); 376 } 377 } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) { 378 if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || 379 (nd = prom_getchild(iommund)) == 0 || 380 (nd = prom_searchsiblings(nd, "sbus")) == 0) { 381#ifdef CONFIG_PCI 382 if (!pcic_present()) { 383 prom_printf("Neither SBUS nor PCI found.\n"); 384 prom_halt(); 385 } 386 return 0; 387#else 388 /* No reason to run further - the data access trap will occur. */ 389 panic("sbus not found"); 390#endif 391 } 392 } 393 394 /* Ok, we've found the first one, allocate first SBus struct 395 * and place in chain. 396 */ 397 sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); 398 sbus->next = NULL; 399 sbus->prom_node = nd; 400 this_sbus = nd; 401 402 if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d) 403 iommu_init(iommund, sbus); 404 405 /* Loop until we find no more SBUS's */ 406 while(this_sbus) { 407#ifdef CONFIG_SPARC64 408 /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */ 409 if(sparc_cpu_model == sun4u) { 410 extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus); 411 412 sbus_iommu_init(this_sbus, sbus); 413 } 414#endif /* CONFIG_SPARC64 */ 415 416#ifdef CONFIG_SPARC32 417 if (sparc_cpu_model == sun4d) 418 iounit_init(this_sbus, iommund, sbus); 419#endif /* CONFIG_SPARC32 */ 420 printk("sbus%d: ", num_sbus); 421 sbus_clock = prom_getint(this_sbus, "clock-frequency"); 422 if(sbus_clock == -1) 423 sbus_clock = (25*1000*1000); 424 printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), 425 (int) (((sbus_clock/1000)%1000 != 0) ? 426 (((sbus_clock/1000)%1000) + 1000) : 0)); 427 428 prom_getstring(this_sbus, "name", 429 sbus->prom_name, sizeof(sbus->prom_name)); 430 sbus->clock_freq = sbus_clock; 431#ifdef CONFIG_SPARC32 432 if (sparc_cpu_model == sun4d) { 433 sbus->devid = prom_getint(iommund, "device-id"); 434 sbus->board = prom_getint(iommund, "board#"); 435 } 436#endif 437 438 sbus_bus_ranges_init(iommund, sbus); 439 440 sbus_devs = prom_getchild(this_sbus); 441 if (!sbus_devs) { 442 sbus->devices = NULL; 443 goto next_bus; 444 } 445 446 sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC); 447 448 this_dev = sbus->devices; 449 this_dev->next = NULL; 450 451 this_dev->bus = sbus; 452 this_dev->parent = NULL; 453 fill_sbus_device(sbus_devs, this_dev); 454 455 /* Should we traverse for children? */ 456 if(prom_getchild(sbus_devs)) { 457 /* Allocate device node */ 458 this_dev->child = kmalloc(sizeof(struct sbus_dev), 459 GFP_ATOMIC); 460 /* Fill it */ 461 this_dev->child->bus = sbus; 462 this_dev->child->next = NULL; 463 fill_sbus_device(prom_getchild(sbus_devs), 464 this_dev->child); 465 sbus_do_child_siblings(prom_getchild(sbus_devs), 466 this_dev->child, 467 this_dev, 468 sbus); 469 } else { 470 this_dev->child = NULL; 471 } 472 473 while((sbus_devs = prom_getsibling(sbus_devs)) != 0) { 474 /* Allocate device node */ 475 this_dev->next = kmalloc(sizeof(struct sbus_dev), 476 GFP_ATOMIC); 477 this_dev = this_dev->next; 478 this_dev->next = NULL; 479 480 /* Fill it */ 481 this_dev->bus = sbus; 482 this_dev->parent = NULL; 483 fill_sbus_device(sbus_devs, this_dev); 484 485 /* Is there a child node hanging off of us? */ 486 if(prom_getchild(sbus_devs)) { 487 /* Get new device struct */ 488 this_dev->child = kmalloc(sizeof(struct sbus_dev), 489 GFP_ATOMIC); 490 /* Fill it */ 491 this_dev->child->bus = sbus; 492 this_dev->child->next = NULL; 493 fill_sbus_device(prom_getchild(sbus_devs), 494 this_dev->child); 495 sbus_do_child_siblings(prom_getchild(sbus_devs), 496 this_dev->child, 497 this_dev, 498 sbus); 499 } else { 500 this_dev->child = NULL; 501 } 502 } 503 504 /* Walk all devices and apply parent ranges. */ 505 sbus_fixup_all_regs(sbus->devices); 506 507 dvma_init(sbus); 508 next_bus: 509 num_sbus++; 510 if(sparc_cpu_model == sun4u) { 511 this_sbus = prom_getsibling(this_sbus); 512 if(!this_sbus) 513 break; 514 this_sbus = prom_searchsiblings(this_sbus, "sbus"); 515 } else if(sparc_cpu_model == sun4d) { 516 iommund = prom_getsibling(iommund); 517 if(!iommund) 518 break; 519 iommund = prom_searchsiblings(iommund, "io-unit"); 520 if(!iommund) 521 break; 522 this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi"); 523 } else { 524 this_sbus = prom_getsibling(this_sbus); 525 if(!this_sbus) 526 break; 527 this_sbus = prom_searchsiblings(this_sbus, "sbus"); 528 } 529 if(this_sbus) { 530 sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC); 531 sbus = sbus->next; 532 sbus->next = NULL; 533 sbus->prom_node = this_sbus; 534 } else { 535 break; 536 } 537 } /* while(this_sbus) */ 538 539 if (sparc_cpu_model == sun4d) { 540 extern void sun4d_init_sbi_irq(void); 541 sun4d_init_sbi_irq(); 542 } 543 544#ifdef CONFIG_SPARC64 545 if (sparc_cpu_model == sun4u) { 546 firetruck_init(); 547 } 548#endif 549#ifdef CONFIG_SUN_AUXIO 550 if (sparc_cpu_model == sun4u) 551 auxio_probe (); 552#endif 553#ifdef CONFIG_SPARC64 554 if (sparc_cpu_model == sun4u) { 555 extern void clock_probe(void); 556 557 clock_probe(); 558 } 559#endif 560 561 return 0; 562} 563 564subsys_initcall(sbus_init);