diff options
Diffstat (limited to 'drivers/sbus/sbus.c')
-rw-r--r-- | drivers/sbus/sbus.c | 143 |
1 files changed, 19 insertions, 124 deletions
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 5d30a3ebfccd..6e9b2608202b 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c | |||
@@ -1,7 +1,6 @@ | |||
1 | /* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $ | 1 | /* sbus.c: SBus support routines. |
2 | * sbus.c: SBus support routines. | ||
3 | * | 2 | * |
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | 3 | * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net) |
5 | */ | 4 | */ |
6 | 5 | ||
7 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
@@ -17,29 +16,12 @@ | |||
17 | #include <asm/bpp.h> | 16 | #include <asm/bpp.h> |
18 | #include <asm/irq.h> | 17 | #include <asm/irq.h> |
19 | 18 | ||
20 | struct sbus_bus *sbus_root = NULL; | 19 | struct sbus_bus *sbus_root; |
21 | |||
22 | static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } }; | ||
23 | #ifdef CONFIG_SPARC32 | ||
24 | static int interrupts[PROMINTR_MAX] __initdata = { 0 }; | ||
25 | #endif | ||
26 | 20 | ||
27 | #ifdef CONFIG_PCI | 21 | #ifdef CONFIG_PCI |
28 | extern int pcic_present(void); | 22 | extern int pcic_present(void); |
29 | #endif | 23 | #endif |
30 | 24 | ||
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 | |||
43 | static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) | 25 | static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) |
44 | { | 26 | { |
45 | unsigned long address, base; | 27 | unsigned long address, base; |
@@ -52,117 +34,30 @@ static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev) | |||
52 | len = prom_getproperty(prom_node, "reg", | 34 | len = prom_getproperty(prom_node, "reg", |
53 | (char *) sdev->reg_addrs, | 35 | (char *) sdev->reg_addrs, |
54 | sizeof(sdev->reg_addrs)); | 36 | sizeof(sdev->reg_addrs)); |
55 | if (len == -1) { | 37 | sdev->num_registers = 0; |
56 | sdev->num_registers = 0; | 38 | if (len != -1) { |
57 | goto no_regs; | 39 | sdev->num_registers = |
58 | } | 40 | len / sizeof(struct linux_prom_registers); |
59 | 41 | sdev->ranges_applied = 0; | |
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 | 42 | ||
76 | base = (unsigned long) sdev->reg_addrs[0].phys_addr; | 43 | base = (unsigned long) sdev->reg_addrs[0].phys_addr; |
77 | 44 | ||
78 | /* Compute the slot number. */ | 45 | /* Compute the slot number. */ |
79 | if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) { | 46 | if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) |
80 | sdev->slot = sbus_dev_slot(base); | 47 | sdev->slot = sbus_dev_slot(base); |
81 | } else { | 48 | else |
82 | sdev->slot = sdev->reg_addrs[0].which_io; | 49 | sdev->slot = sdev->reg_addrs[0].which_io; |
83 | } | 50 | } |
84 | 51 | ||
85 | no_regs: | ||
86 | len = prom_getproperty(prom_node, "ranges", | 52 | len = prom_getproperty(prom_node, "ranges", |
87 | (char *)sdev->device_ranges, | 53 | (char *)sdev->device_ranges, |
88 | sizeof(sdev->device_ranges)); | 54 | sizeof(sdev->device_ranges)); |
89 | if (len == -1) { | 55 | sdev->num_device_ranges = 0; |
90 | sdev->num_device_ranges = 0; | 56 | if (len != -1) |
91 | goto no_ranges; | 57 | sdev->num_device_ranges = |
92 | } | 58 | len / sizeof(struct linux_prom_ranges); |
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 | 59 | ||
109 | no_ranges: | 60 | sbus_fill_device_irq(sdev); |
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 | } | 61 | } |
167 | 62 | ||
168 | /* This routine gets called from whoever needs the sbus first, to scan | 63 | /* This routine gets called from whoever needs the sbus first, to scan |