~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/sbus/sbus.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.