Deleted Added
full compact
isa.c (133589) isa.c (137819)
1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 11 unchanged lines hidden (view full) ---

20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * from: FreeBSD: src/sys/alpha/isa/isa.c,v 1.26 2001/07/11
1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 11 unchanged lines hidden (view full) ---

20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * from: FreeBSD: src/sys/alpha/isa/isa.c,v 1.26 2001/07/11
28 *
29 * $FreeBSD: head/sys/sparc64/isa/isa.c 133589 2004-08-12 17:41:33Z marius $
30 */
31
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sys/sparc64/isa/isa.c 137819 2004-11-17 14:44:10Z marius $");
32
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35
36#include <machine/bus.h>
37
38#include <sys/rman.h>
39

--- 21 unchanged lines hidden (view full) ---

61static u_int64_t isa_io_base;
62static u_int64_t isa_io_limit;
63static u_int64_t isa_mem_base;
64static u_int64_t isa_mem_limit;
65
66device_t isa_bus_device;
67
68static phandle_t isab_node;
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36
37#include <machine/bus.h>
38
39#include <sys/rman.h>
40

--- 21 unchanged lines hidden (view full) ---

62static u_int64_t isa_io_base;
63static u_int64_t isa_io_limit;
64static u_int64_t isa_mem_base;
65static u_int64_t isa_mem_limit;
66
67device_t isa_bus_device;
68
69static phandle_t isab_node;
70static struct isa_ranges *isab_ranges;
71static int isab_nrange;
69static ofw_pci_intr_t isa_ino[8];
72static ofw_pci_intr_t isa_ino[8];
70struct ofw_bus_iinfo isa_iinfo;
73static struct ofw_bus_iinfo isa_iinfo;
71
72/*
74
75/*
73 * XXX: This is really partly partly PCI-specific, but unfortunately is
76 * XXX: This is really partly PCI-specific, but unfortunately is
74 * differently enough to have to duplicate it here...
75 */
76#define ISAB_RANGE_PHYS(r) \
77 (((u_int64_t)(r)->phys_mid << 32) | (u_int64_t)(r)->phys_lo)
78#define ISAB_RANGE_SPACE(r) (((r)->phys_hi >> 24) & 0x03)
79
80#define ISAR_SPACE_IO 0x01
81#define ISAR_SPACE_MEM 0x02
82
83#define INRANGE(x, start, end) ((x) >= (start) && (x) <= (end))
84
77 * differently enough to have to duplicate it here...
78 */
79#define ISAB_RANGE_PHYS(r) \
80 (((u_int64_t)(r)->phys_mid << 32) | (u_int64_t)(r)->phys_lo)
81#define ISAB_RANGE_SPACE(r) (((r)->phys_hi >> 24) & 0x03)
82
83#define ISAR_SPACE_IO 0x01
84#define ISAR_SPACE_MEM 0x02
85
86#define INRANGE(x, start, end) ((x) >= (start) && (x) <= (end))
87
85static int isa_route_intr_res(device_t, u_long, u_long);
88static void isa_setup_children(device_t, phandle_t);
86
87intrmask_t
88isa_irq_pending(void)
89{
90 intrmask_t pending;
91 int i;
92
93 /* XXX: Is this correct? */

--- 6 unchanged lines hidden (view full) ---

100 }
101 return (pending);
102}
103
104void
105isa_init(device_t dev)
106{
107 device_t bridge;
89
90intrmask_t
91isa_irq_pending(void)
92{
93 intrmask_t pending;
94 int i;
95
96 /* XXX: Is this correct? */

--- 6 unchanged lines hidden (view full) ---

103 }
104 return (pending);
105}
106
107void
108isa_init(device_t dev)
109{
110 device_t bridge;
108 phandle_t node;
109 ofw_isa_intr_t ino;
110 struct isa_ranges *br;
111 int nbr, i;
111 int i;
112
113 /* The parent of the bus must be a PCI-ISA bridge. */
114 bridge = device_get_parent(dev);
115 isab_node = ofw_bus_get_node(bridge);
112
113 /* The parent of the bus must be a PCI-ISA bridge. */
114 bridge = device_get_parent(dev);
115 isab_node = ofw_bus_get_node(bridge);
116 nbr = OF_getprop_alloc(isab_node, "ranges", sizeof(*br), (void **)&br);
117 if (nbr <= 0)
116 isab_nrange = OF_getprop_alloc(isab_node, "ranges",
117 sizeof(*isab_ranges), (void **)&isab_ranges);
118 if (isab_nrange <= 0)
118 panic("isa_init: cannot get bridge range property");
119
120 ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t));
121
122 /*
123 * This is really a bad kludge; however, it is needed to provide
124 * isa_irq_pending(), which is unfortunately still used by some
125 * drivers.
119 panic("isa_init: cannot get bridge range property");
120
121 ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t));
122
123 /*
124 * This is really a bad kludge; however, it is needed to provide
125 * isa_irq_pending(), which is unfortunately still used by some
126 * drivers.
127 * XXX: The only driver still using isa_irq_pending() is sio(4)
128 * which we don't use on sparc64. Should we just drop support
129 * for isa_irq_pending()?
126 */
127 for (i = 0; i < 8; i++)
128 isa_ino[i] = PCI_INVALID_IRQ;
130 */
131 for (i = 0; i < 8; i++)
132 isa_ino[i] = PCI_INVALID_IRQ;
129 for (node = OF_child(isab_node); node != 0; node = OF_peer(node)) {
130 if (OF_getprop(node, "interrupts", &ino, sizeof(ino)) == -1)
131 continue;
132 if (ino > 7)
133 panic("isa_init: XXX: ino too large");
134 isa_ino[ino] = ofw_isa_route_intr(bridge, node, &isa_iinfo,
135 ino);
136 }
137
133
138 for (nbr -= 1; nbr >= 0; nbr--) {
139 switch(ISAB_RANGE_SPACE(br + nbr)) {
134 isa_setup_children(dev, isab_node);
135
136 for (i = isab_nrange - 1; i >= 0; i--) {
137 switch(ISAB_RANGE_SPACE(&isab_ranges[i])) {
140 case ISAR_SPACE_IO:
141 /* This is probably always 0. */
138 case ISAR_SPACE_IO:
139 /* This is probably always 0. */
142 isa_io_base = ISAB_RANGE_PHYS(&br[nbr]);
143 isa_io_limit = br[nbr].size;
140 isa_io_base = ISAB_RANGE_PHYS(&isab_ranges[i]);
141 isa_io_limit = isab_ranges[i].size;
144 isa_io_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
145 SYS_RES_IOPORT, isa_io_base, &isa_io_bt);
146 break;
147 case ISAR_SPACE_MEM:
148 /* This is probably always 0. */
142 isa_io_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
143 SYS_RES_IOPORT, isa_io_base, &isa_io_bt);
144 break;
145 case ISAR_SPACE_MEM:
146 /* This is probably always 0. */
149 isa_mem_base = ISAB_RANGE_PHYS(&br[nbr]);
150 isa_mem_limit = br[nbr].size;
147 isa_mem_base = ISAB_RANGE_PHYS(&isab_ranges[i]);
148 isa_mem_limit = isab_ranges[i].size;
151 isa_mem_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
152 SYS_RES_MEMORY, isa_mem_base, &isa_mem_bt);
153 break;
154 }
155 }
149 isa_mem_hdl = OFW_PCI_GET_BUS_HANDLE(bridge,
150 SYS_RES_MEMORY, isa_mem_base, &isa_mem_bt);
151 break;
152 }
153 }
156 free(br, M_OFWPROP);
157}
158
154}
155
159static int
160isa_route_intr_res(device_t bus, u_long start, u_long end)
156struct ofw_isa_pnp_map {
157 const char *name;
158 uint32_t id;
159};
160
161static struct ofw_isa_pnp_map pnp_map[] = {
162 { "SUNW,lomh", 0x0000ae4e }, /* SUN0000 */
163 { "dma", 0x0002d041 }, /* PNP0200 */
164 { "floppy", 0x0007d041 }, /* PNP0700 */
165 { "rtc", 0x000bd041 }, /* PNP0B00 */
166 { "flashprom", 0x0100ae4e }, /* SUN0001 */
167 { "parallel", 0x0104d041 }, /* PNP0401 */
168 { "serial", 0x0105d041 }, /* PNP0501 */
169 { "kb_ps2", 0x0303d041 }, /* PNP0303 */
170 { "kdmouse", 0x030fd041 }, /* PNP0F03 */
171 { "power", 0x0c0cd041 }, /* PNP0C0C */
172 { NULL, 0x0 }
173};
174
175static void
176isa_setup_children(device_t dev, phandle_t parent)
161{
177{
162 int res;
178 struct isa_regs *regs;
179 device_t cdev;
180 u_int64_t end, start;
181 ofw_isa_intr_t *intrs, rintr;
182 phandle_t node;
183 uint32_t *drqs, *regidx;
184 int i, ndrq, nintr, nreg, nregidx, rtype;
185 char *name;
163
186
164 if (start != end) {
165 panic("isa_route_intr_res: allocation of interrupt range not "
166 "supported (0x%lx - 0x%lx)", start, end);
187 /*
188 * Loop through children and fake up PnP devices for them.
189 * Their resources are added as fully mapped and specified because
190 * adjusting the resources and the resource list entries respectively
191 * in isa_alloc_resource() causes trouble with drivers which use
192 * rman_get_start(), pass-through or allocate and release resources
193 * multiple times, etc. Adjusting the resources might be better off
194 * in a bus_activate_resource method but the common ISA code doesn't
195 * allow for an isa_activate_resource().
196 */
197 for (node = OF_child(parent); node != 0; node = OF_peer(node)) {
198 if ((OF_getprop_alloc(node, "name", 1, (void **)&name)) == -1)
199 continue;
200
201 /*
202 * Keyboard and mouse controllers hang off of the `8042'
203 * node but we have no real use for the `8042' itself.
204 */
205 if (strcmp(name, "8042") == 0) {
206 isa_setup_children(dev, node);
207 free(name, M_OFWPROP);
208 continue;
209 }
210
211 for (i = 0; pnp_map[i].name != NULL; i++)
212 if (strcmp(pnp_map[i].name, name) == 0)
213 break;
214 if (i == (sizeof(pnp_map) / sizeof(*pnp_map)) - 1) {
215 printf("isa_setup_children: no PnP map entry for node "
216 "0x%lx: %s\n", (unsigned long)node, name);
217 continue;
218 }
219
220 if ((cdev = BUS_ADD_CHILD(dev, ISA_ORDER_PNP, NULL, -1)) ==
221 NULL)
222 panic("isa_setup_children: BUS_ADD_CHILD failed");
223 isa_set_logicalid(cdev, pnp_map[i].id);
224 isa_set_vendorid(cdev, pnp_map[i].id);
225
226 nreg = OF_getprop_alloc(node, "reg", sizeof(*regs),
227 (void **)&regs);
228 for (i = 0; i < nreg; i++) {
229 start = ISA_REG_PHYS(&regs[i]);
230 end = start + regs[i].size - 1;
231 rtype = ofw_isa_range_map(isab_ranges, isab_nrange,
232 &start, &end, NULL);
233 bus_set_resource(cdev, rtype, i, start,
234 end - start + 1);
235 }
236 if (nreg == -1 && parent != isab_node) {
237 /*
238 * The "reg" property still might be an index into
239 * the set of registers of the parent device like
240 * with the nodes hanging off of the `8042' node.
241 */
242 nregidx = OF_getprop_alloc(node, "reg", sizeof(*regidx),
243 (void **)&regidx);
244 if (nregidx > 2)
245 panic("isa_setup_children: impossible number "
246 "of register indices");
247 if (nregidx != -1 && (nreg = OF_getprop_alloc(parent,
248 "reg", sizeof(*regs), (void **)&regs)) >= nregidx) {
249 for (i = 0; i < nregidx; i++) {
250 start = ISA_REG_PHYS(&regs[regidx[i]]);
251 end = start + regs[regidx[i]].size - 1;
252 rtype = ofw_isa_range_map(isab_ranges,
253 isab_nrange, &start, &end, NULL);
254 bus_set_resource(cdev, rtype, i, start,
255 end - start + 1);
256 }
257 }
258 if (regidx != NULL)
259 free(regidx, M_OFWPROP);
260 }
261 if (regs != NULL)
262 free(regs, M_OFWPROP);
263
264 nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs),
265 (void **)&intrs);
266 for (i = 0; i < nintr; i++) {
267 if (intrs[i] > 7)
268 panic("isa_setup_children: intr too large");
269 rintr = ofw_isa_route_intr(device_get_parent(dev), node,
270 &isa_iinfo, intrs[i]);
271 if (rintr == PCI_INVALID_IRQ)
272 panic("isa_setup_children: could not map ISA "
273 "interrupt %d", intrs[i]);
274 isa_ino[intrs[i]] = rintr;
275 bus_set_resource(cdev, SYS_RES_IRQ, i, rintr, 1);
276 }
277 if (intrs != NULL)
278 free(intrs, M_OFWPROP);
279
280 ndrq = OF_getprop_alloc(node, "dma-channel", sizeof(*drqs),
281 (void **)&drqs);
282 for (i = 0; i < ndrq; i++)
283 bus_set_resource(cdev, SYS_RES_DRQ, i, drqs[i], 1);
284 if (drqs != NULL)
285 free(drqs, M_OFWPROP);
286
287 /*
288 * Devices using DMA hang off of the `dma' node instead of
289 * directly from the ISA bridge node.
290 */
291 if (strcmp(name, "dma") == 0)
292 isa_setup_children(dev, node);
293
294 free(name, M_OFWPROP);
167 }
295 }
168 if (start > 7)
169 panic("isa_route_intr_res: start out of isa range");
170 res = isa_ino[start];
171 if (res == PCI_INVALID_IRQ)
172 device_printf(bus, "could not map interrupt %d\n", res);
173 return (res);
174}
175
176struct resource *
177isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
178 u_long start, u_long end, u_long count, u_int flags)
179{
180 /*
181 * Consider adding a resource definition.

--- 30 unchanged lines hidden (view full) ---

212 default:
213 return 0;
214 }
215 resource_list_add(rl, type, *rid, start, end, count);
216 }
217 }
218
219 /*
296}
297
298struct resource *
299isa_alloc_resource(device_t bus, device_t child, int type, int *rid,
300 u_long start, u_long end, u_long count, u_int flags)
301{
302 /*
303 * Consider adding a resource definition.

--- 30 unchanged lines hidden (view full) ---

334 default:
335 return 0;
336 }
337 resource_list_add(rl, type, *rid, start, end, count);
338 }
339 }
340
341 /*
220 * Add the base, change default allocations to be between base and
221 * limit, and reject allocations if a resource type is not enabled.
342 * Sanity check if the resource in the respective entry is fully
343 * mapped and specified and its type allocable. A driver could
344 * have added an out of range resource on its own.
222 */
345 */
223 base = limit = 0;
224 switch(type) {
225 case SYS_RES_MEMORY:
226 if (isa_mem_bt == NULL)
346 if (!passthrough) {
347 if ((rle = resource_list_find(rl, type, *rid)) == NULL)
227 return (NULL);
348 return (NULL);
228 base = isa_mem_base;
229 limit = base + isa_mem_limit;
230 break;
231 case SYS_RES_IOPORT:
232 if (isa_io_bt == NULL)
233 return (NULL);
234 base = isa_io_base;
235 limit = base + isa_io_limit;
236 break;
237 case SYS_RES_IRQ:
238 if (isdefault && passthrough)
239 panic("isa_alloc_resource: cannot pass through default "
240 "irq allocation");
241 if (!isdefault) {
242 start = end = isa_route_intr_res(bus, start, end);
243 if (start == PCI_INVALID_IRQ)
244 return (NULL);
245 }
246 break;
247 default:
248 panic("isa_alloc_resource: unsupported resource type %d", type);
249 }
250 if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
251 start = ulmin(start + base, limit);
252 end = ulmin(end + base, limit);
253 }
254
255 /*
256 * This inlines a modified resource_list_alloc(); this is needed
257 * because the resources need to have offsets added to them, which
258 * cannot be done beforehand without patching the resource list entries
259 * (which is ugly).
260 */
261 if (passthrough) {
262 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
263 type, rid, start, end, count, flags));
264 }
265
266 rle = resource_list_find(rl, type, *rid);
267 if (rle == NULL)
268 return (NULL); /* no resource of that type/rid */
269
270 if (rle->res != NULL)
271 panic("isa_alloc_resource: resource entry is busy");
272
273 if (isdefault) {
274 start = rle->start;
275 count = ulmax(count, rle->count);
276 end = ulmax(rle->end, start + count - 1);
349 base = limit = 0;
277 switch (type) {
278 case SYS_RES_MEMORY:
350 switch (type) {
351 case SYS_RES_MEMORY:
352 if (isa_mem_bt == NULL)
353 return (NULL);
354 base = isa_mem_base;
355 limit = base + isa_mem_limit;
356 break;
279 case SYS_RES_IOPORT:
357 case SYS_RES_IOPORT:
280 start += base;
281 end += base;
282 if (!INRANGE(start, base, limit) ||
283 !INRANGE(end, base, limit))
358 if (isa_io_bt == NULL)
284 return (NULL);
359 return (NULL);
360 base = isa_io_base;
361 limit = base + isa_io_limit;
285 break;
286 case SYS_RES_IRQ:
362 break;
363 case SYS_RES_IRQ:
287 start = end = isa_route_intr_res(bus, start, end);
288 if (start == PCI_INVALID_IRQ)
364 if (rle->start != rle->end || rle->start <= 7)
289 return (NULL);
290 break;
365 return (NULL);
366 break;
367 case SYS_RES_DRQ:
368 break;
369 default:
370 return (NULL);
291 }
371 }
372 if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
373 if (!INRANGE(rle->start, base, limit) ||
374 !INRANGE(rle->end, base, limit))
375 return (NULL);
376 }
292 }
293
377 }
378
294 rle->res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
295 type, rid, start, end, count, flags);
296
297 /*
298 * Record the new range.
299 */
300 if (rle->res != NULL) {
301 rle->start = rman_get_start(rle->res) - base;
302 rle->end = rman_get_end(rle->res) - base;
303 rle->count = count;
304 }
305
306 return (rle->res);
379 return (resource_list_alloc(rl, bus, child, type, rid, start, end,
380 count, flags));
307}
308
309int
310isa_release_resource(device_t bus, device_t child, int type, int rid,
311 struct resource *res)
312{
313 struct isa_device* idev = DEVTOISA(child);
314 struct resource_list *rl = &idev->id_resources;

--- 26 unchanged lines hidden ---
381}
382
383int
384isa_release_resource(device_t bus, device_t child, int type, int rid,
385 struct resource *res)
386{
387 struct isa_device* idev = DEVTOISA(child);
388 struct resource_list *rl = &idev->id_resources;

--- 26 unchanged lines hidden ---