xref: /netbsd-src/sys/arch/alpha/eisa/eisa_machdep.c (revision 0ff686a3a684360c3140adda0e24043c8ae24569)
1 /* $NetBSD: eisa_machdep.c,v 1.14 2021/09/25 20:16:17 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  *
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.
30  */
31 
32 #include <sys/cdefs.h>
33 
34 __KERNEL_RCSID(0, "$NetBSD: eisa_machdep.c,v 1.14 2021/09/25 20:16:17 thorpej Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/device.h>
39 #include <sys/kmem.h>
40 #include <sys/queue.h>
41 
42 #include <machine/intr.h>
43 #include <machine/rpb.h>
44 
45 #include <dev/eisa/eisareg.h>
46 #include <dev/eisa/eisavar.h>
47 
48 void
eisa_attach_hook(device_t parent,device_t self,struct eisabus_attach_args * eba)49 eisa_attach_hook(device_t parent, device_t self,
50     struct eisabus_attach_args *eba)
51 {
52 	eba->eba_ec->ec_attach_hook(parent, self, eba);
53 }
54 
55 int
eisa_maxslots(eisa_chipset_tag_t ec)56 eisa_maxslots(eisa_chipset_tag_t ec)
57 {
58 	return ec->ec_maxslots(ec->ec_v);
59 }
60 
61 int
eisa_intr_map(eisa_chipset_tag_t ec,u_int irq,eisa_intr_handle_t * ihp)62 eisa_intr_map(eisa_chipset_tag_t ec, u_int irq, eisa_intr_handle_t *ihp)
63 {
64 	return ec->ec_intr_map(ec->ec_v, irq, ihp);
65 }
66 
67 const char *
eisa_intr_string(eisa_chipset_tag_t ec,eisa_intr_handle_t ih,char * buf,size_t len)68 eisa_intr_string(eisa_chipset_tag_t ec, eisa_intr_handle_t ih, char *buf,
69     size_t len)
70 {
71 	return ec->ec_intr_string(ec->ec_v, ih, buf, len);
72 }
73 
74 const struct evcnt *
eisa_intr_evcnt(eisa_chipset_tag_t ec,eisa_intr_handle_t ih)75 eisa_intr_evcnt(eisa_chipset_tag_t ec, eisa_intr_handle_t ih)
76 {
77 	return ec->ec_intr_evcnt(ec->ec_v, ih);
78 }
79 
80 void *
eisa_intr_establish(eisa_chipset_tag_t ec,eisa_intr_handle_t ih,int type,int level,int (* func)(void *),void * arg)81 eisa_intr_establish(eisa_chipset_tag_t ec, eisa_intr_handle_t ih,
82     int type, int level, int (*func)(void *), void *arg)
83 {
84 	return ec->ec_intr_establish(ec->ec_v, ih, type, level, func, arg);
85 }
86 
87 void
eisa_intr_disestablish(eisa_chipset_tag_t ec,void * cookie)88 eisa_intr_disestablish(eisa_chipset_tag_t ec, void *cookie)
89 {
90 	return ec->ec_intr_disestablish(ec->ec_v, cookie);
91 }
92 
93 #define	EISA_SLOT_HEADER_SIZE	31
94 #define	EISA_SLOT_INFO_OFFSET	20
95 
96 #define	EISA_FUNC_INFO_OFFSET	34
97 #define	EISA_CONFIG_BLOCK_SIZE	320
98 
99 #define	ECUF_TYPE_STRING	0x01
100 #define	ECUF_MEM_ENTRY		0x02
101 #define	ECUF_IRQ_ENTRY		0x04
102 #define	ECUF_DMA_ENTRY		0x08
103 #define	ECUF_IO_ENTRY		0x10
104 #define	ECUF_INIT_ENTRY		0x20
105 #define	ECUF_DISABLED		0x80
106 
107 #define	ECUF_SELECTIONS_SIZE	26
108 #define	ECUF_TYPE_STRING_SIZE	80
109 #define	ECUF_MEM_ENTRY_SIZE	7
110 #define	ECUF_IRQ_ENTRY_SIZE	2
111 #define	ECUF_DMA_ENTRY_SIZE	2
112 #define	ECUF_IO_ENTRY_SIZE	3
113 #define	ECUF_INIT_ENTRY_SIZE	60
114 
115 #define	ECUF_MEM_ENTRY_CNT	9
116 #define	ECUF_IRQ_ENTRY_CNT	7
117 #define	ECUF_DMA_ENTRY_CNT	4
118 #define	ECUF_IO_ENTRY_CNT	20
119 
120 #define	CBUFSIZE		512
121 
122 /*
123  * EISA configuration space, as set up by the ECU, may be sparse.
124  */
125 bus_size_t eisa_config_stride;
126 paddr_t eisa_config_addr;		/* defaults to 0 */
127 paddr_t eisa_config_header_addr;
128 
129 struct ecu_mem {
130 	SIMPLEQ_ENTRY(ecu_mem) ecum_list;
131 	struct eisa_cfg_mem ecum_mem;
132 };
133 
134 struct ecu_irq {
135 	SIMPLEQ_ENTRY(ecu_irq) ecui_list;
136 	struct eisa_cfg_irq ecui_irq;
137 };
138 
139 struct ecu_dma {
140 	SIMPLEQ_ENTRY(ecu_dma) ecud_list;
141 	struct eisa_cfg_dma ecud_dma;
142 };
143 
144 struct ecu_io {
145 	SIMPLEQ_ENTRY(ecu_io) ecuio_list;
146 	struct eisa_cfg_io ecuio_io;
147 };
148 
149 struct ecu_func {
150 	SIMPLEQ_ENTRY(ecu_func) ecuf_list;
151 	int ecuf_funcno;
152 	uint32_t ecuf_id;
153 	uint16_t ecuf_slot_info;
154 	uint16_t ecuf_cfg_ext;
155 	uint8_t ecuf_selections[ECUF_SELECTIONS_SIZE];
156 	uint8_t ecuf_func_info;
157 	uint8_t ecuf_type_string[ECUF_TYPE_STRING_SIZE];
158 	uint8_t ecuf_init[ECUF_INIT_ENTRY_SIZE];
159 	SIMPLEQ_HEAD(, ecu_mem) ecuf_mem;
160 	SIMPLEQ_HEAD(, ecu_irq) ecuf_irq;
161 	SIMPLEQ_HEAD(, ecu_dma) ecuf_dma;
162 	SIMPLEQ_HEAD(, ecu_io) ecuf_io;
163 };
164 
165 struct ecu_data {
166 	SIMPLEQ_ENTRY(ecu_data) ecud_list;
167 	int ecud_slot;
168 	uint8_t ecud_eisaid[EISA_IDSTRINGLEN];
169 	uint32_t ecud_offset;
170 
171 	/* General slot info. */
172 	uint8_t ecud_slot_info;
173 	uint16_t ecud_ecu_major_rev;
174 	uint16_t ecud_ecu_minor_rev;
175 	uint16_t ecud_cksum;
176 	uint16_t ecud_ndevfuncs;
177 	uint8_t ecud_funcinfo;
178 	uint32_t ecud_comp_id;
179 
180 	/* The functions */
181 	SIMPLEQ_HEAD(, ecu_func) ecud_funcs;
182 };
183 
184 SIMPLEQ_HEAD(, ecu_data) ecu_data_list =
185     SIMPLEQ_HEAD_INITIALIZER(ecu_data_list);
186 
187 static void
ecuf_init(struct ecu_func * ecuf)188 ecuf_init(struct ecu_func *ecuf)
189 {
190 
191 	memset(ecuf, 0, sizeof(*ecuf));
192 	SIMPLEQ_INIT(&ecuf->ecuf_mem);
193 	SIMPLEQ_INIT(&ecuf->ecuf_irq);
194 	SIMPLEQ_INIT(&ecuf->ecuf_dma);
195 	SIMPLEQ_INIT(&ecuf->ecuf_io);
196 }
197 
198 static void
eisa_parse_mem(struct ecu_func * ecuf,uint8_t * dp)199 eisa_parse_mem(struct ecu_func *ecuf, uint8_t *dp)
200 {
201 	struct ecu_mem *ecum;
202 	int i;
203 
204 	for (i = 0; i < ECUF_MEM_ENTRY_CNT; i++) {
205 		ecum = kmem_zalloc(sizeof(*ecum), KM_SLEEP);
206 		ecum->ecum_mem.ecm_isram = dp[0] & 0x1;
207 		ecum->ecum_mem.ecm_unitsize = dp[1] & 0x3;
208 		ecum->ecum_mem.ecm_decode = (dp[1] >> 2) & 0x3;
209 		ecum->ecum_mem.ecm_addr =
210 		    (dp[2] | (dp[3] << 8) | (dp[4] << 16)) << 8;
211 		ecum->ecum_mem.ecm_size = (dp[5] | (dp[6] << 8)) << 10;
212 		if (ecum->ecum_mem.ecm_size == 0)
213 			ecum->ecum_mem.ecm_size = (1 << 26);
214 		SIMPLEQ_INSERT_TAIL(&ecuf->ecuf_mem, ecum, ecum_list);
215 
216 #ifdef EISA_DEBUG
217 		printf("MEM 0x%lx 0x%lx %d %d %d\n",
218 		    ecum->ecum_mem.ecm_addr, ecum->ecum_mem.ecm_size,
219 		    ecum->ecum_mem.ecm_isram, ecum->ecum_mem.ecm_unitsize,
220 		    ecum->ecum_mem.ecm_decode);
221 #endif
222 
223 		if ((dp[0] & 0x80) == 0)
224 			break;
225 		dp += ECUF_MEM_ENTRY_SIZE;
226 	}
227 }
228 
229 static void
eisa_parse_irq(struct ecu_func * ecuf,uint8_t * dp)230 eisa_parse_irq(struct ecu_func *ecuf, uint8_t *dp)
231 {
232 	struct ecu_irq *ecui;
233 	int i;
234 
235 	for (i = 0; i < ECUF_IRQ_ENTRY_CNT; i++) {
236 		ecui = kmem_zalloc(sizeof(*ecui), KM_SLEEP);
237 		ecui->ecui_irq.eci_irq = dp[0] & 0xf;
238 		ecui->ecui_irq.eci_ist = (dp[0] & 0x20) ? IST_LEVEL : IST_EDGE;
239 		ecui->ecui_irq.eci_shared = (dp[0] & 0x40) ? 1 : 0;
240 		SIMPLEQ_INSERT_TAIL(&ecuf->ecuf_irq, ecui, ecui_list);
241 
242 #ifdef EISA_DEBUG
243 		printf("IRQ %d %s%s\n", ecui->ecui_irq.eci_irq,
244 		    ecui->ecui_irq.eci_ist == IST_LEVEL ? "level" : "edge",
245 		    ecui->ecui_irq.eci_shared ? " shared" : "");
246 #endif
247 
248 		if ((dp[0] & 0x80) == 0)
249 			break;
250 		dp += ECUF_IRQ_ENTRY_SIZE;
251 	}
252 }
253 
254 static void
eisa_parse_dma(struct ecu_func * ecuf,uint8_t * dp)255 eisa_parse_dma(struct ecu_func *ecuf, uint8_t *dp)
256 {
257 	struct ecu_dma *ecud;
258 	int i;
259 
260 	for (i = 0; i < ECUF_DMA_ENTRY_CNT; i++) {
261 		ecud = kmem_zalloc(sizeof(*ecud), KM_SLEEP);
262 		ecud->ecud_dma.ecd_drq = dp[0] & 0x7;
263 		ecud->ecud_dma.ecd_shared = dp[0] & 0x40;
264 		ecud->ecud_dma.ecd_size = (dp[1] >> 2) & 0x3;
265 		ecud->ecud_dma.ecd_timing = (dp[1] >> 4) & 0x3;
266 		SIMPLEQ_INSERT_TAIL(&ecuf->ecuf_dma, ecud, ecud_list);
267 
268 #ifdef EISA_DEBUG
269 		printf("DRQ %d%s %d %d\n", ecud->ecud_dma.ecd_drq,
270 		    ecud->ecud_dma.ecd_shared ? " shared" : "",
271 		    ecud->ecud_dma.ecd_size, ecud->ecud_dma.ecd_timing);
272 #endif
273 
274 		if ((dp[0] & 0x80) == 0)
275 			break;
276 		dp += ECUF_DMA_ENTRY_SIZE;
277 	}
278 }
279 
280 static void
eisa_parse_io(struct ecu_func * ecuf,uint8_t * dp)281 eisa_parse_io(struct ecu_func *ecuf, uint8_t *dp)
282 {
283 	struct ecu_io *ecuio;
284 	int i;
285 
286 	for (i = 0; i < ECUF_IO_ENTRY_CNT; i++) {
287 		ecuio = kmem_zalloc(sizeof(*ecuio), KM_SLEEP);
288 		ecuio->ecuio_io.ecio_addr = dp[1] | (dp[2] << 8);
289 		ecuio->ecuio_io.ecio_size = (dp[0] & 0x1f) + 1;
290 		ecuio->ecuio_io.ecio_shared = (dp[0] & 0x40) ? 1 : 0;
291 		SIMPLEQ_INSERT_TAIL(&ecuf->ecuf_io, ecuio, ecuio_list);
292 
293 #ifdef EISA_DEBUG
294 		printf("IO 0x%lx 0x%lx%s\n", ecuio->ecuio_io.ecio_addr,
295 		    ecuio->ecuio_io.ecio_size,
296 		    ecuio->ecuio_io.ecio_shared ? " shared" : "");
297 #endif
298 
299 		if ((dp[0] & 0x80) == 0)
300 			break;
301 		dp += ECUF_IO_ENTRY_SIZE;
302 	}
303 }
304 
305 static void
eisa_read_config_bytes(paddr_t addr,void * buf,size_t count)306 eisa_read_config_bytes(paddr_t addr, void *buf, size_t count)
307 {
308 	const uint8_t *src = (const uint8_t *)ALPHA_PHYS_TO_K0SEG(addr);
309 	uint8_t *dst = buf;
310 
311 	for (; count != 0; count--) {
312 		*dst++ = *src;
313 		src += eisa_config_stride;
314 	}
315 }
316 
317 static void
eisa_read_config_word(paddr_t addr,uint32_t * valp)318 eisa_read_config_word(paddr_t addr, uint32_t *valp)
319 {
320 	const uint8_t *src = (const uint8_t *)ALPHA_PHYS_TO_K0SEG(addr);
321 	uint32_t val = 0;
322 	int i;
323 
324 	for (i = 0; i < sizeof(val); i++) {
325 		val |= (uint32_t)*src << (i * 8);
326 		src += eisa_config_stride;
327 	}
328 
329 	*valp = val;
330 }
331 
332 static size_t
eisa_uncompress(void * cbufp,void * ucbufp,size_t count)333 eisa_uncompress(void *cbufp, void *ucbufp, size_t count)
334 {
335 	const uint8_t *cbuf = cbufp;
336 	uint8_t *ucbuf = ucbufp;
337 	u_int zeros = 0;
338 
339 	while (count--) {
340 		if (zeros) {
341 			zeros--;
342 			*ucbuf++ = '\0';
343 		} else if (*cbuf == '\0') {
344 			*ucbuf++ = *cbuf++;
345 			zeros = *cbuf++ - 1;
346 		} else
347 			*ucbuf++ = *cbuf++;
348 	}
349 
350 	return ((size_t)cbuf - (size_t)cbufp);
351 }
352 
353 void
eisa_init(eisa_chipset_tag_t ec)354 eisa_init(eisa_chipset_tag_t ec)
355 {
356 	struct ecu_data *ecud;
357 	paddr_t cfgaddr;
358 	uint32_t offset;
359 	uint8_t eisaid[EISA_IDSTRINGLEN];
360 	uint8_t *cdata, *data;
361 	uint8_t *cdp, *dp;
362 	struct ecu_func *ecuf;
363 	int i, func;
364 
365 	/*
366 	 * Locate EISA configuration space.
367 	 */
368 	if (hwrpb->rpb_condat_off == 0UL ||
369 	    (hwrpb->rpb_condat_off >> 63) != 0) {
370 		printf(": WARNING: no EISA configuration space");
371 		return;
372 	}
373 
374 	if (eisa_config_header_addr) {
375 		printf("\n");
376 		panic("eisa_init: EISA config space already initialized");
377 	}
378 
379 	eisa_config_header_addr = hwrpb->rpb_condat_off;
380 	if (eisa_config_stride == 0)
381 		eisa_config_stride = 1;
382 
383 #ifdef EISA_DEBUG
384 	printf("\nEISA config header at 0x%lx\n", eisa_config_header_addr);
385 	printf("EISA config at 0x%lx\n", eisa_config_addr);
386 	printf("EISA config stride: %ld\n", eisa_config_stride);
387 #endif
388 
389 	/*
390 	 * Read the slot headers, and allocate config structures for
391 	 * valid slots.
392 	 */
393 	for (cfgaddr = eisa_config_header_addr, i = 0;
394 	    i < eisa_maxslots(ec); i++) {
395 		eisa_read_config_bytes(cfgaddr, eisaid, sizeof(eisaid));
396 		eisaid[EISA_IDSTRINGLEN - 1] = '\0';	/* sanity */
397 		cfgaddr += sizeof(eisaid) * eisa_config_stride;
398 		eisa_read_config_word(cfgaddr, &offset);
399 		cfgaddr += sizeof(offset) * eisa_config_stride;
400 
401 		if (offset != 0 && offset != 0xffffffff) {
402 #ifdef EISA_DEBUG
403 			printf("SLOT %d: offset 0x%08x eisaid %s\n",
404 			    i, offset, eisaid);
405 #endif
406 			ecud = kmem_zalloc(sizeof(*ecud), KM_SLEEP);
407 			SIMPLEQ_INIT(&ecud->ecud_funcs);
408 
409 			ecud->ecud_slot = i;
410 			memcpy(ecud->ecud_eisaid, eisaid, sizeof(eisaid));
411 			ecud->ecud_offset = offset;
412 			SIMPLEQ_INSERT_TAIL(&ecu_data_list, ecud, ecud_list);
413 		}
414 	}
415 
416 	/*
417 	 * Now traverse the valid slots and read the info.
418 	 */
419 
420 	cdata = kmem_zalloc(CBUFSIZE, KM_SLEEP);
421 	data = kmem_zalloc(CBUFSIZE, KM_SLEEP);
422 
423 	SIMPLEQ_FOREACH(ecud, &ecu_data_list, ecud_list) {
424 		cfgaddr = eisa_config_addr + ecud->ecud_offset;
425 #ifdef EISA_DEBUG
426 		printf("Checking SLOT %d\n", ecud->ecud_slot);
427 		printf("Reading config bytes at 0x%lx to cdata[0]\n", cfgaddr);
428 #endif
429 		eisa_read_config_bytes(cfgaddr, &cdata[0], 1);
430 		cfgaddr += eisa_config_stride;
431 
432 		for (i = 1; i < CBUFSIZE; cfgaddr += eisa_config_stride, i++) {
433 #ifdef EISA_DEBUG
434 			printf("Reading config bytes at 0x%lx to cdata[%d]\n",
435 			    cfgaddr, i);
436 #endif
437 			eisa_read_config_bytes(cfgaddr, &cdata[i], 1);
438 			if (cdata[i - 1] == 0 && cdata[i] == 0)
439 				break;
440 		}
441 		if (i == CBUFSIZE) {
442 			/* assume this compressed data invalid */
443 #ifdef EISA_DEBUG
444 			printf("SLOT %d has invalid config\n", ecud->ecud_slot);
445 #endif
446 			continue;
447 		}
448 
449 		i++;	/* index -> length */
450 
451 #ifdef EISA_DEBUG
452 		printf("SLOT %d compressed data length %d:",
453 		    ecud->ecud_slot, i);
454 		{
455 			int j;
456 
457 			for (j = 0; j < i; j++) {
458 				if ((j % 16) == 0)
459 					printf("\n");
460 				printf("0x%02x ", cdata[j]);
461 			}
462 			printf("\n");
463 		}
464 #endif
465 
466 		cdp = cdata;
467 		dp = data;
468 
469 		/* Uncompress the slot header. */
470 		cdp += eisa_uncompress(cdp, dp, EISA_SLOT_HEADER_SIZE);
471 #ifdef EISA_DEBUG
472 		printf("SLOT %d uncompressed header data:",
473 		    ecud->ecud_slot);
474 		{
475 			int j;
476 
477 			for (j = 0; j < EISA_SLOT_HEADER_SIZE; j++) {
478 				if ((j % 16) == 0)
479 					printf("\n");
480 				printf("0x%02x ", dp[j]);
481 			}
482 			printf("\n");
483 		}
484 #endif
485 
486 		dp = &data[EISA_SLOT_INFO_OFFSET];
487 		ecud->ecud_slot_info = *dp++;
488 		ecud->ecud_ecu_major_rev = *dp++;
489 		ecud->ecud_ecu_minor_rev = *dp++;
490 		memcpy(&ecud->ecud_cksum, dp, sizeof(ecud->ecud_cksum));
491 		dp += sizeof(ecud->ecud_cksum);
492 		ecud->ecud_ndevfuncs = *dp++;
493 		ecud->ecud_funcinfo = *dp++;
494 		memcpy(&ecud->ecud_comp_id, dp, sizeof(ecud->ecud_comp_id));
495 		dp += sizeof(ecud->ecud_comp_id);
496 
497 #ifdef EISA_DEBUG
498 		printf("SLOT %d: ndevfuncs %d\n", ecud->ecud_slot,
499 		    ecud->ecud_ndevfuncs);
500 #endif
501 
502 		for (func = 0; func < ecud->ecud_ndevfuncs; func++) {
503 			dp = data;
504 			cdp += eisa_uncompress(cdp, dp, EISA_CONFIG_BLOCK_SIZE);
505 #ifdef EISA_DEBUG
506 			printf("SLOT %d:%d uncompressed data:",
507 			    ecud->ecud_slot, func);
508 			{
509 				int j;
510 
511 				for (j = 0; i < EISA_CONFIG_BLOCK_SIZE; j++) {
512 					if ((j % 16) == 0)
513 						printf("\n");
514 					printf("0x%02x ", dp[j]);
515 				}
516 				printf("\n");
517 			}
518 #endif
519 
520 			/* Skip disabled functions. */
521 			if (dp[EISA_FUNC_INFO_OFFSET] & ECUF_DISABLED) {
522 #ifdef EISA_DEBUG
523 				printf("SLOT %d:%d disabled\n",
524 				    ecud->ecud_slot, func);
525 #endif
526 				continue;
527 			}
528 
529 			ecuf = kmem_zalloc(sizeof(*ecuf), KM_SLEEP);
530 			ecuf_init(ecuf);
531 			ecuf->ecuf_funcno = func;
532 			SIMPLEQ_INSERT_TAIL(&ecud->ecud_funcs, ecuf,
533 			    ecuf_list);
534 
535 			memcpy(&ecuf->ecuf_id, dp, sizeof(ecuf->ecuf_id));
536 			dp += sizeof(ecuf->ecuf_id);
537 
538 			memcpy(&ecuf->ecuf_slot_info, dp,
539 			    sizeof(ecuf->ecuf_slot_info));
540 			dp += sizeof(ecuf->ecuf_slot_info);
541 
542 			memcpy(&ecuf->ecuf_cfg_ext, dp,
543 			    sizeof(ecuf->ecuf_cfg_ext));
544 			dp += sizeof(ecuf->ecuf_cfg_ext);
545 
546 			memcpy(&ecuf->ecuf_selections, dp,
547 			    sizeof(ecuf->ecuf_selections));
548 			dp += sizeof(ecuf->ecuf_selections);
549 
550 			memcpy(&ecuf->ecuf_func_info, dp,
551 			    sizeof(ecuf->ecuf_func_info));
552 			dp += sizeof(ecuf->ecuf_func_info);
553 
554 			if (ecuf->ecuf_func_info & ECUF_TYPE_STRING)
555 				memcpy(ecuf->ecuf_type_string, dp,
556 				    sizeof(ecuf->ecuf_type_string));
557 			dp += sizeof(ecuf->ecuf_type_string);
558 
559 			if (ecuf->ecuf_func_info & ECUF_MEM_ENTRY)
560 				eisa_parse_mem(ecuf, dp);
561 			dp += ECUF_MEM_ENTRY_SIZE * ECUF_MEM_ENTRY_CNT;
562 
563 			if (ecuf->ecuf_func_info & ECUF_IRQ_ENTRY)
564 				eisa_parse_irq(ecuf, dp);
565 			dp += ECUF_IRQ_ENTRY_SIZE * ECUF_IRQ_ENTRY_CNT;
566 
567 			if (ecuf->ecuf_func_info & ECUF_DMA_ENTRY)
568 				eisa_parse_dma(ecuf, dp);
569 			dp += ECUF_DMA_ENTRY_SIZE * ECUF_DMA_ENTRY_CNT;
570 
571 			if (ecuf->ecuf_func_info & ECUF_IO_ENTRY)
572 				eisa_parse_io(ecuf, dp);
573 			dp += ECUF_IO_ENTRY_SIZE * ECUF_IO_ENTRY_CNT;
574 
575 			if (ecuf->ecuf_func_info & ECUF_INIT_ENTRY)
576 				memcpy(ecuf->ecuf_init, dp,
577 				    sizeof(ecuf->ecuf_init));
578 			dp += sizeof(ecuf->ecuf_init);
579 		}
580 	}
581 
582 	kmem_free(cdata, CBUFSIZE);
583 	kmem_free(data, CBUFSIZE);
584 }
585 
586 static struct ecu_data *
eisa_lookup_data(int slot)587 eisa_lookup_data(int slot)
588 {
589 	struct ecu_data *ecud;
590 
591 	SIMPLEQ_FOREACH(ecud, &ecu_data_list, ecud_list) {
592 		if (ecud->ecud_slot == slot)
593 			return (ecud);
594 	}
595 	return (NULL);
596 }
597 
598 static struct ecu_func *
eisa_lookup_func(int slot,int func)599 eisa_lookup_func(int slot, int func)
600 {
601 	struct ecu_data *ecud;
602 	struct ecu_func *ecuf;
603 
604 	ecud = eisa_lookup_data(slot);
605 	if (ecud == NULL)
606 		return (NULL);
607 
608 	SIMPLEQ_FOREACH(ecuf, &ecud->ecud_funcs, ecuf_list) {
609 		if (ecuf->ecuf_funcno == func)
610 			return (ecuf);
611 	}
612 	return (NULL);
613 }
614 
615 int
eisa_conf_read_mem(eisa_chipset_tag_t ec,int slot,int func,int entry,struct eisa_cfg_mem * dp)616 eisa_conf_read_mem(eisa_chipset_tag_t ec, int slot, int func, int entry,
617     struct eisa_cfg_mem *dp)
618 {
619 	struct ecu_func *ecuf;
620 	struct ecu_mem *ecum;
621 
622 	ecuf = eisa_lookup_func(slot, func);
623 	if (ecuf == NULL)
624 		return (ENOENT);
625 
626 	SIMPLEQ_FOREACH(ecum, &ecuf->ecuf_mem, ecum_list) {
627 		if (entry-- == 0)
628 			break;
629 	}
630 	if (ecum == NULL)
631 		return (ENOENT);
632 
633 	*dp = ecum->ecum_mem;
634 	return (0);
635 }
636 
637 int
eisa_conf_read_irq(eisa_chipset_tag_t ec,int slot,int func,int entry,struct eisa_cfg_irq * dp)638 eisa_conf_read_irq(eisa_chipset_tag_t ec, int slot, int func, int entry,
639     struct eisa_cfg_irq *dp)
640 {
641 	struct ecu_func *ecuf;
642 	struct ecu_irq *ecui;
643 
644 	ecuf = eisa_lookup_func(slot, func);
645 	if (ecuf == NULL)
646 		return (ENOENT);
647 
648 	SIMPLEQ_FOREACH(ecui, &ecuf->ecuf_irq, ecui_list) {
649 		if (entry-- == 0)
650 			break;
651 	}
652 	if (ecui == NULL)
653 		return (ENOENT);
654 
655 	*dp = ecui->ecui_irq;
656 	return (0);
657 }
658 
659 int
eisa_conf_read_dma(eisa_chipset_tag_t ec,int slot,int func,int entry,struct eisa_cfg_dma * dp)660 eisa_conf_read_dma(eisa_chipset_tag_t ec, int slot, int func, int entry,
661     struct eisa_cfg_dma *dp)
662 {
663 	struct ecu_func *ecuf;
664 	struct ecu_dma *ecud;
665 
666 	ecuf = eisa_lookup_func(slot, func);
667 	if (ecuf == NULL)
668 		return (ENOENT);
669 
670 	SIMPLEQ_FOREACH(ecud, &ecuf->ecuf_dma, ecud_list) {
671 		if (entry-- == 0)
672 			break;
673 	}
674 	if (ecud == NULL)
675 		return (ENOENT);
676 
677 	*dp = ecud->ecud_dma;
678 	return (0);
679 }
680 
681 int
eisa_conf_read_io(eisa_chipset_tag_t ec,int slot,int func,int entry,struct eisa_cfg_io * dp)682 eisa_conf_read_io(eisa_chipset_tag_t ec, int slot, int func, int entry,
683     struct eisa_cfg_io *dp)
684 {
685 	struct ecu_func *ecuf;
686 	struct ecu_io *ecuio;
687 
688 	ecuf = eisa_lookup_func(slot, func);
689 	if (ecuf == NULL)
690 		return (ENOENT);
691 
692 	SIMPLEQ_FOREACH(ecuio, &ecuf->ecuf_io, ecuio_list) {
693 		if (entry-- == 0)
694 			break;
695 	}
696 	if (ecuio == NULL)
697 		return (ENOENT);
698 
699 	*dp = ecuio->ecuio_io;
700 	return (0);
701 }
702