xref: /dragonfly/sys/dev/pccard/cardbus/cardbus_cis.c (revision 86d7f5d3)
1 /*-
2  * Copyright (c) 2000,2001 Jonathan Chen.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/cardbus/cardbus_cis.c,v 1.50 2005/02/20 20:36:16 imp Exp $
27  */
28 
29 /*
30  * CIS Handling for the Cardbus Bus
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/endian.h>
41 
42 #include <sys/pciio.h>
43 #include <bus/pci/pcivar.h>
44 #include <bus/pci/pcireg.h>
45 
46 #include <bus/pccard/pccardvar.h>
47 #include <bus/pccard/pccard_cis.h>
48 
49 #include <dev/pccard/cardbus/cardbusreg.h>
50 #include <dev/pccard/cardbus/cardbusvar.h>
51 #include <dev/pccard/cardbus/cardbus_cis.h>
52 
53 extern int cardbus_cis_debug;
54 
55 #define	DPRINTF(a) if (cardbus_cis_debug) kprintf a
56 #define	DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
57 
58 struct tuple_callbacks;
59 
60 typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
61 		 uint8_t *tupledata, uint32_t start, uint32_t *off,
62 		 struct tuple_callbacks *info);
63 
64 struct tuple_callbacks {
65 	int	id;
66 	char	*name;
67 	tuple_cb *func;
68 };
69 
70 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
71     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
72     struct tuple_callbacks *info);
73 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
74     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
75     struct tuple_callbacks *info);
76 static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
77     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
78     struct tuple_callbacks *info);
79 static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
80     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
81     struct tuple_callbacks *info);
82 static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
83     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
84     struct tuple_callbacks *info);
85 static int decode_tuple_funce(device_t cbdev, device_t child, int id,
86     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
87     struct tuple_callbacks *info);
88 static int decode_tuple_bar(device_t cbdev, device_t child, int id,
89     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
90     struct tuple_callbacks *info);
91 static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
92     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
93     struct tuple_callbacks *info);
94 static int decode_tuple_end(device_t cbdev, device_t child, int id,
95     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
96     struct tuple_callbacks *info);
97 
98 static int	cardbus_read_tuple_conf(device_t cbdev, device_t child,
99 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
100 		    uint8_t *tupledata);
101 static int	cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
102 		    uint32_t start, uint32_t *off, int *tupleid, int *len,
103 		    uint8_t *tupledata);
104 static int	cardbus_read_tuple(device_t cbdev, device_t child,
105 		    struct resource *res, uint32_t start, uint32_t *off,
106 		    int *tupleid, int *len, uint8_t *tupledata);
107 static void	cardbus_read_tuple_finish(device_t cbdev, device_t child,
108 		    int rid, struct resource *res);
109 static struct resource	*cardbus_read_tuple_init(device_t cbdev, device_t child,
110 		    uint32_t *start, int *rid);
111 static int	decode_tuple(device_t cbdev, device_t child, int tupleid,
112 		    int len, uint8_t *tupledata, uint32_t start,
113 		    uint32_t *off, struct tuple_callbacks *callbacks);
114 static int	cardbus_parse_cis(device_t cbdev, device_t child,
115 		    struct tuple_callbacks *callbacks);
116 
117 #define	MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
118 
119 static char *funcnames[] = {
120 	"Multi-Functioned",
121 	"Memory",
122 	"Serial Port",
123 	"Parallel Port",
124 	"Fixed Disk",
125 	"Video Adaptor",
126 	"Network Adaptor",
127 	"AIMS",
128 	"SCSI",
129 	"Security"
130 };
131 
132 /*
133  * Handler functions for various CIS tuples
134  */
135 
136 static int
decode_tuple_generic(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)137 decode_tuple_generic(device_t cbdev, device_t child, int id,
138     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
139     struct tuple_callbacks *info)
140 {
141 	int i;
142 
143 	if (cardbus_cis_debug) {
144 		if (info)
145 			kprintf("TUPLE: %s [%d]:", info->name, len);
146 		else
147 			kprintf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
148 
149 		for (i = 0; i < len; i++) {
150 			if (i % 0x10 == 0 && len > 0x10)
151 				kprintf("\n       0x%02x:", i);
152 			kprintf(" %02x", tupledata[i]);
153 		}
154 		kprintf("\n");
155 	}
156 	return (0);
157 }
158 
159 static int
decode_tuple_linktarget(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)160 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
161     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
162     struct tuple_callbacks *info)
163 {
164 	int i;
165 
166 	if (cardbus_cis_debug) {
167 		kprintf("TUPLE: %s [%d]:", info->name, len);
168 
169 		for (i = 0; i < len; i++) {
170 			if (i % 0x10 == 0 && len > 0x10)
171 				kprintf("\n       0x%02x:", i);
172 			kprintf(" %02x", tupledata[i]);
173 		}
174 		kprintf("\n");
175 	}
176 	if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
177 	    tupledata[2] != 'S') {
178 		kprintf("Invalid data for CIS Link Target!\n");
179 		decode_tuple_generic(cbdev, child, id, len, tupledata,
180 		    start, off, info);
181 		return (EINVAL);
182 	}
183 	return (0);
184 }
185 
186 static int
decode_tuple_vers_1(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)187 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
188     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
189     struct tuple_callbacks *info)
190 {
191 	int i;
192 
193 	if (cardbus_cis_debug) {
194 		kprintf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
195 		kprintf("Product name: ");
196 		for (i = 2; i < len; i++) {
197 			if (tupledata[i] == '\0')
198 				kprintf(" | ");
199 			else if (tupledata[i] == 0xff)
200 				break;
201 			else
202 				kprintf("%c", tupledata[i]);
203 		}
204 		kprintf("\n");
205 	}
206 	return (0);
207 }
208 
209 static int
decode_tuple_funcid(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)210 decode_tuple_funcid(device_t cbdev, device_t child, int id,
211     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
212     struct tuple_callbacks *info)
213 {
214 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
215 	int numnames = NELEM(funcnames);
216 	int i;
217 
218 	if (cardbus_cis_debug) {
219 		kprintf("Functions: ");
220 		for (i = 0; i < len; i++) {
221 			if (tupledata[i] < numnames)
222 				kprintf("%s", funcnames[tupledata[i]]);
223 			else
224 				kprintf("Unknown(%d)", tupledata[i]);
225 			if (i < len-1)
226 				kprintf(", ");
227 		}
228 		kprintf("\n");
229 	}
230 	if (len > 0)
231 		dinfo->funcid = tupledata[0];		/* use first in list */
232 	return (0);
233 }
234 
235 static int
decode_tuple_manfid(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)236 decode_tuple_manfid(device_t cbdev, device_t child, int id,
237     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
238     struct tuple_callbacks *info)
239 {
240 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
241 	int i;
242 
243 	if (cardbus_cis_debug) {
244 		kprintf("Manufacturer ID: ");
245 		for (i = 0; i < len; i++)
246 			kprintf("%02x", tupledata[i]);
247 		kprintf("\n");
248 	}
249 
250 	if (len == 5) {
251 		dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
252 		dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
253 	}
254 	return (0);
255 }
256 
257 static int
decode_tuple_funce(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)258 decode_tuple_funce(device_t cbdev, device_t child, int id,
259     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
260     struct tuple_callbacks *info)
261 {
262 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
263 	int type, i;
264 
265 	if (cardbus_cis_debug) {
266 		kprintf("Function Extension: ");
267 		for (i = 0; i < len; i++)
268 			kprintf("%02x", tupledata[i]);
269 		kprintf("\n");
270 	}
271 	if (len < 2)			/* too short */
272 		return (0);
273 	type = tupledata[0];		/* XXX <32 always? */
274 	switch (dinfo->funcid) {
275 	case PCCARD_FUNCTION_NETWORK:
276 		switch (type) {
277 		case PCCARD_TPLFE_TYPE_LAN_NID:
278 			if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
279 				/* ignore, warning? */
280 				return (0);
281 			}
282 			bcopy(tupledata + 2, dinfo->funce.lan.nid,
283 			    tupledata[1]);
284 			break;
285 		}
286 		dinfo->fepresent |= 1<<type;
287 		break;
288 	}
289 	return (0);
290 }
291 
292 static int
decode_tuple_bar(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)293 decode_tuple_bar(device_t cbdev, device_t child, int id,
294     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
295     struct tuple_callbacks *info)
296 {
297 	struct cardbus_devinfo *dinfo = device_get_ivars(child);
298 	int type;
299 	uint8_t reg;
300 	uint32_t bar, pci_bar;
301 
302 	if (len != 6) {
303 		device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
304 		return (EINVAL);
305 	}
306 
307 	reg = *tupledata;
308 	len = le32toh(*(uint32_t*)(tupledata + 2));
309 	if (reg & TPL_BAR_REG_AS) {
310 		type = SYS_RES_IOPORT;
311 	} else {
312 		type = SYS_RES_MEMORY;
313 	}
314 
315 	bar = reg & TPL_BAR_REG_ASI_MASK;
316 	if (bar == 0) {
317 		device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
318 		return (EINVAL);	/* XXX Return an error? */
319 	} else if (bar == 7) {
320 		/* XXX Should we try to map in Option ROMs? */
321 		return (0);
322 	}
323 
324 	/* Convert from BAR type to BAR offset */
325 	bar = CARDBUS_BASE0_REG + (bar - 1) * 4;
326 
327 	if (type == SYS_RES_MEMORY) {
328 		if (reg & TPL_BAR_REG_PREFETCHABLE)
329 			dinfo->mprefetchable |= BARBIT(bar);
330 #if 0
331 		/*
332 		 * XXX: It appears from a careful reading of the spec
333 		 * that we're not supposed to honor this when the bridge
334 		 * is not on the main system bus.  PCI spec doesn't appear
335 		 * to allow for memory ranges not listed in the bridge's
336 		 * decode range to be decoded.  The PC Card spec seems to
337 		 * indicate that this should only be done on x86 based
338 		 * machines, which seems to imply that on non-x86 machines
339 		 * the adddresses can be anywhere.  This further implies that
340 		 * since the hardware can do it on non-x86 machines, it should
341 		 * be able to do it on x86 machines.  Therefore, we can and
342 		 * should ignore this hint.  Furthermore, the PC Card spec
343 		 * recommends always allocating memory above 1MB, contradicting
344 		 * the other part of the PC Card spec.
345 		 *
346 		 * NetBSD ignores this bit, but it also ignores the
347 		 * prefetchable bit too, so that's not an indication of
348 		 * correctness.
349 		 */
350 		if (reg & TPL_BAR_REG_BELOW1MB)
351 			dinfo->mbelow1mb |= BARBIT(bar);
352 #endif
353 	}
354 
355 	/*
356 	 * Sanity check the BAR length reported in the CIS with the length
357 	 * encoded in the PCI BAR.  The latter seems to be more reliable.
358 	 * XXX - This probably belongs elsewhere.
359 	 */
360 	pci_write_config(child, bar, 0xffffffff, 4);
361 	pci_bar = pci_read_config(child, bar, 4);
362 	if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
363 		if (type == SYS_RES_MEMORY) {
364 			pci_bar &= ~0xf;
365 		} else {
366 			pci_bar &= ~0x3;
367 		}
368 		len = 1 << (ffs(pci_bar) - 1);
369 	}
370 
371 	DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
372 	    (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
373 	    (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
374 	    " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
375 	    ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : ""));
376 
377 	resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len, -1);
378 
379 	/*
380 	 * Mark the appropriate bit in the PCI command register so that
381 	 * device drivers will know which type of BARs can be used.
382 	 */
383 	pci_enable_io(child, type);
384 	return (0);
385 }
386 
387 static int
decode_tuple_unhandled(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)388 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
389     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
390     struct tuple_callbacks *info)
391 {
392 	/* Make this message suck less XXX */
393 	kprintf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
394 	return (-1);
395 }
396 
397 static int
decode_tuple_end(device_t cbdev,device_t child,int id,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * info)398 decode_tuple_end(device_t cbdev, device_t child, int id,
399     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
400     struct tuple_callbacks *info)
401 {
402 	if (cardbus_cis_debug)
403 		kprintf("CIS reading done\n");
404 	return (0);
405 }
406 
407 /*
408  * Functions to read the a tuple from the card
409  */
410 
411 static int
cardbus_read_tuple_conf(device_t cbdev,device_t child,uint32_t start,uint32_t * off,int * tupleid,int * len,uint8_t * tupledata)412 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
413     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
414 {
415 	int i, j;
416 	uint32_t e;
417 	uint32_t loc;
418 
419 	loc = start + *off;
420 
421 	e = pci_read_config(child, loc - loc % 4, 4);
422 	for (j = loc % 4; j > 0; j--)
423 		e >>= 8;
424 	*len = 0;
425 	for (i = loc, j = -2; j < *len; j++, i++) {
426 		if (i % 4 == 0)
427 			e = pci_read_config(child, i, 4);
428 		if (j == -2)
429 			*tupleid = 0xff & e;
430 		else if (j == -1)
431 			*len = 0xff & e;
432 		else
433 			tupledata[j] = 0xff & e;
434 		e >>= 8;
435 	}
436 	*off += *len + 2;
437 	return (0);
438 }
439 
440 static int
cardbus_read_tuple_mem(device_t cbdev,struct resource * res,uint32_t start,uint32_t * off,int * tupleid,int * len,uint8_t * tupledata)441 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
442     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
443 {
444 	bus_space_tag_t bt;
445 	bus_space_handle_t bh;
446 	int ret;
447 
448 	bt = rman_get_bustag(res);
449 	bh = rman_get_bushandle(res);
450 
451 	*tupleid = bus_space_read_1(bt, bh, start + *off);
452 	*len = bus_space_read_1(bt, bh, start + *off + 1);
453 	bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
454 	ret = 0;
455 	*off += *len + 2;
456 	return (ret);
457 }
458 
459 static int
cardbus_read_tuple(device_t cbdev,device_t child,struct resource * res,uint32_t start,uint32_t * off,int * tupleid,int * len,uint8_t * tupledata)460 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
461     uint32_t start, uint32_t *off, int *tupleid, int *len,
462     uint8_t *tupledata)
463 {
464 	if (res == (struct resource*)~0UL) {
465 		return (cardbus_read_tuple_conf(cbdev, child, start, off,
466 		    tupleid, len, tupledata));
467 	} else {
468 		return (cardbus_read_tuple_mem(cbdev, res, start, off,
469 		    tupleid, len, tupledata));
470 	}
471 }
472 
473 static void
cardbus_read_tuple_finish(device_t cbdev,device_t child,int rid,struct resource * res)474 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
475     struct resource *res)
476 {
477 	if (res != (struct resource*)~0UL) {
478 		bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
479 		pci_write_config(child, rid, 0, 4);
480 		PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
481 	}
482 }
483 
484 static struct resource *
cardbus_read_tuple_init(device_t cbdev,device_t child,uint32_t * start,int * rid)485 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
486     int *rid)
487 {
488 	uint32_t testval;
489 	uint32_t size;
490 	struct resource *res;
491 
492 	switch (CARDBUS_CIS_SPACE(*start)) {
493 	case CARDBUS_CIS_ASI_TUPLE:
494 		/* CIS in PCI config space need no initialization */
495 		return ((struct resource*)~0UL);
496 	case CARDBUS_CIS_ASI_BAR0:
497 	case CARDBUS_CIS_ASI_BAR1:
498 	case CARDBUS_CIS_ASI_BAR2:
499 	case CARDBUS_CIS_ASI_BAR3:
500 	case CARDBUS_CIS_ASI_BAR4:
501 	case CARDBUS_CIS_ASI_BAR5:
502 		*rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
503 		break;
504 	case CARDBUS_CIS_ASI_ROM:
505 		*rid = CARDBUS_ROM_REG;
506 #if 0
507 		/*
508 		 * This mask doesn't contain the bit that actually enables
509 		 * the Option ROM.
510 		 */
511 		pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
512 #endif
513 		break;
514 	default:
515 		device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
516 		    CARDBUS_CIS_SPACE(*start));
517 		return (NULL);
518 	}
519 
520 	/* figure out how much space we need */
521 	pci_write_config(child, *rid, 0xffffffff, 4);
522 	testval = pci_read_config(child, *rid, 4);
523 
524 	/*
525 	 * This bit has a different meaning depending if we are dealing
526 	 * with a normal BAR or an Option ROM BAR.
527 	 */
528 	if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
529 		device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
530 		return (NULL);
531 	}
532 
533 	size = CARDBUS_MAPREG_MEM_SIZE(testval);
534 	/* XXX Is this some kind of hack? */
535 	if (size < 4096)
536 		size = 4096;
537 	/* allocate the memory space to read CIS */
538 	res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
539 	    rman_make_alignment_flags(size) | RF_ACTIVE);
540 	if (res == NULL) {
541 		device_printf(cbdev, "Unable to allocate resource "
542 		    "to read CIS.\n");
543 		return (NULL);
544 	}
545 	pci_write_config(child, *rid,
546 	    rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
547 		CARDBUS_ROM_ENABLE : 0),
548 	    4);
549 	PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
550 
551 	/* Flip to the right ROM image if CIS is in ROM */
552 	if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
553 		bus_space_tag_t bt;
554 		bus_space_handle_t bh;
555 		uint32_t imagesize;
556 		uint32_t imagebase = 0;
557 		uint32_t pcidata;
558 		uint16_t romsig;
559 		int romnum = 0;
560 		int imagenum;
561 
562 		bt = rman_get_bustag(res);
563 		bh = rman_get_bushandle(res);
564 
565 		imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
566 		for (romnum = 0;; romnum++) {
567 			romsig = bus_space_read_2(bt, bh,
568 			    imagebase + CARDBUS_EXROM_SIGNATURE);
569 			if (romsig != 0xaa55) {
570 				device_printf(cbdev, "Bad header in rom %d: "
571 				    "[%x] %04x\n", romnum, imagebase +
572 				    CARDBUS_EXROM_SIGNATURE, romsig);
573 				bus_release_resource(cbdev, SYS_RES_MEMORY,
574 				    *rid, res);
575 				*rid = 0;
576 				return (NULL);
577 			}
578 
579 			/*
580 			 * If this was the Option ROM image that we were
581 			 * looking for, then we are done.
582 			 */
583 			if (romnum == imagenum)
584 				break;
585 
586 			/* Find out where the next Option ROM image is */
587 			pcidata = imagebase + bus_space_read_2(bt, bh,
588 			    imagebase + CARDBUS_EXROM_DATA_PTR);
589 			imagesize = bus_space_read_2(bt, bh,
590 			    pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
591 
592 			if (imagesize == 0) {
593 				/*
594 				 * XXX some ROMs seem to have this as zero,
595 				 * can we assume this means 1 block?
596 				 */
597 				device_printf(cbdev, "Warning, size of Option "
598 				    "ROM image %d is 0 bytes, assuming 512 "
599 				    "bytes.\n", romnum);
600 				imagesize = 1;
601 			}
602 
603 			/* Image size is in 512 byte units */
604 			imagesize <<= 9;
605 
606 			if ((bus_space_read_1(bt, bh, pcidata +
607 			    CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
608 				device_printf(cbdev, "Cannot find CIS in "
609 				    "Option ROM\n");
610 				bus_release_resource(cbdev, SYS_RES_MEMORY,
611 				    *rid, res);
612 				*rid = 0;
613 				return (NULL);
614 			}
615 			imagebase += imagesize;
616 		}
617 		*start = imagebase + CARDBUS_CIS_ADDR(*start);
618 	} else {
619 		*start = CARDBUS_CIS_ADDR(*start);
620 	}
621 
622 	return (res);
623 }
624 
625 /*
626  * Dispatch the right handler function per tuple
627  */
628 
629 static int
decode_tuple(device_t cbdev,device_t child,int tupleid,int len,uint8_t * tupledata,uint32_t start,uint32_t * off,struct tuple_callbacks * callbacks)630 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
631     uint8_t *tupledata, uint32_t start, uint32_t *off,
632     struct tuple_callbacks *callbacks)
633 {
634 	int i;
635 	for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
636 		if (tupleid == callbacks[i].id)
637 			return (callbacks[i].func(cbdev, child, tupleid, len,
638 			    tupledata, start, off, &callbacks[i]));
639 	}
640 	return (callbacks[i].func(cbdev, child, tupleid, len,
641 	    tupledata, start, off, NULL));
642 }
643 
644 static int
cardbus_parse_cis(device_t cbdev,device_t child,struct tuple_callbacks * callbacks)645 cardbus_parse_cis(device_t cbdev, device_t child,
646     struct tuple_callbacks *callbacks)
647 {
648 	uint8_t tupledata[MAXTUPLESIZE];
649 	int tupleid = CISTPL_NULL;
650 	int len;
651 	int expect_linktarget;
652 	uint32_t start, off;
653 	struct resource *res;
654 	int rid;
655 
656 	bzero(tupledata, MAXTUPLESIZE);
657 	expect_linktarget = TRUE;
658 	if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) {
659 		if (bootverbose)
660 			device_printf(cbdev, "CIS pointer is 0!\n");
661 		return (ENXIO);
662 	}
663 	off = 0;
664 	res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
665 	if (res == NULL) {
666 		device_printf(cbdev, "Unable to allocate resources for CIS\n");
667 		return (ENXIO);
668 	}
669 
670 	do {
671 		if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
672 		    &tupleid, &len, tupledata)) {
673 			device_printf(cbdev, "Failed to read CIS.\n");
674 			cardbus_read_tuple_finish(cbdev, child, rid, res);
675 			return (ENXIO);
676 		}
677 
678 		if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
679 			device_printf(cbdev, "Expecting link target, got 0x%x\n",
680 			    tupleid);
681 			cardbus_read_tuple_finish(cbdev, child, rid, res);
682 			return (EINVAL);
683 		}
684 		expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
685 		    tupledata, start, &off, callbacks);
686 		if (expect_linktarget != 0) {
687 			device_printf(cbdev, "Parsing failed with %d\n",
688 			    expect_linktarget);
689 			cardbus_read_tuple_finish(cbdev, child, rid, res);
690 			return (expect_linktarget);
691 		}
692 	} while (tupleid != CISTPL_END);
693 	cardbus_read_tuple_finish(cbdev, child, rid, res);
694 	return (0);
695 }
696 
697 int
cardbus_do_cis(device_t cbdev,device_t child)698 cardbus_do_cis(device_t cbdev, device_t child)
699 {
700 	int ret;
701 	struct tuple_callbacks init_callbacks[] = {
702 		MAKETUPLE(LONGLINK_CB,		unhandled),
703 		MAKETUPLE(INDIRECT,		unhandled),
704 		MAKETUPLE(LONGLINK_MFC,		unhandled),
705 		MAKETUPLE(BAR,			bar),
706 		MAKETUPLE(LONGLINK_A,		unhandled),
707 		MAKETUPLE(LONGLINK_C,		unhandled),
708 		MAKETUPLE(LINKTARGET,		linktarget),
709 		MAKETUPLE(VERS_1,		vers_1),
710 		MAKETUPLE(MANFID,		manfid),
711 		MAKETUPLE(FUNCID,		funcid),
712 		MAKETUPLE(FUNCE,		funce),
713 		MAKETUPLE(END,			end),
714 		MAKETUPLE(GENERIC,		generic),
715 	};
716 
717 	ret = cardbus_parse_cis(cbdev, child, init_callbacks);
718 	if (ret < 0)
719 		return (ret);
720 	return 0;
721 }
722