diff options
author | scottl <scottl@FreeBSD.org> | 2002-11-12 08:23:27 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2002-11-12 08:23:27 +0000 |
commit | 57f021e104a4f3c1f693cd01da9ef1851e243997 (patch) | |
tree | dddef6e15fb1ff8f372427d4246e8c59c2cb5329 /sys | |
parent | e4a311f35f891fd45763fdd0459ec09c8c4d58f0 (diff) | |
download | FreeBSD-src-57f021e104a4f3c1f693cd01da9ef1851e243997.zip FreeBSD-src-57f021e104a4f3c1f693cd01da9ef1851e243997.tar.gz |
Step one of cleaning and fixing cardbus:
- Fix some especially bad style in the CIS BAR tuple parsing code.
- activate Option ROMS correctly.
- de-obfuscate the Option ROM image selection code.
- Fix mis-interpretation of the PCI spec that prevented Option ROMs whose
CIS section wasn't in the first image from working.
- Fix mis-interpretation of the PCI spec that prevented CIS's mapped into
MEMIO space from working at all.
- Reject invalid CIS pointers.
Reviewed by: imp
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/cardbus/cardbus_cis.c | 157 |
1 files changed, 92 insertions, 65 deletions
diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index 47d3807..c8bf780 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -265,51 +265,48 @@ DECODE_PROTOTYPE(funce) DECODE_PROTOTYPE(bar) { + struct cardbus_devinfo *dinfo = device_get_ivars(child); + int type; + int reg; + u_int32_t bar; + if (len != 6) { printf("*** ERROR *** BAR length not 6 (%d)\n", len); return (EINVAL); + } + reg = *(u_int16_t*)tupledata; + len = *(u_int32_t*)(tupledata + 2); + if (reg & TPL_BAR_REG_AS) { + type = SYS_RES_IOPORT; } else { - struct cardbus_devinfo *dinfo = device_get_ivars(child); - int type; - int reg; - u_int32_t bar; - - reg = *(u_int16_t*)tupledata; - len = *(u_int32_t*)(tupledata + 2); - if (reg & TPL_BAR_REG_AS) { - type = SYS_RES_IOPORT; - } else { - type = SYS_RES_MEMORY; - } - bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; - if (bar < 0 || bar > 5 || - (type == SYS_RES_IOPORT && bar == 5)) { - device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n", - reg, bar); - return (0); - } - bar = CARDBUS_BASE0_REG + bar * 4; - if (type == SYS_RES_MEMORY) { - if (bar & TPL_BAR_REG_PREFETCHABLE) - dinfo->mprefetchable |= BARBIT(bar); - if (bar & TPL_BAR_REG_BELOW1MB) - dinfo->mbelow1mb |= BARBIT(bar); - } else if (type == SYS_RES_IOPORT) { - if (bar & TPL_BAR_REG_BELOW1MB) - dinfo->ibelow1mb |= BARBIT(bar); - } - DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, " - "len=%04x%s%s\n", - (type==SYS_RES_MEMORY)?"MEM":"IO", bar, len, - (type==SYS_RES_MEMORY&&dinfo->mprefetchable&BARBIT(bar))? - " (Prefetchable)":"", - type==SYS_RES_MEMORY? - ((dinfo->mbelow1mb&BARBIT(bar))?" (Below 1Mb)":"") - :(dinfo->ibelow1mb&BARBIT(bar))?" (Below 1Mb)":"" - )); - - resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len); + type = SYS_RES_MEMORY; + } + bar = (reg & TPL_BAR_REG_ASI_MASK) - 1; + if (bar < 0 || bar > 5 || + (type == SYS_RES_IOPORT && bar == 5)) { + device_printf(cbdev, "Invalid BAR number: %02x(%02x)\n", + reg, bar); + return (0); } + bar = CARDBUS_BASE0_REG + bar * 4; + if (type == SYS_RES_MEMORY) { + if (bar & TPL_BAR_REG_PREFETCHABLE) + dinfo->mprefetchable |= BARBIT(bar); + if (bar & TPL_BAR_REG_BELOW1MB) + dinfo->mbelow1mb |= BARBIT(bar); + } else if (type == SYS_RES_IOPORT) { + if (bar & TPL_BAR_REG_BELOW1MB) + dinfo->ibelow1mb |= BARBIT(bar); + } + DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n", + (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len, + (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ? + " (Prefetchable)" : "", type == SYS_RES_MEMORY ? + ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : + (dinfo->ibelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "" )); + + resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len); + return (0); } @@ -412,7 +409,7 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, switch (CARDBUS_CIS_SPACE(*start)) { case CARDBUS_CIS_ASI_TUPLE: - /* CIS in tuple space need no initialization */ + /* CIS in PCI config space need no initialization */ return ((struct resource*)~0UL); case CARDBUS_CIS_ASI_BAR0: case CARDBUS_CIS_ASI_BAR1: @@ -421,11 +418,16 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, case CARDBUS_CIS_ASI_BAR4: case CARDBUS_CIS_ASI_BAR5: *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4; - pci_write_config(child, *rid, 0xffffffff, 4); break; case CARDBUS_CIS_ASI_ROM: *rid = CARDBUS_ROM_REG; +#if 0 + /* + * This mask doesn't contain the bit that actually enables + * the Option ROM. + */ pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4); +#endif break; default: device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", @@ -434,12 +436,20 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, } /* figure out how much space we need */ + pci_write_config(child, *rid, 0xffffffff, 4); testval = pci_read_config(child, *rid, 4); - if (testval & 1) { + + /* + * This bit has a different meaning depending if we are dealing + * with normal a normal BAR or an Option ROM BAR. + */ + if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) { device_printf(cbdev, "CIS Space is IO, expecting memory.\n"); return (NULL); } + size = CARDBUS_MAPREG_MEM_SIZE(testval); + /* XXX Is this some kind of hack? */ if (size < 4096) size = 4096; /* allocate the memory space to read CIS */ @@ -460,57 +470,73 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) { bus_space_tag_t bt; bus_space_handle_t bh; - int imagenum; u_int32_t imagesize; - int mystart = 0; + u_int32_t imagebase = 0; + u_int32_t pcidata; + u_int16_t romsig; int romnum = 0; - int dataptr; + int imagenum; bt = rman_get_bustag(res); bh = rman_get_bushandle(res); imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start); for (romnum = 0;; romnum++) { - if (bus_space_read_2(bt, bh, - mystart+CARDBUS_EXROM_SIGNATURE) != 0xaa55) { + romsig = bus_space_read_2(bt, bh, + imagebase + CARDBUS_EXROM_SIGNATURE); + if (romsig != 0xaa55) { device_printf(cbdev, "Bad header in rom %d: " - "[%x] %04x\n", romnum, mystart + - CARDBUS_EXROM_SIGNATURE, - bus_space_read_2(bt, bh, - mystart+CARDBUS_EXROM_SIGNATURE)); + "[%x] %04x\n", romnum, imagebase + + CARDBUS_EXROM_SIGNATURE, romsig); bus_release_resource(cbdev, SYS_RES_MEMORY, *rid, res); *rid = 0; return (NULL); } - dataptr = mystart + bus_space_read_2(bt, bh, - mystart + CARDBUS_EXROM_DATA_PTR); + + /* + * If this was the Option ROM image that we were + * looking for, then we are done. + */ + if (romnum == imagenum) + break; + + /* Find out where the next Option ROM image is */ + pcidata = imagebase + bus_space_read_2(bt, bh, + imagebase + CARDBUS_EXROM_DATA_PTR); imagesize = bus_space_read_2(bt, bh, - dataptr + CARDBUS_EXROM_DATA_IMAGE_LENGTH); + pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH); if (imagesize == 0) { /* * XXX some ROMs seem to have this as zero, * can we assume this means 1 block? */ + device_printf(cbdev, "Warning, size of Option " + "ROM image %d is 0 bytes, assuming 512 " + "bytes.\n", romnum); imagesize = 1; } + + /* Image size is in 512 byte units */ imagesize <<= 9; - if (romnum == imagenum) - break; - if ((bus_space_read_1(bt, bh, mystart + - CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 0) { - device_printf(cbdev, "Cannot read CIS: " - "Not enough images of rom\n"); + if ((bus_space_read_1(bt, bh, pcidata + + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) == 1) { + device_printf(cbdev, "Cannot find CIS in " + "Option ROM\n"); + bus_release_resource(cbdev, SYS_RES_MEMORY, + *rid, res); + *rid = 0; return (NULL); } - mystart += imagesize; + imagebase += imagesize; } - *start = mystart + CARDBUS_CIS_ADDR(*start); + *start = imagebase + CARDBUS_CIS_ADDR(*start); } else { - *start = CARDBUS_CIS_SPACE(*start); + *start = CARDBUS_CIS_ADDR(*start); } + return (res); } @@ -553,7 +579,8 @@ cardbus_parse_cis(device_t cbdev, device_t child, bzero(tupledata, MAXTUPLESIZE); expect_linktarget = TRUE; - start = pci_read_config(child, CARDBUS_CIS_REG, 4); + if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) + return (ENXIO); off = 0; res = cardbus_read_tuple_init(cbdev, child, &start, &rid); if (res == NULL) |