1 /* $NetBSD: eisa_machdep.c,v 1.7 2007/10/17 19:52:57 garbled Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: eisa_machdep.c,v 1.7 2007/10/17 19:52:57 garbled Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/queue.h>
42 #include <machine/intr.h>
43 #include <machine/rpb.h>
45 #include <dev/eisa/eisareg.h>
46 #include <dev/eisa/eisavar.h>
48 #define EISA_SLOT_HEADER_SIZE 31
49 #define EISA_SLOT_INFO_OFFSET 20
51 #define EISA_FUNC_INFO_OFFSET 34
52 #define EISA_CONFIG_BLOCK_SIZE 320
54 #define ECUF_TYPE_STRING 0x01
55 #define ECUF_MEM_ENTRY 0x02
56 #define ECUF_IRQ_ENTRY 0x04
57 #define ECUF_DMA_ENTRY 0x08
58 #define ECUF_IO_ENTRY 0x10
59 #define ECUF_INIT_ENTRY 0x20
60 #define ECUF_DISABLED 0x80
62 #define ECUF_SELECTIONS_SIZE 26
63 #define ECUF_TYPE_STRING_SIZE 80
64 #define ECUF_MEM_ENTRY_SIZE 7
65 #define ECUF_IRQ_ENTRY_SIZE 2
66 #define ECUF_DMA_ENTRY_SIZE 2
67 #define ECUF_IO_ENTRY_SIZE 3
68 #define ECUF_INIT_ENTRY_SIZE 60
70 #define ECUF_MEM_ENTRY_CNT 9
71 #define ECUF_IRQ_ENTRY_CNT 7
72 #define ECUF_DMA_ENTRY_CNT 4
73 #define ECUF_IO_ENTRY_CNT 20
78 * EISA configuration space, as set up by the ECU, may be sparse.
80 bus_size_t eisa_config_stride
;
81 paddr_t eisa_config_addr
; /* defaults to 0 */
82 paddr_t eisa_config_header_addr
;
85 SIMPLEQ_ENTRY(ecu_mem
) ecum_list
;
86 struct eisa_cfg_mem ecum_mem
;
90 SIMPLEQ_ENTRY(ecu_irq
) ecui_list
;
91 struct eisa_cfg_irq ecui_irq
;
95 SIMPLEQ_ENTRY(ecu_dma
) ecud_list
;
96 struct eisa_cfg_dma ecud_dma
;
100 SIMPLEQ_ENTRY(ecu_io
) ecuio_list
;
101 struct eisa_cfg_io ecuio_io
;
105 SIMPLEQ_ENTRY(ecu_func
) ecuf_list
;
108 u_int16_t ecuf_slot_info
;
109 u_int16_t ecuf_cfg_ext
;
110 u_int8_t ecuf_selections
[ECUF_SELECTIONS_SIZE
];
111 u_int8_t ecuf_func_info
;
112 u_int8_t ecuf_type_string
[ECUF_TYPE_STRING_SIZE
];
113 u_int8_t ecuf_init
[ECUF_INIT_ENTRY_SIZE
];
114 SIMPLEQ_HEAD(, ecu_mem
) ecuf_mem
;
115 SIMPLEQ_HEAD(, ecu_irq
) ecuf_irq
;
116 SIMPLEQ_HEAD(, ecu_dma
) ecuf_dma
;
117 SIMPLEQ_HEAD(, ecu_io
) ecuf_io
;
121 SIMPLEQ_ENTRY(ecu_data
) ecud_list
;
123 u_int8_t ecud_eisaid
[EISA_IDSTRINGLEN
];
124 u_int32_t ecud_offset
;
126 /* General slot info. */
127 u_int8_t ecud_slot_info
;
128 u_int16_t ecud_ecu_major_rev
;
129 u_int16_t ecud_ecu_minor_rev
;
130 u_int16_t ecud_cksum
;
131 u_int16_t ecud_ndevfuncs
;
132 u_int8_t ecud_funcinfo
;
133 u_int32_t ecud_comp_id
;
136 SIMPLEQ_HEAD(, ecu_func
) ecud_funcs
;
139 SIMPLEQ_HEAD(, ecu_data
) ecu_data_list
=
140 SIMPLEQ_HEAD_INITIALIZER(ecu_data_list
);
143 ecuf_init(struct ecu_func
*ecuf
)
146 memset(ecuf
, 0, sizeof(*ecuf
));
147 SIMPLEQ_INIT(&ecuf
->ecuf_mem
);
148 SIMPLEQ_INIT(&ecuf
->ecuf_irq
);
149 SIMPLEQ_INIT(&ecuf
->ecuf_dma
);
150 SIMPLEQ_INIT(&ecuf
->ecuf_io
);
154 eisa_parse_mem(struct ecu_func
*ecuf
, u_int8_t
*dp
)
156 struct ecu_mem
*ecum
;
159 for (i
= 0; i
< ECUF_MEM_ENTRY_CNT
; i
++) {
160 ecum
= malloc(sizeof(*ecum
), M_DEVBUF
, M_ZERO
|M_WAITOK
);
162 panic("%s: can't allocate memory for ecum", __func__
);
164 ecum
->ecum_mem
.ecm_isram
= dp
[0] & 0x1;
165 ecum
->ecum_mem
.ecm_unitsize
= dp
[1] & 0x3;
166 ecum
->ecum_mem
.ecm_decode
= (dp
[1] >> 2) & 0x3;
167 ecum
->ecum_mem
.ecm_addr
=
168 (dp
[2] | (dp
[3] << 8) | (dp
[4] << 16)) << 8;
169 ecum
->ecum_mem
.ecm_size
= (dp
[5] | (dp
[6] << 8)) << 10;
170 if (ecum
->ecum_mem
.ecm_size
== 0)
171 ecum
->ecum_mem
.ecm_size
= (1 << 26);
172 SIMPLEQ_INSERT_TAIL(&ecuf
->ecuf_mem
, ecum
, ecum_list
);
175 printf("MEM 0x%lx 0x%lx %d %d %d\n",
176 ecum
->ecum_mem
.ecm_addr
, ecum
->ecum_mem
.ecm_size
,
177 ecum
->ecum_mem
.ecm_isram
, ecum
->ecum_mem
.ecm_unitsize
,
178 ecum
->ecum_mem
.ecm_decode
);
181 if ((dp
[0] & 0x80) == 0)
183 dp
+= ECUF_MEM_ENTRY_SIZE
;
188 eisa_parse_irq(struct ecu_func
*ecuf
, u_int8_t
*dp
)
190 struct ecu_irq
*ecui
;
193 for (i
= 0; i
< ECUF_IRQ_ENTRY_CNT
; i
++) {
194 ecui
= malloc(sizeof(*ecui
), M_DEVBUF
, M_ZERO
|M_WAITOK
);
196 panic("%s: can't allocate memory for ecui", __func__
);
198 ecui
->ecui_irq
.eci_irq
= dp
[0] & 0xf;
199 ecui
->ecui_irq
.eci_ist
= (dp
[0] & 0x20) ? IST_LEVEL
: IST_EDGE
;
200 ecui
->ecui_irq
.eci_shared
= (dp
[0] & 0x40) ? 1 : 0;
201 SIMPLEQ_INSERT_TAIL(&ecuf
->ecuf_irq
, ecui
, ecui_list
);
204 printf("IRQ %d %s%s\n", ecui
->ecui_irq
.eci_irq
,
205 ecui
->ecui_irq
.eci_ist
== IST_LEVEL
? "level" : "edge",
206 ecui
->ecui_irq
.eci_shared
? " shared" : "");
209 if ((dp
[0] & 0x80) == 0)
211 dp
+= ECUF_IRQ_ENTRY_SIZE
;
216 eisa_parse_dma(struct ecu_func
*ecuf
, u_int8_t
*dp
)
218 struct ecu_dma
*ecud
;
221 for (i
= 0; i
< ECUF_DMA_ENTRY_CNT
; i
++) {
222 ecud
= malloc(sizeof(*ecud
), M_DEVBUF
, M_ZERO
|M_WAITOK
);
224 panic("%s: can't allocate memory for ecud", __func__
);
226 ecud
->ecud_dma
.ecd_drq
= dp
[0] & 0x7;
227 ecud
->ecud_dma
.ecd_shared
= dp
[0] & 0x40;
228 ecud
->ecud_dma
.ecd_size
= (dp
[1] >> 2) & 0x3;
229 ecud
->ecud_dma
.ecd_timing
= (dp
[1] >> 4) & 0x3;
230 SIMPLEQ_INSERT_TAIL(&ecuf
->ecuf_dma
, ecud
, ecud_list
);
233 printf("DRQ %d%s %d %d\n", ecud
->ecud_dma
.ecd_drq
,
234 ecud
->ecud_dma
.ecd_shared
? " shared" : "",
235 ecud
->ecud_dma
.ecd_size
, ecud
->ecud_dma
.ecd_timing
);
238 if ((dp
[0] & 0x80) == 0)
240 dp
+= ECUF_DMA_ENTRY_SIZE
;
245 eisa_parse_io(struct ecu_func
*ecuf
, u_int8_t
*dp
)
247 struct ecu_io
*ecuio
;
250 for (i
= 0; i
< ECUF_IO_ENTRY_CNT
; i
++) {
251 ecuio
= malloc(sizeof(*ecuio
), M_DEVBUF
, M_ZERO
|M_WAITOK
);
253 panic("%s: can't allocate memory for ecuio", __func__
);
255 ecuio
->ecuio_io
.ecio_addr
= dp
[1] | (dp
[2] << 8);
256 ecuio
->ecuio_io
.ecio_size
= (dp
[0] & 0x1f) + 1;
257 ecuio
->ecuio_io
.ecio_shared
= (dp
[0] & 0x40) ? 1 : 0;
260 printf("IO 0x%lx 0x%lx%s\n", ecuio
->ecuio_io
.ecio_addr
,
261 ecuio
->ecuio_io
.ecio_size
,
262 ecuio
->ecuio_io
.ecio_shared
? " shared" : "");
265 if ((dp
[0] & 0x80) == 0)
267 dp
+= ECUF_IO_ENTRY_SIZE
;
272 eisa_read_config_bytes(paddr_t addr
, void *buf
, size_t count
)
274 const u_int8_t
*src
= (const u_int8_t
*)ALPHA_PHYS_TO_K0SEG(addr
);
277 for (; count
!= 0; count
--) {
279 src
+= eisa_config_stride
;
284 eisa_read_config_word(paddr_t addr
, u_int32_t
*valp
)
286 const u_int8_t
*src
= (const u_int8_t
*)ALPHA_PHYS_TO_K0SEG(addr
);
290 for (i
= 0; i
< sizeof(val
); i
++) {
291 val
|= (uint32_t)*src
<< (i
* 8);
292 src
+= eisa_config_stride
;
299 eisa_uncompress(void *cbufp
, void *ucbufp
, size_t count
)
301 const u_int8_t
*cbuf
= cbufp
;
302 u_int8_t
*ucbuf
= ucbufp
;
309 } else if (*cbuf
== '\0') {
316 return ((size_t)cbuf
- (size_t)cbufp
);
320 eisa_init(eisa_chipset_tag_t ec
)
322 struct ecu_data
*ecud
;
325 u_int8_t eisaid
[EISA_IDSTRINGLEN
];
326 u_int8_t
*cdata
, *data
;
328 struct ecu_func
*ecuf
;
332 * Locate EISA configuration space.
334 if (hwrpb
->rpb_condat_off
== 0UL ||
335 (hwrpb
->rpb_condat_off
>> 63) != 0) {
336 printf(": WARNING: no EISA configuration space");
340 if (eisa_config_header_addr
) {
342 panic("eisa_init: EISA config space already initialized");
345 eisa_config_header_addr
= hwrpb
->rpb_condat_off
;
346 if (eisa_config_stride
== 0)
347 eisa_config_stride
= 1;
350 printf("\nEISA config header at 0x%lx\n", eisa_config_header_addr
);
351 printf("EISA config at 0x%lx\n", eisa_config_addr
);
352 printf("EISA config stride: %ld\n", eisa_config_stride
);
356 * Read the slot headers, and allocate config structures for
359 for (cfgaddr
= eisa_config_header_addr
, i
= 0;
360 i
< eisa_maxslots(ec
); i
++) {
361 eisa_read_config_bytes(cfgaddr
, eisaid
, sizeof(eisaid
));
362 eisaid
[EISA_IDSTRINGLEN
- 1] = '\0'; /* sanity */
363 cfgaddr
+= sizeof(eisaid
) * eisa_config_stride
;
364 eisa_read_config_word(cfgaddr
, &offset
);
365 cfgaddr
+= sizeof(offset
) * eisa_config_stride
;
367 if (offset
!= 0 && offset
!= 0xffffffff) {
369 printf("SLOT %d: offset 0x%08x eisaid %s\n",
372 ecud
= malloc(sizeof(*ecud
), M_DEVBUF
, M_ZERO
|M_WAITOK
);
374 panic("%s: can't allocate memory for ecud",
377 SIMPLEQ_INIT(&ecud
->ecud_funcs
);
380 memcpy(ecud
->ecud_eisaid
, eisaid
, sizeof(eisaid
));
381 ecud
->ecud_offset
= offset
;
382 SIMPLEQ_INSERT_TAIL(&ecu_data_list
, ecud
, ecud_list
);
387 * Now traverse the valid slots and read the info.
390 cdata
= malloc(CBUFSIZE
, M_TEMP
, M_ZERO
|M_WAITOK
);
392 panic("%s: can't allocate memory for cdata", __func__
);
393 data
= malloc(CBUFSIZE
, M_TEMP
, M_ZERO
|M_WAITOK
);
395 panic("%s: can't allocate memory for data", __func__
);
397 SIMPLEQ_FOREACH(ecud
, &ecu_data_list
, ecud_list
) {
398 cfgaddr
= eisa_config_addr
+ ecud
->ecud_offset
;
400 printf("Checking SLOT %d\n", ecud
->ecud_slot
);
401 printf("Reading config bytes at 0x%lx to cdata[0]\n", cfgaddr
);
403 eisa_read_config_bytes(cfgaddr
, &cdata
[0], 1);
404 cfgaddr
+= eisa_config_stride
;
406 for (i
= 1; i
< CBUFSIZE
; cfgaddr
+= eisa_config_stride
, i
++) {
408 printf("Reading config bytes at 0x%lx to cdata[%d]\n",
411 eisa_read_config_bytes(cfgaddr
, &cdata
[i
], 1);
412 if (cdata
[i
- 1] == 0 && cdata
[i
] == 0)
416 /* assume this compressed data invalid */
418 printf("SLOT %d has invalid config\n", ecud
->ecud_slot
);
423 i
++; /* index -> length */
426 printf("SLOT %d compressed data length %d:",
431 for (j
= 0; j
< i
; j
++) {
434 printf("0x%02x ", cdata
[j
]);
443 /* Uncompress the slot header. */
444 cdp
+= eisa_uncompress(cdp
, dp
, EISA_SLOT_HEADER_SIZE
);
446 printf("SLOT %d uncompressed header data:",
451 for (j
= 0; j
< EISA_SLOT_HEADER_SIZE
; j
++) {
454 printf("0x%02x ", dp
[j
]);
460 dp
= &data
[EISA_SLOT_INFO_OFFSET
];
461 ecud
->ecud_slot_info
= *dp
++;
462 ecud
->ecud_ecu_major_rev
= *dp
++;
463 ecud
->ecud_ecu_minor_rev
= *dp
++;
464 memcpy(&ecud
->ecud_cksum
, dp
, sizeof(ecud
->ecud_cksum
));
465 dp
+= sizeof(ecud
->ecud_cksum
);
466 ecud
->ecud_ndevfuncs
= *dp
++;
467 ecud
->ecud_funcinfo
= *dp
++;
468 memcpy(&ecud
->ecud_comp_id
, dp
, sizeof(ecud
->ecud_comp_id
));
469 dp
+= sizeof(ecud
->ecud_comp_id
);
472 printf("SLOT %d: ndevfuncs %d\n", ecud
->ecud_slot
,
473 ecud
->ecud_ndevfuncs
);
476 for (func
= 0; func
< ecud
->ecud_ndevfuncs
; func
++) {
478 cdp
+= eisa_uncompress(cdp
, dp
, EISA_CONFIG_BLOCK_SIZE
);
480 printf("SLOT %d:%d uncompressed data:",
481 ecud
->ecud_slot
, func
);
485 for (j
= 0; i
< EISA_CONFIG_BLOCK_SIZE
; j
++) {
488 printf("0x%02x ", dp
[j
]);
494 /* Skip disabled functions. */
495 if (dp
[EISA_FUNC_INFO_OFFSET
] & ECUF_DISABLED
) {
497 printf("SLOT %d:%d disabled\n",
498 ecud
->ecud_slot
, func
);
503 ecuf
= malloc(sizeof(*ecuf
), M_DEVBUF
, M_WAITOK
);
505 panic("%s: can't allocate memory for ecuf",
508 ecuf
->ecuf_funcno
= func
;
509 SIMPLEQ_INSERT_TAIL(&ecud
->ecud_funcs
, ecuf
,
512 memcpy(&ecuf
->ecuf_id
, dp
, sizeof(ecuf
->ecuf_id
));
513 dp
+= sizeof(ecuf
->ecuf_id
);
515 memcpy(&ecuf
->ecuf_slot_info
, dp
,
516 sizeof(ecuf
->ecuf_slot_info
));
517 dp
+= sizeof(ecuf
->ecuf_slot_info
);
519 memcpy(&ecuf
->ecuf_cfg_ext
, dp
,
520 sizeof(ecuf
->ecuf_cfg_ext
));
521 dp
+= sizeof(ecuf
->ecuf_cfg_ext
);
523 memcpy(&ecuf
->ecuf_selections
, dp
,
524 sizeof(ecuf
->ecuf_selections
));
525 dp
+= sizeof(ecuf
->ecuf_selections
);
527 memcpy(&ecuf
->ecuf_func_info
, dp
,
528 sizeof(ecuf
->ecuf_func_info
));
529 dp
+= sizeof(ecuf
->ecuf_func_info
);
531 if (ecuf
->ecuf_func_info
& ECUF_TYPE_STRING
)
532 memcpy(ecuf
->ecuf_type_string
, dp
,
533 sizeof(ecuf
->ecuf_type_string
));
534 dp
+= sizeof(ecuf
->ecuf_type_string
);
536 if (ecuf
->ecuf_func_info
& ECUF_MEM_ENTRY
)
537 eisa_parse_mem(ecuf
, dp
);
538 dp
+= ECUF_MEM_ENTRY_SIZE
* ECUF_MEM_ENTRY_CNT
;
540 if (ecuf
->ecuf_func_info
& ECUF_IRQ_ENTRY
)
541 eisa_parse_irq(ecuf
, dp
);
542 dp
+= ECUF_IRQ_ENTRY_SIZE
* ECUF_IRQ_ENTRY_CNT
;
544 if (ecuf
->ecuf_func_info
& ECUF_DMA_ENTRY
)
545 eisa_parse_dma(ecuf
, dp
);
546 dp
+= ECUF_DMA_ENTRY_SIZE
* ECUF_DMA_ENTRY_CNT
;
548 if (ecuf
->ecuf_func_info
& ECUF_IO_ENTRY
)
549 eisa_parse_io(ecuf
, dp
);
550 dp
+= ECUF_IO_ENTRY_SIZE
* ECUF_IO_ENTRY_CNT
;
552 if (ecuf
->ecuf_func_info
& ECUF_INIT_ENTRY
)
553 memcpy(ecuf
->ecuf_init
, dp
,
554 sizeof(ecuf
->ecuf_init
));
555 dp
+= sizeof(ecuf
->ecuf_init
);
563 static struct ecu_data
*
564 eisa_lookup_data(int slot
)
566 struct ecu_data
*ecud
;
568 SIMPLEQ_FOREACH(ecud
, &ecu_data_list
, ecud_list
) {
569 if (ecud
->ecud_slot
== slot
)
575 static struct ecu_func
*
576 eisa_lookup_func(int slot
, int func
)
578 struct ecu_data
*ecud
;
579 struct ecu_func
*ecuf
;
581 ecud
= eisa_lookup_data(slot
);
585 SIMPLEQ_FOREACH(ecuf
, &ecud
->ecud_funcs
, ecuf_list
) {
586 if (ecuf
->ecuf_funcno
== func
)
593 eisa_conf_read_mem(eisa_chipset_tag_t ec
, int slot
, int func
, int entry
,
594 struct eisa_cfg_mem
*dp
)
596 struct ecu_func
*ecuf
;
597 struct ecu_mem
*ecum
;
599 ecuf
= eisa_lookup_func(slot
, func
);
603 SIMPLEQ_FOREACH(ecum
, &ecuf
->ecuf_mem
, ecum_list
) {
610 *dp
= ecum
->ecum_mem
;
615 eisa_conf_read_irq(eisa_chipset_tag_t ec
, int slot
, int func
, int entry
,
616 struct eisa_cfg_irq
*dp
)
618 struct ecu_func
*ecuf
;
619 struct ecu_irq
*ecui
;
621 ecuf
= eisa_lookup_func(slot
, func
);
625 SIMPLEQ_FOREACH(ecui
, &ecuf
->ecuf_irq
, ecui_list
) {
632 *dp
= ecui
->ecui_irq
;
637 eisa_conf_read_dma(eisa_chipset_tag_t ec
, int slot
, int func
, int entry
,
638 struct eisa_cfg_dma
*dp
)
640 struct ecu_func
*ecuf
;
641 struct ecu_dma
*ecud
;
643 ecuf
= eisa_lookup_func(slot
, func
);
647 SIMPLEQ_FOREACH(ecud
, &ecuf
->ecuf_dma
, ecud_list
) {
654 *dp
= ecud
->ecud_dma
;
659 eisa_conf_read_io(eisa_chipset_tag_t ec
, int slot
, int func
, int entry
,
660 struct eisa_cfg_io
*dp
)
662 struct ecu_func
*ecuf
;
663 struct ecu_io
*ecuio
;
665 ecuf
= eisa_lookup_func(slot
, func
);
669 SIMPLEQ_FOREACH(ecuio
, &ecuf
->ecuf_io
, ecuio_list
) {
676 *dp
= ecuio
->ecuio_io
;