X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7ed9009bbdf799be5f9f1446c264b8504f483beb..95316451cb8a4d8c63fb5cc7074912f497815f12:/target/linux/brcm-2.4/files/arch/mips/bcm947xx/bcmsrom.c diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/bcmsrom.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/bcmsrom.c index 1d08218a4..d5737d72f 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/bcmsrom.c +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/bcmsrom.c @@ -1,509 +1,1048 @@ /* - * Misc useful routines to access NIC SROM/OTP . + * Routines to access SPROM and to parse SROM/CIS variables. * - * Copyright 2006, Broadcom Corporation + * Copyright 2007, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * $Id: bcmsrom.c,v 1.1.1.14 2006/04/15 01:28:25 michael Exp $ + * $Id$ */ #include #include #include -#include -#include +#include +#include #include #include #include #include +#include #include +#include #include +#include "utils.h" /* debug/trace */ #if defined(WLTEST) #define BS_ERROR(args) printf args #else #define BS_ERROR(args) -#endif /* BCMDBG_ERR || WLTEST */ - -#define VARS_MAX 4096 /* should be reduced */ +#endif #define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */ #define WRITE_WORD_DELAY 20 /* 20 ms between each word write */ -static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count); -static int initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count); -static int initvars_flash_sb(void *sbh, char **vars, uint *count); -static int srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count); -static int sprom_cmd_pcmcia(osl_t *osh, uint8 cmd); -static int sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data); -static int sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data); -static int sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, - bool check_crc); +typedef struct varbuf +{ + char *buf; /* pointer to current position */ + unsigned int size; /* current (residual) size in bytes */ +} varbuf_t; + +static int initvars_srom_sb (sb_t * sbh, osl_t * osh, void *curmap, + char **vars, uint * count); +static void _initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off, + varbuf_t * b); +static int initvars_srom_pci (sb_t * sbh, void *curmap, char **vars, + uint * count); +static int initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars, + uint * count); +#if !defined(BCMUSBDEV) && !defined(BCMSDIODEV) +static int initvars_flash_sb (sb_t * sbh, char **vars, uint * count); +#endif /* !BCMUSBDEV && !BCMSDIODEV */ +static int sprom_cmd_pcmcia (osl_t * osh, uint8 cmd); +static int sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data); +static int sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data); +static int sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff, + uint16 * buf, uint nwords, bool check_crc); + +static int initvars_table (osl_t * osh, char *start, char *end, char **vars, + uint * count); +static int initvars_flash (sb_t * sbh, osl_t * osh, char **vp, uint len); + +#ifdef BCMUSBDEV +static int get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs, + uint boff, uint16 * srom, uint bsz); +static int set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs, + uint boff, uint16 * srom, uint bsz); +static uint srom_size (sb_t * sbh, osl_t * osh); +#endif /* def BCMUSBDEV */ + +/* Initialization of varbuf structure */ +static void +varbuf_init (varbuf_t * b, char *buf, uint size) +{ + b->size = size; + b->buf = buf; +} -static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count); -static int initvars_flash(osl_t *osh, char **vp, uint len, char *devpath); +/* append a null terminated var=value string */ +static int +varbuf_append (varbuf_t * b, const char *fmt, ...) +{ + va_list ap; + int r; + + if (b->size < 2) + return 0; + + va_start (ap, fmt); + r = vsnprintf (b->buf, b->size, fmt, ap); + va_end (ap); + + /* C99 snprintf behavior returns r >= size on overflow, + * others return -1 on overflow. + * All return -1 on format error. + * We need to leave room for 2 null terminations, one for the current var + * string, and one for final null of the var table. So check that the + * strlen written, r, leaves room for 2 chars. + */ + if ((r == -1) || (r > (int) (b->size - 2))) + { + b->size = 0; + return 0; + } + + /* skip over this string's null termination */ + r++; + b->size -= r; + b->buf += r; + + return r; +} /* * Initialize local vars from the right source for this platform. * Return 0 on success, nonzero on error. */ int -srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, uint *count) +BCMINITFN (srom_var_init) (sb_t * sbh, uint bustype, void *curmap, + osl_t * osh, char **vars, uint * count) { - ASSERT(bustype == BUSTYPE(bustype)); - if (vars == NULL || count == NULL) - return (0); + ASSERT (bustype == BUSTYPE (bustype)); + if (vars == NULL || count == NULL) + return (0); - switch (BUSTYPE(bustype)) { - case SB_BUS: - case JTAG_BUS: - return initvars_flash_sb(sbh, vars, count); + *vars = NULL; + *count = 0; - case PCI_BUS: - ASSERT(curmap); /* can not be NULL */ - return initvars_srom_pci(sbh, curmap, vars, count); + switch (BUSTYPE (bustype)) + { + case SB_BUS: + case JTAG_BUS: + return initvars_srom_sb (sbh, osh, curmap, vars, count); - case PCMCIA_BUS: - return initvars_cis_pcmcia(sbh, osh, vars, count); + case PCI_BUS: + ASSERT (curmap); /* can not be NULL */ + return initvars_srom_pci (sbh, curmap, vars, count); + case PCMCIA_BUS: + return initvars_cis_pcmcia (sbh, osh, vars, count); - default: - ASSERT(0); - } - return (-1); + + default: + ASSERT (0); + } + return (-1); } /* support only 16-bit word read from srom */ int -srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf) +srom_read (sb_t * sbh, uint bustype, void *curmap, osl_t * osh, + uint byteoff, uint nbytes, uint16 * buf) { - void *srom; - uint i, off, nw; - - ASSERT(bustype == BUSTYPE(bustype)); - - /* check input - 16-bit access only */ - if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) - return 1; - - off = byteoff / 2; - nw = nbytes / 2; - - if (BUSTYPE(bustype) == PCI_BUS) { - if (!curmap) - return 1; - srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET; - if (sprom_read_pci(osh, srom, off, buf, nw, FALSE)) - return 1; - } else if (BUSTYPE(bustype) == PCMCIA_BUS) { - for (i = 0; i < nw; i++) { - if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i))) - return 1; - } - } else { - return 1; + void *srom; + uint i, off, nw; + + ASSERT (bustype == BUSTYPE (bustype)); + + /* check input - 16-bit access only */ + if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) + return 1; + + off = byteoff / 2; + nw = nbytes / 2; + + if (BUSTYPE (bustype) == PCI_BUS) + { + if (!curmap) + return 1; + srom = (uchar *) curmap + PCI_BAR0_SPROM_OFFSET; + if (sprom_read_pci (osh, srom, off, buf, nw, FALSE)) + return 1; + } + else if (BUSTYPE (bustype) == PCMCIA_BUS) + { + for (i = 0; i < nw; i++) + { + if (sprom_read_pcmcia + (osh, (uint16) (off + i), (uint16 *) (buf + i))) + return 1; } + } + else if (BUSTYPE (bustype) == SB_BUS) + { +#ifdef BCMUSBDEV + if (SPROMBUS == PCMCIA_BUS) + { + uint origidx; + void *regs; + int rc; + bool wasup; + + origidx = sb_coreidx (sbh); + regs = sb_setcore (sbh, SB_PCMCIA, 0); + ASSERT (regs != NULL); + + if (!(wasup = sb_iscoreup (sbh))) + sb_core_reset (sbh, 0, 0); + + rc = get_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes); + + if (!wasup) + sb_core_disable (sbh, 0); + + sb_setcoreidx (sbh, origidx); + return rc; + } +#endif /* def BCMUSBDEV */ - return 0; + return 1; + } + else + { + return 1; + } + + return 0; } /* support only 16-bit word write into srom */ int -srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf) +srom_write (sb_t * sbh, uint bustype, void *curmap, osl_t * osh, + uint byteoff, uint nbytes, uint16 * buf) { - uint16 *srom; - uint i, nw, crc_range; - uint16 image[SPROM_SIZE]; - uint8 crc; - volatile uint32 val32; - - ASSERT(bustype == BUSTYPE(bustype)); - - /* check input - 16-bit access only */ - if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2)) - return 1; - - /* Are we writing the whole thing at once? */ - if ((byteoff == 0) && - ((nbytes == SPROM_SIZE) || - (nbytes == (SPROM_CRC_RANGE * 2)) || - (nbytes == (SROM4_WORDS * 2)))) { - crc_range = nbytes; - bcopy((void*)buf, (void*)image, nbytes); - nw = nbytes / 2; - } else { - if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS)) - crc_range = SPROM_SIZE; - else - crc_range = SPROM_CRC_RANGE * 2; /* Tentative */ - - nw = crc_range / 2; - /* read first 64 words from srom */ - if (srom_read(bustype, curmap, osh, 0, crc_range, image)) - return 1; - if (image[SROM4_SIGN] == SROM4_SIGNATURE) { - crc_range = SROM4_WORDS; - nw = crc_range / 2; - if (srom_read(bustype, curmap, osh, 0, crc_range, image)) - return 1; - } - /* make changes */ - bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes); + uint16 *srom; + uint i, nw, crc_range; + uint16 image[SPROM_SIZE]; + uint8 crc; + volatile uint32 val32; + + ASSERT (bustype == BUSTYPE (bustype)); + + /* check input - 16-bit access only */ + if ((byteoff & 1) || (nbytes & 1)) + return 1; + + if (byteoff == 0x55aa) + { + /* Erase request */ + crc_range = 0; + memset ((void *) image, 0xff, nbytes); + nw = nbytes / 2; + } + else if ((byteoff == 0) && + ((nbytes == SPROM_SIZE * 2) || + (nbytes == (SPROM_CRC_RANGE * 2)) || + (nbytes == (SROM4_WORDS * 2)))) + { + /* Are we writing the whole thing at once? */ + crc_range = nbytes; + bcopy ((void *) buf, (void *) image, nbytes); + nw = nbytes / 2; + } + else + { + if ((byteoff + nbytes) > (SPROM_SIZE * 2)) + return 1; + + if (BUSTYPE (bustype) == PCMCIA_BUS) + { + crc_range = SPROM_SIZE * 2; + } + else + { + crc_range = SPROM_CRC_RANGE * 2; /* Tentative */ } - /* calculate crc */ - htol16_buf(image, crc_range); - crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE); - ltoh16_buf(image, crc_range); - image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff); - - if (BUSTYPE(bustype) == PCI_BUS) { - srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET); - /* enable writes to the SPROM */ - val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); - val32 |= SPROM_WRITEEN; - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32); - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - for (i = 0; i < nw; i++) { - W_REG(osh, &srom[i], image[i]); - bcm_mdelay(WRITE_WORD_DELAY); - } - /* disable writes to the SPROM */ - OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & - ~SPROM_WRITEEN); - } else if (BUSTYPE(bustype) == PCMCIA_BUS) { - /* enable writes to the SPROM */ - if (sprom_cmd_pcmcia(osh, SROM_WEN)) - return 1; - bcm_mdelay(WRITE_ENABLE_DELAY); - /* write srom */ - for (i = 0; i < nw; i++) { - sprom_write_pcmcia(osh, (uint16)(i), image[i]); - bcm_mdelay(WRITE_WORD_DELAY); - } - /* disable writes to the SPROM */ - if (sprom_cmd_pcmcia(osh, SROM_WDS)) - return 1; - } else { - return 1; + nw = crc_range / 2; + /* read first 64 words from srom */ + if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image)) + return 1; + if (image[SROM4_SIGN] == SROM4_SIGNATURE) + { + nw = SROM4_WORDS; + crc_range = nw * 2; + if (srom_read (sbh, bustype, curmap, osh, 0, crc_range, image)) + return 1; + } + /* make changes */ + bcopy ((void *) buf, (void *) &image[byteoff / 2], nbytes); + } + + if (crc_range) + { + /* calculate crc */ + htol16_buf (image, crc_range); + crc = ~hndcrc8 ((uint8 *) image, crc_range - 1, 0xff); + ltoh16_buf (image, crc_range); + image[nw - 1] = (crc << 8) | (image[nw - 1] & 0xff); + } + + if (BUSTYPE (bustype) == PCI_BUS) + { + srom = (uint16 *) ((uchar *) curmap + PCI_BAR0_SPROM_OFFSET); + /* enable writes to the SPROM */ + val32 = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32)); + val32 |= SPROM_WRITEEN; + OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32); + bcm_mdelay (WRITE_ENABLE_DELAY); + /* write srom */ + for (i = 0; i < nw; i++) + { + W_REG (osh, &srom[i], image[i]); + bcm_mdelay (WRITE_WORD_DELAY); + } + /* disable writes to the SPROM */ + OSL_PCI_WRITE_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32), val32 & + ~SPROM_WRITEEN); + } + else if (BUSTYPE (bustype) == PCMCIA_BUS) + { + /* enable writes to the SPROM */ + if (sprom_cmd_pcmcia (osh, SROM_WEN)) + return 1; + bcm_mdelay (WRITE_ENABLE_DELAY); + /* write srom */ + for (i = 0; i < nw; i++) + { + sprom_write_pcmcia (osh, (uint16) (i), image[i]); + bcm_mdelay (WRITE_WORD_DELAY); } + /* disable writes to the SPROM */ + if (sprom_cmd_pcmcia (osh, SROM_WDS)) + return 1; + } + else if (BUSTYPE (bustype) == SB_BUS) + { +#ifdef BCMUSBDEV + if (SPROMBUS == PCMCIA_BUS) + { + uint origidx; + void *regs; + int rc; + bool wasup; + + origidx = sb_coreidx (sbh); + regs = sb_setcore (sbh, SB_PCMCIA, 0); + ASSERT (regs != NULL); + + if (!(wasup = sb_iscoreup (sbh))) + sb_core_reset (sbh, 0, 0); + + rc = set_sb_pcmcia_srom (sbh, osh, regs, byteoff, buf, nbytes); + + if (!wasup) + sb_core_disable (sbh, 0); + + sb_setcoreidx (sbh, origidx); + return rc; + } +#endif /* def BCMUSBDEV */ + return 1; + } + else + { + return 1; + } + + bcm_mdelay (WRITE_ENABLE_DELAY); + return 0; +} + +#ifdef BCMUSBDEV +#define SB_PCMCIA_READ(osh, regs, fcr) \ + R_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2) +#define SB_PCMCIA_WRITE(osh, regs, fcr, v) \ + W_REG(osh, (volatile uint8 *)(regs) + 0x600 + (fcr) - 0x700 / 2, v) + +/* set PCMCIA srom command register */ +static int +srom_cmd_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint8 cmd) +{ + uint8 status = 0; + uint wait_cnt = 0; + + /* write srom command register */ + SB_PCMCIA_WRITE (osh, pcmregs, SROM_CS, cmd); - bcm_mdelay(WRITE_ENABLE_DELAY); + /* wait status */ + while (++wait_cnt < 1000000) + { + status = SB_PCMCIA_READ (osh, pcmregs, SROM_CS); + if (status & SROM_DONE) return 0; + OSL_DELAY (1); + } + + BS_ERROR (("sr_cmd: Give up after %d tries, stat = 0x%x\n", wait_cnt, + status)); + return 1; } +/* read a word from the PCMCIA srom over SB */ +static int +srom_read_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 * data) +{ + uint8 addr_l, addr_h, data_l, data_h; + + addr_l = (uint8) ((addr * 2) & 0xff); + addr_h = (uint8) (((addr * 2) >> 8) & 0xff); + + /* set address */ + SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h); + SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l); + /* do read */ + if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_READ)) + return 1; + + /* read data */ + data_h = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAH); + data_l = SB_PCMCIA_READ (osh, pcmregs, SROM_DATAL); + *data = ((uint16) data_h << 8) | data_l; + + return 0; +} + +/* write a word to the PCMCIA srom over SB */ static int -srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count) +srom_write_sb_pcmcia (osl_t * osh, uint8 * pcmregs, uint16 addr, uint16 data) { - char eabuf[32]; - char *vp, *base; - uint8 *cis, tup, tlen, sromrev = 1; - int i, j; - uint varsize; - bool ag_init = FALSE; - uint32 w32; - - ASSERT(vars); - ASSERT(count); - - base = vp = MALLOC(osh, VARS_MAX); - ASSERT(vp); - if (!vp) - return -2; - - while (ciscnt--) { - cis = *pcis++; - i = 0; - do { - tup = cis[i++]; - tlen = cis[i++]; - if ((i + tlen) >= CIS_SIZE) - break; - - switch (tup) { - case CISTPL_MANFID: - vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]); - vp++; - vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]); - vp++; - break; - - case CISTPL_FUNCE: - switch (cis[i]) { - case LAN_NID: - ASSERT(cis[i + 1] == 6); - bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], eabuf); - vp += sprintf(vp, "il0macaddr=%s", eabuf); - vp++; - break; - case 1: /* SDIO Extended Data */ - vp += sprintf(vp, "sdmaxblk=%d", - (cis[i + 13] << 8) | cis[i + 12]); - vp++; - break; - } - break; - - case CISTPL_CFTABLE: - vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]); - vp++; - break; - - case CISTPL_BRCM_HNBU: - switch (cis[i]) { - case HNBU_SROMREV: - sromrev = cis[i + 1]; - break; - - case HNBU_CHIPID: - vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) + - cis[i + 1]); - vp++; - vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) + - cis[i + 3]); - vp++; - if (tlen == 7) { - vp += sprintf(vp, "chiprev=%d", - (cis[i + 6] << 8) + cis[i + 5]); - vp++; - } - break; - - case HNBU_BOARDREV: - vp += sprintf(vp, "boardrev=%d", cis[i + 1]); - vp++; - break; - - case HNBU_AA: - vp += sprintf(vp, "aa2g=%d", cis[i + 1]); - vp++; - break; - - case HNBU_AG: - vp += sprintf(vp, "ag0=%d", cis[i + 1]); - vp++; - ag_init = TRUE; - break; - - case HNBU_CC: - ASSERT(sromrev == 1); - vp += sprintf(vp, "cc=%d", cis[i + 1]); - vp++; - break; - - case HNBU_PAPARMS: - if (tlen == 2) { - ASSERT(sromrev == 1); - vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 1]); - vp++; - } else if (tlen >= 9) { - if (tlen == 10) { - ASSERT(sromrev == 2); - vp += sprintf(vp, "opo=%d", cis[i + 9]); - vp++; - } else - ASSERT(tlen == 9); - - for (j = 0; j < 3; j++) { - vp += sprintf(vp, "pa0b%d=%d", j, - (cis[i + (j * 2) + 2] << 8) + - cis[i + (j * 2) + 1]); - vp++; - } - vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]); - vp++; - vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 8]); - vp++; - } else - ASSERT(tlen >= 9); - break; - - case HNBU_OEM: - ASSERT(sromrev == 1); - vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x", - cis[i + 1], cis[i + 2], - cis[i + 3], cis[i + 4], - cis[i + 5], cis[i + 6], - cis[i + 7], cis[i + 8]); - vp++; - break; - - case HNBU_BOARDFLAGS: - w32 = (cis[i + 2] << 8) + cis[i + 1]; - if (tlen == 5) - w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16); - vp += sprintf(vp, "boardflags=0x%x", w32); - vp++; - break; - - case HNBU_LEDS: - if (cis[i + 1] != 0xff) { - vp += sprintf(vp, "ledbh0=%d", cis[i + 1]); - vp++; - } - if (cis[i + 2] != 0xff) { - vp += sprintf(vp, "ledbh1=%d", cis[i + 2]); - vp++; - } - if (cis[i + 3] != 0xff) { - vp += sprintf(vp, "ledbh2=%d", cis[i + 3]); - vp++; - } - if (cis[i + 4] != 0xff) { - vp += sprintf(vp, "ledbh3=%d", cis[i + 4]); - vp++; - } - break; - - case HNBU_CCODE: - { - char str[3]; - ASSERT(sromrev > 1); - str[0] = cis[i + 1]; - str[1] = cis[i + 2]; - str[2] = 0; - vp += sprintf(vp, "ccode=%s", str); - vp++; - vp += sprintf(vp, "cctl=0x%x", cis[i + 3]); - vp++; - break; - } - - case HNBU_CCKPO: - ASSERT(sromrev > 2); - vp += sprintf(vp, "cckpo=0x%x", - (cis[i + 2] << 8) | cis[i + 1]); - vp++; - break; - - case HNBU_OFDMPO: - ASSERT(sromrev > 2); - vp += sprintf(vp, "ofdmpo=0x%x", - (cis[i + 4] << 24) | - (cis[i + 3] << 16) | - (cis[i + 2] << 8) | - cis[i + 1]); - vp++; - break; - } - break; + uint8 addr_l, addr_h, data_l, data_h; + int rc; - } - i += tlen; - } while (tup != 0xff); + addr_l = (uint8) ((addr * 2) & 0xff); + addr_h = (uint8) (((addr * 2) >> 8) & 0xff); + + /* set address */ + SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRH, addr_h); + SB_PCMCIA_WRITE (osh, pcmregs, SROM_ADDRL, addr_l); + + data_l = (uint8) (data & 0xff); + data_h = (uint8) ((data >> 8) & 0xff); + + /* write data */ + SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAH, data_h); + SB_PCMCIA_WRITE (osh, pcmregs, SROM_DATAL, data_l); + + /* do write */ + rc = srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WRITE); + OSL_DELAY (20000); + return rc; +} + +/* + * Read the srom for the pcmcia-srom over sb case. + * Return 0 on success, nonzero on error. + */ +static int +get_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs, + uint boff, uint16 * srom, uint bsz) +{ + uint i, nw, woff, wsz; + int err = 0; + + /* read must be at word boundary */ + ASSERT ((boff & 1) == 0 && (bsz & 1) == 0); + + /* read sprom size and validate the parms */ + if ((nw = srom_size (sbh, osh)) == 0) + { + BS_ERROR (("get_sb_pcmcia_srom: sprom size unknown\n")); + err = -1; + goto out; + } + if (boff + bsz > 2 * nw) + { + BS_ERROR (("get_sb_pcmcia_srom: sprom size exceeded\n")); + err = -2; + goto out; + } + + /* read in sprom contents */ + for (woff = boff / 2, wsz = bsz / 2, i = 0; + woff < nw && i < wsz; woff++, i++) + { + if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &srom[i])) + { + BS_ERROR (("get_sb_pcmcia_srom: sprom read failed\n")); + err = -3; + goto out; } + } - /* Set the srom version */ - vp += sprintf(vp, "sromrev=%d", sromrev); - vp++; +out: + return err; +} - /* if there is no antenna gain field, set default */ - if (ag_init == FALSE) { - ASSERT(sromrev == 1); - vp += sprintf(vp, "ag0=%d", 0xff); - vp++; +/* + * Write the srom for the pcmcia-srom over sb case. + * Return 0 on success, nonzero on error. + */ +static int +set_sb_pcmcia_srom (sb_t * sbh, osl_t * osh, uint8 * pcmregs, + uint boff, uint16 * srom, uint bsz) +{ + uint i, nw, woff, wsz; + uint16 word; + uint8 crc; + int err = 0; + + /* write must be at word boundary */ + ASSERT ((boff & 1) == 0 && (bsz & 1) == 0); + + /* read sprom size and validate the parms */ + if ((nw = srom_size (sbh, osh)) == 0) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom size unknown\n")); + err = -1; + goto out; + } + if (boff + bsz > 2 * nw) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom size exceeded\n")); + err = -2; + goto out; + } + + /* enable write */ + if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WEN)) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom wen failed\n")); + err = -3; + goto out; + } + + /* write buffer to sprom */ + for (woff = boff / 2, wsz = bsz / 2, i = 0; + woff < nw && i < wsz; woff++, i++) + { + if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) woff, srom[i])) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom write failed\n")); + err = -4; + goto out; + } + } + + /* fix crc */ + crc = 0xff; + for (woff = 0; woff < nw; woff++) + { + if (srom_read_sb_pcmcia (osh, pcmregs, (uint16) woff, &word)) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc read failed\n")); + err = -5; + goto out; } + word = htol16 (word); + crc = hndcrc8 ((uint8 *) & word, woff != nw - 1 ? 2 : 1, crc); + } + word = (~crc << 8) + (ltoh16 (word) & 0xff); + if (srom_write_sb_pcmcia (osh, pcmregs, (uint16) (woff - 1), word)) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom fix crc write failed\n")); + err = -6; + goto out; + } + + /* disable write */ + if (srom_cmd_sb_pcmcia (osh, pcmregs, SROM_WDS)) + { + BS_ERROR (("set_sb_pcmcia_srom: sprom wds failed\n")); + err = -7; + goto out; + } + +out: + return err; +} +#endif /* def BCMUSBDEV */ - /* final nullbyte terminator */ - *vp++ = '\0'; - varsize = (uint)(vp - base); - - ASSERT((vp - base) < VARS_MAX); - - if (varsize == VARS_MAX) { - *vars = base; - } else { - vp = MALLOC(osh, varsize); - ASSERT(vp); - if (vp) - bcopy(base, vp, varsize); - MFREE(osh, base, VARS_MAX); - *vars = vp; - if (!vp) { - *count = 0; - return -2; +int +srom_parsecis (osl_t * osh, uint8 * pcis[], uint ciscnt, char **vars, + uint * count) +{ + char eabuf[32]; + char *base; + varbuf_t b; + uint8 *cis, tup, tlen, sromrev = 1; + int i, j; + uint varsize; + bool ag_init = FALSE; + uint32 w32; + uint funcid; + uint cisnum; + int32 boardnum = -1; + + ASSERT (vars); + ASSERT (count); + + base = MALLOC (osh, MAXSZ_NVRAM_VARS); + ASSERT (base); + if (!base) + return -2; + + varbuf_init (&b, base, MAXSZ_NVRAM_VARS); + + eabuf[0] = '\0'; + for (cisnum = 0; cisnum < ciscnt; cisnum++) + { + cis = *pcis++; + i = 0; + funcid = 0; + do + { + tup = cis[i++]; + tlen = cis[i++]; + if ((i + tlen) >= CIS_SIZE) + break; + + switch (tup) + { + case CISTPL_VERS_1: + /* assume the strings are good if the version field checks out */ + if (((cis[i + 1] << 8) + cis[i]) >= 0x0008) + { + varbuf_append (&b, "manf=%s", &cis[i + 2]); + varbuf_append (&b, "productname=%s", + &cis[i + 3 + strlen ((char *) &cis[i + 2])]); + break; } + + case CISTPL_MANFID: + varbuf_append (&b, "manfid=0x%x", (cis[i + 1] << 8) + cis[i]); + varbuf_append (&b, "prodid=0x%x", + (cis[i + 3] << 8) + cis[i + 2]); + break; + + case CISTPL_FUNCID: + funcid = cis[i]; + break; + + case CISTPL_FUNCE: + switch (funcid) + { + default: + /* set macaddr if HNBU_MACADDR not seen yet */ + if (eabuf[0] == '\0' && cis[i] == LAN_NID) + { + ASSERT (cis[i + 1] == ETHER_ADDR_LEN); + bcm_ether_ntoa ((struct ether_addr *) &cis[i + 2], + eabuf); + } + /* set boardnum if HNBU_BOARDNUM not seen yet */ + if (boardnum == -1) + boardnum = (cis[i + 6] << 8) + cis[i + 7]; + break; + } + break; + + case CISTPL_CFTABLE: + varbuf_append (&b, "regwindowsz=%d", + (cis[i + 7] << 8) | cis[i + 6]); + break; + + case CISTPL_BRCM_HNBU: + switch (cis[i]) + { + case HNBU_SROMREV: + sromrev = cis[i + 1]; + varbuf_append (&b, "sromrev=%d", sromrev); + break; + + case HNBU_CHIPID: + varbuf_append (&b, "vendid=0x%x", (cis[i + 2] << 8) + + cis[i + 1]); + varbuf_append (&b, "devid=0x%x", (cis[i + 4] << 8) + + cis[i + 3]); + if (tlen >= 7) + { + varbuf_append (&b, "chiprev=%d", + (cis[i + 6] << 8) + cis[i + 5]); + } + if (tlen >= 9) + { + varbuf_append (&b, "subvendid=0x%x", + (cis[i + 8] << 8) + cis[i + 7]); + } + if (tlen >= 11) + { + varbuf_append (&b, "subdevid=0x%x", + (cis[i + 10] << 8) + cis[i + 9]); + /* subdevid doubles for boardtype */ + varbuf_append (&b, "boardtype=0x%x", + (cis[i + 10] << 8) + cis[i + 9]); + } + break; + + case HNBU_BOARDREV: + varbuf_append (&b, "boardrev=0x%x", cis[i + 1]); + break; + + case HNBU_AA: + varbuf_append (&b, "aa2g=%d", cis[i + 1]); + break; + + case HNBU_AG: + varbuf_append (&b, "ag0=%d", cis[i + 1]); + ag_init = TRUE; + break; + + case HNBU_ANT5G: + varbuf_append (&b, "aa5g=%d", cis[i + 1]); + varbuf_append (&b, "ag1=%d", cis[i + 2]); + break; + + case HNBU_CC: + ASSERT (sromrev == 1); + varbuf_append (&b, "cc=%d", cis[i + 1]); + break; + + case HNBU_PAPARMS: + if (tlen == 2) + { + ASSERT (sromrev == 1); + varbuf_append (&b, "pa0maxpwr=%d", cis[i + 1]); + } + else if (tlen >= 9) + { + if (tlen == 10) + { + ASSERT (sromrev >= 2); + varbuf_append (&b, "opo=%d", cis[i + 9]); + } + else + ASSERT (tlen == 9); + + for (j = 0; j < 3; j++) + { + varbuf_append (&b, "pa0b%d=%d", j, + (cis[i + (j * 2) + 2] << 8) + + cis[i + (j * 2) + 1]); + } + varbuf_append (&b, "pa0itssit=%d", cis[i + 7]); + varbuf_append (&b, "pa0maxpwr=%d", cis[i + 8]); + } + else + ASSERT (tlen >= 9); + break; + + case HNBU_PAPARMS5G: + ASSERT ((sromrev == 2) || (sromrev == 3)); + for (j = 0; j < 3; j++) + { + varbuf_append (&b, "pa1b%d=%d", j, + (cis[i + (j * 2) + 2] << 8) + + cis[i + (j * 2) + 1]); + } + for (j = 3; j < 6; j++) + { + varbuf_append (&b, "pa1lob%d=%d", j - 3, + (cis[i + (j * 2) + 2] << 8) + + cis[i + (j * 2) + 1]); + } + for (j = 6; j < 9; j++) + { + varbuf_append (&b, "pa1hib%d=%d", j - 6, + (cis[i + (j * 2) + 2] << 8) + + cis[i + (j * 2) + 1]); + } + varbuf_append (&b, "pa1itssit=%d", cis[i + 19]); + varbuf_append (&b, "pa1maxpwr=%d", cis[i + 20]); + varbuf_append (&b, "pa1lomaxpwr=%d", cis[i + 21]); + varbuf_append (&b, "pa1himaxpwr=%d", cis[i + 22]); + break; + + case HNBU_OEM: + ASSERT (sromrev == 1); + varbuf_append (&b, "oem=%02x%02x%02x%02x%02x%02x%02x%02x", + cis[i + 1], cis[i + 2], + cis[i + 3], cis[i + 4], + cis[i + 5], cis[i + 6], + cis[i + 7], cis[i + 8]); + break; + + case HNBU_BOARDFLAGS: + w32 = (cis[i + 2] << 8) + cis[i + 1]; + if (tlen == 5) + w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16); + varbuf_append (&b, "boardflags=0x%x", w32); + break; + + case HNBU_LEDS: + if (cis[i + 1] != 0xff) + { + varbuf_append (&b, "ledbh0=%d", cis[i + 1]); + } + if (cis[i + 2] != 0xff) + { + varbuf_append (&b, "ledbh1=%d", cis[i + 2]); + } + if (cis[i + 3] != 0xff) + { + varbuf_append (&b, "ledbh2=%d", cis[i + 3]); + } + if (cis[i + 4] != 0xff) + { + varbuf_append (&b, "ledbh3=%d", cis[i + 4]); + } + break; + + case HNBU_CCODE: + ASSERT (sromrev > 1); + if ((cis[i + 1] == 0) || (cis[i + 2] == 0)) + varbuf_append (&b, "ccode="); + else + varbuf_append (&b, "ccode=%c%c", cis[i + 1], cis[i + 2]); + varbuf_append (&b, "cctl=0x%x", cis[i + 3]); + break; + + case HNBU_CCKPO: + ASSERT (sromrev > 2); + varbuf_append (&b, "cckpo=0x%x", + (cis[i + 2] << 8) | cis[i + 1]); + break; + + case HNBU_OFDMPO: + ASSERT (sromrev > 2); + varbuf_append (&b, "ofdmpo=0x%x", + (cis[i + 4] << 24) | + (cis[i + 3] << 16) | + (cis[i + 2] << 8) | cis[i + 1]); + break; + + case HNBU_RDLID: + varbuf_append (&b, "rdlid=0x%x", + (cis[i + 2] << 8) | cis[i + 1]); + break; + + case HNBU_RDLRNDIS: + varbuf_append (&b, "rdlrndis=%d", cis[i + 1]); + break; + + case HNBU_RDLRWU: + varbuf_append (&b, "rdlrwu=%d", cis[i + 1]); + break; + + case HNBU_RDLSN: + varbuf_append (&b, "rdlsn=%d", + (cis[i + 2] << 8) | cis[i + 1]); + break; + + case HNBU_XTALFREQ: + varbuf_append (&b, "xtalfreq=%d", + (cis[i + 4] << 24) | + (cis[i + 3] << 16) | + (cis[i + 2] << 8) | cis[i + 1]); + break; + + case HNBU_RSSISMBXA2G: + ASSERT (sromrev == 3); + varbuf_append (&b, "rssismf2g=%d", cis[i + 1] & 0xf); + varbuf_append (&b, "rssismc2g=%d", (cis[i + 1] >> 4) & 0xf); + varbuf_append (&b, "rssisav2g=%d", cis[i + 2] & 0x7); + varbuf_append (&b, "bxa2g=%d", (cis[i + 2] >> 3) & 0x3); + break; + + case HNBU_RSSISMBXA5G: + ASSERT (sromrev == 3); + varbuf_append (&b, "rssismf5g=%d", cis[i + 1] & 0xf); + varbuf_append (&b, "rssismc5g=%d", (cis[i + 1] >> 4) & 0xf); + varbuf_append (&b, "rssisav5g=%d", cis[i + 2] & 0x7); + varbuf_append (&b, "bxa5g=%d", (cis[i + 2] >> 3) & 0x3); + break; + + case HNBU_TRI2G: + ASSERT (sromrev == 3); + varbuf_append (&b, "tri2g=%d", cis[i + 1]); + break; + + case HNBU_TRI5G: + ASSERT (sromrev == 3); + varbuf_append (&b, "tri5gl=%d", cis[i + 1]); + varbuf_append (&b, "tri5g=%d", cis[i + 2]); + varbuf_append (&b, "tri5gh=%d", cis[i + 3]); + break; + + case HNBU_RXPO2G: + ASSERT (sromrev == 3); + varbuf_append (&b, "rxpo2g=%d", cis[i + 1]); + break; + + case HNBU_RXPO5G: + ASSERT (sromrev == 3); + varbuf_append (&b, "rxpo5g=%d", cis[i + 1]); + break; + + case HNBU_BOARDNUM: + boardnum = (cis[i + 2] << 8) + cis[i + 1]; + break; + + case HNBU_MACADDR: + bcm_ether_ntoa ((struct ether_addr *) &cis[i + 1], eabuf); + break; + + case HNBU_BOARDTYPE: + varbuf_append (&b, "boardtype=0x%x", + (cis[i + 2] << 8) + cis[i + 1]); + break; + +#if defined(BCMCCISSR3) + case HNBU_SROM3SWRGN: + { + uint16 srom[35]; + uint8 srev = cis[i + 1 + 70]; + ASSERT (srev == 3); + /* make tuple value 16-bit aligned and parse it */ + bcopy (&cis[i + 1], srom, sizeof (srom)); + _initvars_srom_pci (srev, srom, SROM3_SWRGN_OFF, &b); + /* create extra variables */ + varbuf_append (&b, "vendid=0x%x", + (cis[i + 1 + 73] << 8) + cis[i + 1 + 72]); + varbuf_append (&b, "devid=0x%x", + (cis[i + 1 + 75] << 8) + cis[i + 1 + 74]); + varbuf_append (&b, "xtalfreq=%d", + (cis[i + 1 + 77] << 8) + cis[i + 1 + 76]); + /* 2.4G antenna gain is included in SROM */ + ag_init = TRUE; + /* Ethernet MAC address is included in SROM */ + eabuf[0] = 0; + boardnum = -1; + break; + } +#endif + } + break; + } + i += tlen; } - *count = varsize; + while (tup != CISTPL_END); + } + + if (boardnum != -1) + { + varbuf_append (&b, "boardnum=%d", boardnum); + } + + if (eabuf[0]) + { + varbuf_append (&b, "macaddr=%s", eabuf); + } + + /* if there is no antenna gain field, set default */ + if (ag_init == FALSE) + { + varbuf_append (&b, "ag0=%d", 0xff); + } + + /* final nullbyte terminator */ + ASSERT (b.size >= 1); + *b.buf++ = '\0'; + varsize = (uint) (b.buf - base); + ASSERT (varsize < MAXSZ_NVRAM_VARS); + if (varsize < MAXSZ_NVRAM_VARS) + { + char *new_buf; + new_buf = (char *) MALLOC (osh, varsize); + ASSERT (new_buf); + if (new_buf) + { + bcopy (base, new_buf, varsize); + MFREE (osh, base, MAXSZ_NVRAM_VARS); + base = new_buf; + } + } + + *vars = base; + *count = varsize; - return (0); + return (0); } /* set PCMCIA sprom command register */ static int -sprom_cmd_pcmcia(osl_t *osh, uint8 cmd) +sprom_cmd_pcmcia (osl_t * osh, uint8 cmd) { - uint8 status = 0; - uint wait_cnt = 1000; + uint8 status = 0; + uint wait_cnt = 1000; - /* write sprom command register */ - OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1); + /* write sprom command register */ + OSL_PCMCIA_WRITE_ATTR (osh, SROM_CS, &cmd, 1); - /* wait status */ - while (wait_cnt--) { - OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1); - if (status & SROM_DONE) - return 0; - } + /* wait status */ + while (wait_cnt--) + { + OSL_PCMCIA_READ_ATTR (osh, SROM_CS, &status, 1); + if (status & SROM_DONE) + return 0; + } - return 1; + return 1; } /* read a word from the PCMCIA srom */ static int -sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data) +sprom_read_pcmcia (osl_t * osh, uint16 addr, uint16 * data) { - uint8 addr_l, addr_h, data_l, data_h; + uint8 addr_l, addr_h, data_l, data_h; - addr_l = (uint8)((addr * 2) & 0xff); - addr_h = (uint8)(((addr * 2) >> 8) & 0xff); + addr_l = (uint8) ((addr * 2) & 0xff); + addr_h = (uint8) (((addr * 2) >> 8) & 0xff); - /* set address */ - OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); - OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); + /* set address */ + OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1); + OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1); - /* do read */ - if (sprom_cmd_pcmcia(osh, SROM_READ)) - return 1; + /* do read */ + if (sprom_cmd_pcmcia (osh, SROM_READ)) + return 1; - /* read data */ - data_h = data_l = 0; - OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1); - OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1); + /* read data */ + data_h = data_l = 0; + OSL_PCMCIA_READ_ATTR (osh, SROM_DATAH, &data_h, 1); + OSL_PCMCIA_READ_ATTR (osh, SROM_DATAL, &data_l, 1); - *data = (data_h << 8) | data_l; - return 0; + *data = (data_h << 8) | data_l; + return 0; } /* write a word to the PCMCIA srom */ static int -sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data) +sprom_write_pcmcia (osl_t * osh, uint16 addr, uint16 data) { - uint8 addr_l, addr_h, data_l, data_h; + uint8 addr_l, addr_h, data_l, data_h; - addr_l = (uint8)((addr * 2) & 0xff); - addr_h = (uint8)(((addr * 2) >> 8) & 0xff); - data_l = (uint8)(data & 0xff); - data_h = (uint8)((data >> 8) & 0xff); + addr_l = (uint8) ((addr * 2) & 0xff); + addr_h = (uint8) (((addr * 2) >> 8) & 0xff); + data_l = (uint8) (data & 0xff); + data_h = (uint8) ((data >> 8) & 0xff); - /* set address */ - OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1); - OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1); + /* set address */ + OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRH, &addr_h, 1); + OSL_PCMCIA_WRITE_ATTR (osh, SROM_ADDRL, &addr_l, 1); - /* write data */ - OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1); - OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1); + /* write data */ + OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAH, &data_h, 1); + OSL_PCMCIA_WRITE_ATTR (osh, SROM_DATAL, &data_l, 1); - /* do write */ - return sprom_cmd_pcmcia(osh, SROM_WRITE); + /* do write */ + return sprom_cmd_pcmcia (osh, SROM_WRITE); } /* @@ -511,25 +1050,43 @@ sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data) * Return 0 on success, nonzero on error. */ static int -sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc) +sprom_read_pci (osl_t * osh, uint16 * sprom, uint wordoff, uint16 * buf, + uint nwords, bool check_crc) { - int err = 0; - uint i; - - /* read the sprom */ - for (i = 0; i < nwords; i++) - buf[i] = R_REG(osh, &sprom[wordoff + i]); - - if (check_crc) { - /* fixup the endianness so crc8 will pass */ - htol16_buf(buf, nwords * 2); - if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE) - err = 1; - /* now correct the endianness of the byte array */ - ltoh16_buf(buf, nwords * 2); + int err = 0; + uint i; + + /* read the sprom */ + for (i = 0; i < nwords; i++) + { +#ifdef BCMQT + buf[i] = R_REG (osh, &sprom[wordoff + i]); +#endif + buf[i] = R_REG (osh, &sprom[wordoff + i]); + } + + if (check_crc) + { + if (buf[0] == 0xffff) + { + /* The hardware thinks that an srom that starts with 0xffff + * is blank, regardless of the rest of the content, so declare + * it bad. + */ + BS_ERROR (("%s: buf[0] = 0x%x, returning bad-crc\n", __FUNCTION__, + buf[0])); + return 1; } - return err; + /* fixup the endianness so crc8 will pass */ + htol16_buf (buf, nwords * 2); + if (hndcrc8 ((uint8 *) buf, nwords * 2, 0xff) != 0x9f) + err = 1; + /* now correct the endianness of the byte array */ + ltoh16_buf (buf, nwords * 2); + } + + return err; } /* @@ -537,26 +1094,29 @@ sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords * Return 0 on success, nonzero on error. */ static int -initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count) +BCMINITFN (initvars_table) (osl_t * osh, char *start, char *end, char **vars, + uint * count) { - int c = (int)(end - start); - - /* do it only when there is more than just the null string */ - if (c > 1) { - char *vp = MALLOC(osh, c); - ASSERT(vp); - if (!vp) - return BCME_NOMEM; - bcopy(start, vp, c); - *vars = vp; - *count = c; - } - else { - *vars = NULL; - *count = 0; - } - - return 0; + int c = (int) (end - start); + + /* do it only when there is more than just the null string */ + if (c > 1) + { + char *vp = MALLOC (osh, c); + ASSERT (vp); + if (!vp) + return BCME_NOMEM; + bcopy (start, vp, c); + *vars = vp; + *count = c; + } + else + { + *vars = NULL; + *count = 0; + } + + return 0; } /* @@ -565,617 +1125,763 @@ initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count) * Return 0 on success, nonzero on error. */ static int -initvars_flash(osl_t *osh, char **base, uint len, char *devpath) +initvars_flash (sb_t * sbh, osl_t * osh, char **base, uint len) { - char *vp = *base; - char *flash; - int err; - char *s; - uint l, dl, copy_len; - - /* allocate memory and read in flash */ - if (!(flash = MALLOC(osh, NVRAM_SPACE))) - return BCME_NOMEM; - if ((err = nvram_getall(flash, NVRAM_SPACE))) - goto exit; - - /* grab vars with the prefix in name */ - dl = strlen(devpath); - for (s = flash; s && *s; s += l + 1) { - l = strlen(s); - - /* skip non-matching variable */ - if (strncmp(s, devpath, dl)) - continue; - - /* is there enough room to copy? */ - copy_len = l - dl + 1; - if (len < copy_len) { - err = BCME_BUFTOOSHORT; - goto exit; - } - - /* no prefix, just the name=value */ - strcpy(vp, &s[dl]); - vp += copy_len; - len -= copy_len; + char *vp = *base; + char *flash; + int err; + char *s; + uint l, dl, copy_len; + char devpath[SB_DEVPATH_BUFSZ]; + + /* allocate memory and read in flash */ + if (!(flash = MALLOC (osh, NVRAM_SPACE))) + return BCME_NOMEM; + if ((err = nvram_getall (flash, NVRAM_SPACE))) + goto exit; + + sb_devpath (sbh, devpath, sizeof (devpath)); + + /* grab vars with the prefix in name */ + dl = strlen (devpath); + for (s = flash; s && *s; s += l + 1) + { + l = strlen (s); + + /* skip non-matching variable */ + if (strncmp (s, devpath, dl)) + continue; + + /* is there enough room to copy? */ + copy_len = l - dl + 1; + if (len < copy_len) + { + err = BCME_BUFTOOSHORT; + goto exit; } - /* add null string as terminator */ - if (len < 1) { - err = BCME_BUFTOOSHORT; - goto exit; - } - *vp++ = '\0'; + /* no prefix, just the name=value */ + strncpy (vp, &s[dl], copy_len); + vp += copy_len; + len -= copy_len; + } + + /* add null string as terminator */ + if (len < 1) + { + err = BCME_BUFTOOSHORT; + goto exit; + } + *vp++ = '\0'; - *base = vp; + *base = vp; -exit: MFREE(osh, flash, NVRAM_SPACE); - return err; +exit:MFREE (osh, flash, NVRAM_SPACE); + return err; } +#if !defined(BCMUSBDEV) && !defined(BCMSDIODEV) /* * Initialize nonvolatile variable table from flash. * Return 0 on success, nonzero on error. */ static int -initvars_flash_sb(void *sbh, char **vars, uint *count) +initvars_flash_sb (sb_t * sbh, char **vars, uint * count) { - osl_t *osh = sb_osh(sbh); - char devpath[SB_DEVPATH_BUFSZ]; - char *vp, *base; - int err; + osl_t *osh = sb_osh (sbh); + char *vp, *base; + int err; - ASSERT(vars); - ASSERT(count); + ASSERT (vars); + ASSERT (count); - if ((err = sb_devpath(sbh, devpath, sizeof(devpath)))) - return err; + base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS); + ASSERT (vp); + if (!vp) + return BCME_NOMEM; - base = vp = MALLOC(osh, VARS_MAX); - ASSERT(vp); - if (!vp) - return BCME_NOMEM; + if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS)) == 0) + err = initvars_table (osh, base, vp, vars, count); - if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath))) - goto err; + MFREE (osh, base, MAXSZ_NVRAM_VARS); - err = initvars_table(osh, base, vp, vars, count); - -err: MFREE(osh, base, VARS_MAX); - return err; + return err; } +#endif /* !BCMUSBDEV && !BCMSDIODEV */ #ifdef WLTEST char mfgsromvars[256]; char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0" - "et0macaddr=00:11:22:33:44:52\0" - "et1macaddr=00:11:22:33:44:53\0" - "boardtype=0xffff\0" - "boardrev=0x10\0" - "boardflags=8\0" - "sromrev=2\0" - "aa2g=3"; -#define MFGSROM_DEFVARSLEN 147 /* default srom len */ + "et0macaddr=00:11:22:33:44:52\0" + "et1macaddr=00:11:22:33:44:53\0" + "boardtype=0xffff\0" + "boardrev=0x10\0" "boardflags=8\0" "sromrev=2\0" "aa2g=3\0" "\0"; +#define MFGSROM_DEFVARSLEN 149 /* default srom len */ #endif /* WL_TEST */ /* * Initialize nonvolatile variable table from sprom. * Return 0 on success, nonzero on error. */ -static int -initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count) -{ - uint16 w, *b; - uint8 sromrev = 0; - struct ether_addr ea; - char eabuf[32]; - uint32 w32; - int woff, i; - char *vp, *base; - osl_t *osh = sb_osh(sbh); - bool flash = FALSE; - char name[SB_DEVPATH_BUFSZ+16], *value; - char devpath[SB_DEVPATH_BUFSZ]; - int err; - - /* - * Apply CRC over SROM content regardless SROM is present or not, - * and use variable sromrev's existance in flash to decide - * if we should return an error when CRC fails or read SROM variables - * from flash. - */ - b = MALLOC(osh, SROM_MAX); - ASSERT(b); - if (!b) - return -2; - - err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, - 64, TRUE); - if (b[SROM4_SIGN] == SROM4_SIGNATURE) { - /* sromrev >= 4, read more */ - err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, SROM4_WORDS, TRUE); - sromrev = b[SROM4_WORDS - 1] & 0xff; - } else if (err == 0) { - /* srom is good and is rev < 4 */ - /* top word of sprom contains version and crc8 */ - sromrev = b[63] & 0xff; - /* bcm4401 sroms misprogrammed */ - if (sromrev == 0x10) - sromrev = 1; - } - - if (err) { -#ifdef WLTEST - BS_ERROR(("SROM Crc Error, so see if we could use a default\n")); - w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32)); - if (w32 & SPROM_OTPIN_USE) { - BS_ERROR(("srom crc failed with OTP, use default vars....\n")); - vp = base = mfgsromvars; - if (sb_chip(sbh) == BCM4311_CHIP_ID) { - BS_ERROR(("setting the devid to be 4311\n")); - vp += sprintf(vp, "devid=0x4311"); - vp++; - } - bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN); - vp += MFGSROM_DEFVARSLEN; - goto varsdone; - } else { - BS_ERROR(("srom crc failed with SPROM....\n")); -#endif /* WLTEST */ - if ((err = sb_devpath(sbh, devpath, sizeof(devpath)))) - return err; - sprintf(name, "%ssromrev", devpath); - if (!(value = getvar(NULL, name))) - return (-1); - sromrev = (uint8)bcm_strtoul(value, NULL, 0); - flash = TRUE; -#ifdef WLTEST - } -#endif /* WLTEST */ - } - /* srom version check */ - if (sromrev > 4) - return (-2); - - ASSERT(vars); - ASSERT(count); - - base = vp = MALLOC(osh, VARS_MAX); - ASSERT(vp); - if (!vp) - return -2; - - /* read variables from flash */ - if (flash) { - if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath))) - goto err; - goto varsdone; - } - - vp += sprintf(vp, "sromrev=%d", sromrev); - vp++; - - if (sromrev >= 4) { - uint path, pathbase; - const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1, - SROM4_PATH2, SROM4_PATH3}; - - vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]); - vp++; - - vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]); - vp++; - - vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]); - vp++; - - /* The macaddr */ - ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff; - ea.octet[1] = b[SROM4_MACHI] & 0xff; - ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff; - ea.octet[3] = b[SROM4_MACMID] & 0xff; - ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff; - ea.octet[5] = b[SROM4_MACLO] & 0xff; - bcm_ether_ntoa(&ea, eabuf); - vp += sprintf(vp, "macaddr=%s", eabuf); - vp++; - - w = b[SROM4_CCODE]; - if (w == 0) - vp += sprintf(vp, "ccode="); - else - vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff)); - vp++; - vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]); - vp++; - - w = b[SROM4_LEDBH10]; - if ((w != 0) && (w != 0xffff)) { - /* ledbh0 */ - vp += sprintf(vp, "ledbh0=%d", (w & 0xff)); - vp++; - - /* ledbh1 */ - vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff); - vp++; - } - w = b[SROM4_LEDBH32]; - if ((w != 0) && (w != 0xffff)) { - /* ledbh2 */ - vp += sprintf(vp, "ledbh2=%d", w & 0xff); - vp++; - - /* ledbh3 */ - vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff); - vp++; - } - /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */ - if (w != 0xffff) { - w = b[SROM4_LEDDC]; - w32 = ((uint32)((unsigned char)(w >> 8) & 0xff) << 24) | /* oncount */ - ((uint32)((unsigned char)(w & 0xff)) << 8); /* offcount */ - vp += sprintf(vp, "leddc=%d", w32); - vp++; - } - - w = b[SROM4_AA]; - vp += sprintf(vp, "aa2g=%d", w & SROM4_AA2G_MASK); - vp++; - vp += sprintf(vp, "aa5g=%d", w >> SROM4_AA5G_SHIFT); - vp++; - - w = b[SROM4_AG10]; - vp += sprintf(vp, "ag0=%d", w & 0xff); - vp++; - vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff); - vp++; - w = b[SROM4_AG32]; - vp += sprintf(vp, "ag2=%d", w & 0xff); - vp++; - vp += sprintf(vp, "ag3=%d", (w >> 8) & 0xff); - vp++; - - /* Fixed power indices when power control is disabled */ - for (i = 0; i < 2; i++) { - w = b[SROM4_TXPID2G + i]; - vp += sprintf(vp, "txpid2ga%d=%d", 2 * i, w & 0xff); - vp++; - vp += sprintf(vp, "txpid2ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff); - vp++; - w = b[SROM4_TXPID5G + i]; - vp += sprintf(vp, "txpid5ga%d=%d", 2 * i, w & 0xff); - vp++; - vp += sprintf(vp, "txpid5ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff); - vp++; - w = b[SROM4_TXPID5GL + i]; - vp += sprintf(vp, "txpid5gla%d=%d", 2 * i, w & 0xff); - vp++; - vp += sprintf(vp, "txpid5gla%d=%d", (2 * i) + 1, (w >> 8) & 0xff); - vp++; - w = b[SROM4_TXPID5GH + i]; - vp += sprintf(vp, "txpid5gha%d=%d", 2 * i, w & 0xff); - vp++; - vp += sprintf(vp, "txpid5gha%d=%d", (2 * i) + 1, (w >> 8) & 0xff); - vp++; - } +typedef struct +{ + const char *name; + uint32 revmask; + uint32 flags; + uint16 off; + uint16 mask; +} sromvar_t; + +#define SRFL_MORE 1 /* value continues as described by the next entry */ +#define SRFL_NOFFS 2 /* value bits can't be all one's */ +#define SRFL_PRHEX 4 /* value is in hexdecimal format */ +#define SRFL_PRSIGN 8 /* value is in signed decimal format */ +#define SRFL_CCODE 0x10 /* value is in country code format */ +#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ +#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ + +/* Assumptions: + * - Ethernet address spins across 3 consective words + * + * Table rules: + * - Add multiple entries next to each other if a value spins across multiple words + * (even multiple fields in the same word) with each entry except the last having + * it's SRFL_MORE bit set. + * - Ethernet address entry does not follow above rule and must not have SRFL_MORE + * bit set. Its SRFL_ETHADDR bit implies it takes multiple words. + * - The last entry's name field must be NULL to indicate the end of the table. Other + * entries must have non-NULL name. + */ - /* Per path variables */ - for (path = 0; path < MAX_PATH; path++) { - pathbase = pathbases[path]; - w = b[pathbase + SROM4_2G_ITT_MAXP]; - vp += sprintf(vp, "itt2ga%d=%d", path, w >> B2G_ITT_SHIFT); - vp++; - vp += sprintf(vp, "maxp2ga%d=%d", path, w & B2G_MAXP_MASK); - vp++; - - for (i = 0; i < 4; i++) { - vp += sprintf(vp, "pa2gw%da%d=%d", i, path, - b[pathbase + SROM4_2G_PA + i]); - vp++; - } +static const sromvar_t pci_sromvars[] = { + {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, + {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM_BFL2, 0xffff}, + {"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM3_BFL2, 0xffff}, + {"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff}, + {"", 0, 0, SROM4_BFL1, 0xffff}, + {"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff}, + {"", 0, 0, SROM5_BFL1, 0xffff}, + {"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff}, + {"", 0, 0, SROM8_BFL1, 0xffff}, + {"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff}, + {"", 0, 0, SROM4_BFL3, 0xffff}, + {"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff}, + {"", 0, 0, SROM5_BFL3, 0xffff}, + {"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff}, + {"", 0, 0, SROM8_BFL3, 0xffff}, + {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, + {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, + {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff}, + {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, + {"regrev", 0x00000010, 0, SROM4_REGREV, 0xff}, + {"regrev", 0x000000e0, 0, SROM5_REGREV, 0xff}, + {"regrev", 0xffffff00, 0, SROM8_REGREV, 0xff}, + {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff}, + {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff}, + {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff}, + {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff}, + {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff}, + {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff}, + {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff}, + {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff}, + {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0xff}, + {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff}, + {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, + {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff}, + {"opo", 0x0000000c, 0, SROM_OPO, 0xff}, + {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0xff}, + {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {"aa2g", 0x000000f0, 0, SROM4_AA, 0xff}, + {"aa2g", 0xffffff00, 0, SROM8_AA, 0xff}, + {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, + {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00}, + {"ag0", 0x0000000e, 0, SROM_AG10, 0xff}, + {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, + {"ag0", 0x000000f0, 0, SROM4_AG10, 0xff}, + {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, + {"ag2", 0x000000f0, 0, SROM4_AG32, 0xff}, + {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, + {"ag0", 0xffffff00, 0, SROM8_AG10, 0xff}, + {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00}, + {"ag2", 0xffffff00, 0, SROM8_AG32, 0xff}, + {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00}, + {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, + {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff}, + {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, + {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff}, + {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff}, + {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, + {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, + {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, + {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, + {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, + {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, + {"tri2g", 0x00000008, 0, SROM_TRI52G, 0xff}, + {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, + {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0xff}, + {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0xff}, + {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00}, + {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0xff}, + {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, + {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff}, + {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff}, + {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, + {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, + {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0xff}, + {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff}, + {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, + {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0xff}, + {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff}, + {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, + {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0xff}, + {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff}, + {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, + {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0xff}, + {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff}, + {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, + {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {"cck2gpo", 0xffffff00, 0, SROM8_2G_CCKPO, 0xffff}, + {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, + {"ofdm2gpo", 0xffffff00, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, + {"ofdm5gpo", 0xffffff00, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, + {"ofdm5glpo", 0xffffff00, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, + {"ofdm5ghpo", 0xffffff00, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, + {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, + {"mcs2gpo0", 0xffffff00, 0, SROM8_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0xffffff00, 0, SROM8_2G_MCSPO + 1, 0xffff}, + {"mcs2gpo2", 0xffffff00, 0, SROM8_2G_MCSPO + 2, 0xffff}, + {"mcs2gpo3", 0xffffff00, 0, SROM8_2G_MCSPO + 3, 0xffff}, + {"mcs2gpo4", 0xffffff00, 0, SROM8_2G_MCSPO + 4, 0xffff}, + {"mcs2gpo5", 0xffffff00, 0, SROM8_2G_MCSPO + 5, 0xffff}, + {"mcs2gpo6", 0xffffff00, 0, SROM8_2G_MCSPO + 6, 0xffff}, + {"mcs2gpo7", 0xffffff00, 0, SROM8_2G_MCSPO + 7, 0xffff}, + {"mcs5gpo0", 0xffffff00, 0, SROM8_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0xffffff00, 0, SROM8_5G_MCSPO + 1, 0xffff}, + {"mcs5gpo2", 0xffffff00, 0, SROM8_5G_MCSPO + 2, 0xffff}, + {"mcs5gpo3", 0xffffff00, 0, SROM8_5G_MCSPO + 3, 0xffff}, + {"mcs5gpo4", 0xffffff00, 0, SROM8_5G_MCSPO + 4, 0xffff}, + {"mcs5gpo5", 0xffffff00, 0, SROM8_5G_MCSPO + 5, 0xffff}, + {"mcs5gpo6", 0xffffff00, 0, SROM8_5G_MCSPO + 6, 0xffff}, + {"mcs5gpo7", 0xffffff00, 0, SROM8_5G_MCSPO + 7, 0xffff}, + {"mcs5glpo0", 0xffffff00, 0, SROM8_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0xffffff00, 0, SROM8_5GL_MCSPO + 1, 0xffff}, + {"mcs5glpo2", 0xffffff00, 0, SROM8_5GL_MCSPO + 2, 0xffff}, + {"mcs5glpo3", 0xffffff00, 0, SROM8_5GL_MCSPO + 3, 0xffff}, + {"mcs5glpo4", 0xffffff00, 0, SROM8_5GL_MCSPO + 4, 0xffff}, + {"mcs5glpo5", 0xffffff00, 0, SROM8_5GL_MCSPO + 5, 0xffff}, + {"mcs5glpo6", 0xffffff00, 0, SROM8_5GL_MCSPO + 6, 0xffff}, + {"mcs5glpo7", 0xffffff00, 0, SROM8_5GL_MCSPO + 7, 0xffff}, + {"mcs5ghpo0", 0xffffff00, 0, SROM8_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0xffffff00, 0, SROM8_5GH_MCSPO + 1, 0xffff}, + {"mcs5ghpo2", 0xffffff00, 0, SROM8_5GH_MCSPO + 2, 0xffff}, + {"mcs5ghpo3", 0xffffff00, 0, SROM8_5GH_MCSPO + 3, 0xffff}, + {"mcs5ghpo4", 0xffffff00, 0, SROM8_5GH_MCSPO + 4, 0xffff}, + {"mcs5ghpo5", 0xffffff00, 0, SROM8_5GH_MCSPO + 5, 0xffff}, + {"mcs5ghpo6", 0xffffff00, 0, SROM8_5GH_MCSPO + 6, 0xffff}, + {"mcs5ghpo7", 0xffffff00, 0, SROM8_5GH_MCSPO + 7, 0xffff}, + {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {"cddpo", 0xffffff00, 0, SROM8_CDDPO, 0xffff}, + {"stbcpo", 0xffffff00, 0, SROM8_STBCPO, 0xffff}, + {"bw40po", 0xffffff00, 0, SROM8_BW40PO, 0xffff}, + {"bwduppo", 0xffffff00, 0, SROM8_BWDUPPO, 0xffff}, + {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, + {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, + {"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff}, + {"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff}, + {"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff}, + {"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff}, + {NULL, 0, 0, 0, 0} +}; + +static const sromvar_t perpath_pci_sromvars[] = { + {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff}, + {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, + {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, + {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff}, + {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff}, + {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, + {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, + {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff}, + {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff}, + {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff}, + {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff}, + {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff}, + {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, + {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, + {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff}, + {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff}, + {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, + {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, + {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff}, + {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff}, + {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff}, + {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff}, + {NULL, 0, 0, 0, 0} +}; + +/* Parse SROM and create name=value pairs. 'srom' points to + * the SROM word array. 'off' specifies the offset of the + * first word 'srom' points to, which should be either 0 or + * SROM3_SWRG_OFF (full SROM or software region). + */ - w = b[pathbase + SROM4_5G_ITT_MAXP]; - vp += sprintf(vp, "itt5ga%d=%d", path, w >> B5G_ITT_SHIFT); - vp++; - vp += sprintf(vp, "maxp5ga%d=%d", path, w & B5G_MAXP_MASK); - vp++; - - w = b[pathbase + SROM4_5GLH_MAXP]; - vp += sprintf(vp, "maxp5lga%d=%d", path, w >> B5GL_MAXP_SHIFT); - vp++; - vp += sprintf(vp, "maxp5gha%d=%d", path, w & B5GH_MAXP_MASK); - vp++; - - for (i = 0; i < 4; i++) { - vp += sprintf(vp, "pa5gw%da%d=%d", i, path, - b[pathbase + SROM4_5G_PA + i]); - vp++; - vp += sprintf(vp, "pa5glw%da%d=%d", i, path, - b[pathbase + SROM4_5GL_PA + i]); - vp++; - vp += sprintf(vp, "pa5hgw%da%d=%d", i, path, - b[pathbase + SROM4_5GH_PA + i]); - vp++; - } - } +static uint +mask_shift (uint16 mask) +{ + uint i; + for (i = 0; i < (sizeof (mask) << 3); i++) + { + if (mask & (1 << i)) + return i; + } + ASSERT (mask); + return 0; +} - vp += sprintf(vp, "cck2gpo=%d", b[SROM4_2G_CCKPO]); - vp++; - - w32 = ((uint32)b[SROM4_2G_OFDMPO + 1] << 16) | b[SROM4_2G_OFDMPO]; - vp += sprintf(vp, "ofdm2gpo=%d", w32); - vp++; - - w32 = ((uint32)b[SROM4_5G_OFDMPO + 1] << 16) | b[SROM4_5G_OFDMPO]; - vp += sprintf(vp, "ofdm5gpo=%d", w32); - vp++; - - w32 = ((uint32)b[SROM4_5GL_OFDMPO + 1] << 16) | b[SROM4_5GL_OFDMPO]; - vp += sprintf(vp, "ofdm5glpo=%d", w32); - vp++; - - w32 = ((uint32)b[SROM4_5GH_OFDMPO + 1] << 16) | b[SROM4_5GH_OFDMPO]; - vp += sprintf(vp, "ofdm5ghpo=%d", w32); - vp++; - - for (i = 0; i < 8; i++) { - vp += sprintf(vp, "mcs2gpo%d=%d", i, b[SROM4_2G_MCSPO]); - vp++; - vp += sprintf(vp, "mcs5gpo%d=%d", i, b[SROM4_5G_MCSPO]); - vp++; - vp += sprintf(vp, "mcs5glpo%d=%d", i, b[SROM4_5GL_MCSPO]); - vp++; - vp += sprintf(vp, "mcs5ghpo%d=%d", i, b[SROM4_5GH_MCSPO]); - vp++; - } +static uint +mask_width (uint16 mask) +{ + int i; + for (i = (sizeof (mask) << 3) - 1; i >= 0; i--) + { + if (mask & (1 << i)) + return (uint) (i - mask_shift (mask) + 1); + } + ASSERT (mask); + return 0; +} - vp += sprintf(vp, "ccdpo%d=%d", i, b[SROM4_CCDPO]); - vp++; - vp += sprintf(vp, "stbcpo%d=%d", i, b[SROM4_STBCPO]); - vp++; - vp += sprintf(vp, "bw40po%d=%d", i, b[SROM4_BW40PO]); - vp++; - vp += sprintf(vp, "bwduppo%d=%d", i, b[SROM4_BWDUPPO]); - vp++; +#ifdef BCMDBG_ASSERT +static bool +mask_valid (uint16 mask) +{ + uint shift = mask_shift (mask); + uint width = mask_width (mask); + return mask == ((~0 << shift) & ~(~0 << (shift + width))); +} +#endif - goto done; +static void +_initvars_srom_pci (uint8 sromrev, uint16 * srom, uint off, varbuf_t * b) +{ + uint16 w; + uint32 val; + const sromvar_t *srv; + uint width; + uint flags; + uint32 sr = (1 << sromrev); + + varbuf_append (b, "sromrev=%d", sromrev); + + for (srv = pci_sromvars; srv->name != NULL; srv++) + { + const char *name; + + if ((srv->revmask & sr) == 0) + continue; + + if (srv->off < off) + continue; + + flags = srv->flags; + name = srv->name; + + if (flags & SRFL_ETHADDR) + { + char eabuf[ETHER_ADDR_STR_LEN]; + struct ether_addr ea; + + ea.octet[0] = (srom[srv->off - off] >> 8) & 0xff; + ea.octet[1] = srom[srv->off - off] & 0xff; + ea.octet[2] = (srom[srv->off + 1 - off] >> 8) & 0xff; + ea.octet[3] = srom[srv->off + 1 - off] & 0xff; + ea.octet[4] = (srom[srv->off + 2 - off] >> 8) & 0xff; + ea.octet[5] = srom[srv->off + 2 - off] & 0xff; + bcm_ether_ntoa (&ea, eabuf); + + varbuf_append (b, "%s=%s", name, eabuf); } - if (sromrev >= 3) { - /* New section takes over the 3th hardware function space */ - - /* Words 22+23 are 11a (mid) ofdm power offsets */ - w32 = ((uint32)b[23] << 16) | b[22]; - vp += sprintf(vp, "ofdmapo=%d", w32); - vp++; - - /* Words 24+25 are 11a (low) ofdm power offsets */ - w32 = ((uint32)b[25] << 16) | b[24]; - vp += sprintf(vp, "ofdmalpo=%d", w32); - vp++; - - /* Words 26+27 are 11a (high) ofdm power offsets */ - w32 = ((uint32)b[27] << 16) | b[26]; - vp += sprintf(vp, "ofdmahpo=%d", w32); - vp++; - - /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */ - w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xff) << 24) | /* oncount */ - ((uint32)((unsigned char)(b[21] & 0xff)) << 8); /* offcount */ - vp += sprintf(vp, "leddc=%d", w32); - - vp++; + else + { + ASSERT (mask_valid (srv->mask)); + ASSERT (mask_width (srv->mask)); + + w = srom[srv->off - off]; + val = (w & srv->mask) >> mask_shift (srv->mask); + width = mask_width (srv->mask); + + while (srv->flags & SRFL_MORE) + { + srv++; + ASSERT (srv->name); + + if (srv->off == 0 || srv->off < off) + continue; + + ASSERT (mask_valid (srv->mask)); + ASSERT (mask_width (srv->mask)); + + w = srom[srv->off - off]; + val += ((w & srv->mask) >> mask_shift (srv->mask)) << width; + width += mask_width (srv->mask); + } + + if ((flags & SRFL_NOFFS) && ((int) val == (1 << width) - 1)) + continue; + + if (flags & SRFL_CCODE) + { + if (val == 0) + varbuf_append (b, "ccode="); + else + varbuf_append (b, "ccode=%c%c", (val >> 8), (val & 0xff)); + } + /* LED Powersave duty cycle has to be scaled: + *(oncount >> 24) (offcount >> 8) + */ + else if (flags & SRFL_LEDDC) + { + uint32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */ + (((val & 0xff)) << 8); /* offcount */ + varbuf_append (b, "leddc=%d", w32); + } + else if (flags & SRFL_PRHEX) + varbuf_append (b, "%s=0x%x", name, val); + else if ((flags & SRFL_PRSIGN) && (val & (1 << (width - 1)))) + varbuf_append (b, "%s=%d", name, (int) (val | (~0 << width))); + else + varbuf_append (b, "%s=%u", name, val); } + } - if (sromrev >= 2) { - /* New section takes over the 4th hardware function space */ - - /* Word 29 is max power 11a high/low */ - w = b[29]; - vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff); - vp++; - vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff); - vp++; - - /* Words 30-32 set the 11alow pa settings, - * 33-35 are the 11ahigh ones. - */ - for (i = 0; i < 3; i++) { - vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]); - vp++; - vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]); - vp++; - } - w = b[59]; - if (w == 0) - vp += sprintf(vp, "ccode="); - else - vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff)); - vp++; + if (sromrev >= 4) + { + /* Do per-path variables */ + uint p, pb, psz; + if (sromrev >= 8) + { + pb = SROM8_PATH0; + psz = SROM8_PATH1 - SROM8_PATH0; } - - /* parameter section of sprom starts at byte offset 72 */ - woff = 72/2; - - /* first 6 bytes are il0macaddr */ - ea.octet[0] = (b[woff] >> 8) & 0xff; - ea.octet[1] = b[woff] & 0xff; - ea.octet[2] = (b[woff+1] >> 8) & 0xff; - ea.octet[3] = b[woff+1] & 0xff; - ea.octet[4] = (b[woff+2] >> 8) & 0xff; - ea.octet[5] = b[woff+2] & 0xff; - woff += 3; - bcm_ether_ntoa(&ea, eabuf); - vp += sprintf(vp, "il0macaddr=%s", eabuf); - vp++; - - /* next 6 bytes are et0macaddr */ - ea.octet[0] = (b[woff] >> 8) & 0xff; - ea.octet[1] = b[woff] & 0xff; - ea.octet[2] = (b[woff+1] >> 8) & 0xff; - ea.octet[3] = b[woff+1] & 0xff; - ea.octet[4] = (b[woff+2] >> 8) & 0xff; - ea.octet[5] = b[woff+2] & 0xff; - woff += 3; - bcm_ether_ntoa(&ea, eabuf); - vp += sprintf(vp, "et0macaddr=%s", eabuf); - vp++; - - /* next 6 bytes are et1macaddr */ - ea.octet[0] = (b[woff] >> 8) & 0xff; - ea.octet[1] = b[woff] & 0xff; - ea.octet[2] = (b[woff+1] >> 8) & 0xff; - ea.octet[3] = b[woff+1] & 0xff; - ea.octet[4] = (b[woff+2] >> 8) & 0xff; - ea.octet[5] = b[woff+2] & 0xff; - woff += 3; - bcm_ether_ntoa(&ea, eabuf); - vp += sprintf(vp, "et1macaddr=%s", eabuf); - vp++; - - /* - * Enet phy settings one or two singles or a dual - * Bits 4-0 : MII address for enet0 (0x1f for not there) - * Bits 9-5 : MII address for enet1 (0x1f for not there) - * Bit 14 : Mdio for enet0 - * Bit 15 : Mdio for enet1 - */ - w = b[woff]; - vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f)); - vp++; - vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f)); - vp++; - vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1)); - vp++; - vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1)); - vp++; - - /* Word 46 has board rev, antennas 0/1 & Country code/control */ - w = b[46]; - vp += sprintf(vp, "boardrev=%d", w & 0xff); - vp++; - - if (sromrev > 1) - vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf); - else - vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf); - vp++; - - vp += sprintf(vp, "aa2g=%d", (w >> 12) & 0x3); - vp++; - - vp += sprintf(vp, "aa5g=%d", (w >> 14) & 0x3); - vp++; - - /* Words 47-49 set the (wl) pa settings */ - woff = 47; - - for (i = 0; i < 3; i++) { - vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]); - vp++; - vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]); - vp++; + else + { + pb = SROM4_PATH0; + psz = SROM4_PATH1 - SROM4_PATH0; } - /* - * Words 50-51 set the customer-configured wl led behavior. - * 8 bits/gpio pin. High bit: activehi=0, activelo=1; - * LED behavior values defined in wlioctl.h . - */ - w = b[50]; - if ((w != 0) && (w != 0xffff)) { - /* ledbh0 */ - vp += sprintf(vp, "ledbh0=%d", (w & 0xff)); - vp++; - - /* ledbh1 */ - vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff); - vp++; - } - w = b[51]; - if ((w != 0) && (w != 0xffff)) { - /* ledbh2 */ - vp += sprintf(vp, "ledbh2=%d", w & 0xff); - vp++; - - /* ledbh */ - vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff); - vp++; + for (p = 0; p < MAX_PATH; p++) + { + for (srv = perpath_pci_sromvars; srv->name != NULL; srv++) + { + if ((srv->revmask & sr) == 0) + continue; + + if (pb + srv->off < off) + continue; + + w = srom[pb + srv->off - off]; + ASSERT (mask_valid (srv->mask)); + val = (w & srv->mask) >> mask_shift (srv->mask); + width = mask_width (srv->mask); + + /* Cheating: no per-path var is more than 1 word */ + + if ((srv->flags & SRFL_NOFFS) + && ((int) val == (1 << width) - 1)) + continue; + + if (srv->flags & SRFL_PRHEX) + varbuf_append (b, "%s%d=0x%x", srv->name, p, val); + else + varbuf_append (b, "%s%d=%d", srv->name, p, val); + } + pb += psz; } + } +} - /* Word 52 is max power 0/1 */ - w = b[52]; - vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff); - vp++; - vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff); - vp++; - - /* Word 56 is idle tssi target 0/1 */ - w = b[56]; - vp += sprintf(vp, "pa0itssit=%d", w & 0xff); - vp++; - vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff); - vp++; - - /* Word 57 is boardflags, if not programmed make it zero */ - w32 = (uint32)b[57]; - if (w32 == 0xffff) w32 = 0; - if (sromrev > 1) { - /* Word 28 is the high bits of boardflags */ - w32 |= (uint32)b[28] << 16; +static int +initvars_srom_pci (sb_t * sbh, void *curmap, char **vars, uint * count) +{ + uint16 *srom; + uint8 sromrev = 0; + uint32 sr; + varbuf_t b; + char *vp, *base = NULL; + osl_t *osh = sb_osh (sbh); + bool flash = FALSE; + char *value; + int err; + + /* + * Apply CRC over SROM content regardless SROM is present or not, + * and use variable sromrev's existance in flash to decide + * if we should return an error when CRC fails or read SROM variables + * from flash. + */ + srom = MALLOC (osh, SROM_MAX); + ASSERT (srom); + if (!srom) + return -2; + + err = + sprom_read_pci (osh, (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET), + 0, srom, SROM_WORDS, TRUE); + + if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) || + ((sbh->buscoretype == SB_PCIE) && (sbh->buscorerev >= 6))) + { + /* sromrev >= 4, read more */ + err = + sprom_read_pci (osh, + (void *) ((int8 *) curmap + PCI_BAR0_SPROM_OFFSET), 0, + srom, SROM4_WORDS, TRUE); + sromrev = srom[SROM4_CRCREV] & 0xff; + } + else if (err == 0) + { + /* srom is good and is rev < 4 */ + /* top word of sprom contains version and crc8 */ + sromrev = srom[SROM_CRCREV] & 0xff; + /* bcm4401 sroms misprogrammed */ + if (sromrev == 0x10) + sromrev = 1; + } + + if (err) + { +#ifdef WLTEST + uint32 val; + + BS_ERROR (("SROM Crc Error, so see if we could use a default\n")); + val = OSL_PCI_READ_CONFIG (osh, PCI_SPROM_CONTROL, sizeof (uint32)); + if (val & SPROM_OTPIN_USE) + { + BS_ERROR (("srom crc failed with OTP, use default vars....\n")); + vp = base = mfgsromvars; + if (sb_chip (sbh) == BCM4311_CHIP_ID) + { + const char *devid = "devid=0x4311"; + const size_t devid_strlen = strlen (devid); + BS_ERROR (("setting the devid to be 4311\n")); + bcopy (devid, vp, devid_strlen + 1); + vp += devid_strlen + 1; + } + bcopy (defaultsromvars, vp, MFGSROM_DEFVARSLEN); + vp += MFGSROM_DEFVARSLEN; + goto varsdone; } - vp += sprintf(vp, "boardflags=%d", w32); - vp++; - - /* Word 58 is antenna gain 0/1 */ - w = b[58]; - vp += sprintf(vp, "ag0=%d", w & 0xff); - vp++; - - vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff); - vp++; - - if (sromrev == 1) { - /* set the oem string */ - vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x", - ((b[59] >> 8) & 0xff), (b[59] & 0xff), - ((b[60] >> 8) & 0xff), (b[60] & 0xff), - ((b[61] >> 8) & 0xff), (b[61] & 0xff), - ((b[62] >> 8) & 0xff), (b[62] & 0xff)); - vp++; - } else if (sromrev == 2) { - /* Word 60 OFDM tx power offset from CCK level */ - /* OFDM Power Offset - opo */ - vp += sprintf(vp, "opo=%d", b[60] & 0xff); - vp++; - } else { - /* Word 60: cck power offsets */ - vp += sprintf(vp, "cckpo=%d", b[60]); - vp++; - - /* Words 61+62: 11g ofdm power offsets */ - w32 = ((uint32)b[62] << 16) | b[61]; - vp += sprintf(vp, "ofdmgpo=%d", w32); - vp++; + else + { +#endif /* WLTEST */ + BS_ERROR (("srom crc failed with SPROM....\n")); + if (!(value = sb_getdevpathvar (sbh, "sromrev"))) + { + err = -1; + goto errout; + } + sromrev = (uint8) simple_strtoul (value, NULL, 0); + flash = TRUE; +#ifdef WLTEST } - - /* final nullbyte terminator */ -done: *vp++ = '\0'; - - ASSERT((vp - base) <= VARS_MAX); +#endif /* WLTEST */ + } + + /* Bitmask for the sromrev */ + sr = 1 << sromrev; + + /* srom version check + * Current valid versions: 1, 2, 3, 4, 5, 8 + */ + if ((sr & 0x13e) == 0) + { + err = -2; + goto errout; + } + + ASSERT (vars); + ASSERT (count); + + base = vp = MALLOC (osh, MAXSZ_NVRAM_VARS); + ASSERT (vp); + if (!vp) + { + err = -2; + goto errout; + } + + /* read variables from flash */ + if (flash) + { + if ((err = initvars_flash (sbh, osh, &vp, MAXSZ_NVRAM_VARS))) + goto errout; + goto varsdone; + } + + varbuf_init (&b, base, MAXSZ_NVRAM_VARS); + + /* parse SROM into name=value pairs. */ + _initvars_srom_pci (sromrev, srom, 0, &b); + + /* final nullbyte terminator */ + ASSERT (b.size >= 1); + vp = b.buf; + *vp++ = '\0'; + + ASSERT ((vp - base) <= MAXSZ_NVRAM_VARS); varsdone: - err = initvars_table(osh, base, vp, vars, count); + err = initvars_table (osh, base, vp, vars, count); -err: +errout: #ifdef WLTEST - if (base != mfgsromvars) + if (base && (base != mfgsromvars)) +#else + if (base) #endif - MFREE(osh, base, VARS_MAX); - MFREE(osh, b, SROM_MAX); - return err; + MFREE (osh, base, MAXSZ_NVRAM_VARS); + + MFREE (osh, srom, SROM_MAX); + return err; } /* @@ -1183,31 +1889,217 @@ err: * Return 0 on success, nonzero on error. */ static int -initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count) +initvars_cis_pcmcia (sb_t * sbh, osl_t * osh, char **vars, uint * count) { - uint8 *cis = NULL; - int rc; - uint data_sz; + uint8 *cis = NULL; + int rc; + uint data_sz; + + data_sz = (sb_pcmciarev (sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE; + + if ((cis = MALLOC (osh, data_sz)) == NULL) + return (-2); + + if (sb_pcmciarev (sbh) == 1) + { + if (srom_read + (sbh, PCMCIA_BUS, (void *) NULL, osh, 0, data_sz, (uint16 *) cis)) + { + MFREE (osh, cis, data_sz); + return (-1); + } + /* fix up endianess for 16-bit data vs 8-bit parsing */ + htol16_buf ((uint16 *) cis, data_sz); + } + else + OSL_PCMCIA_READ_ATTR (osh, 0, cis, data_sz); + + rc = srom_parsecis (osh, &cis, 1, vars, count); - data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE; + MFREE (osh, cis, data_sz); - if ((cis = MALLOC(osh, data_sz)) == NULL) - return (-2); + return (rc); +} + + +static int +BCMINITFN (initvars_srom_sb) (sb_t * sbh, osl_t * osh, void *curmap, + char **vars, uint * varsz) +{ +#if defined(BCMSDIODEV) + /* CIS is read and supplied by the host */ + return BCME_OK; +#elif defined(BCMUSBDEV) + static bool srvars = FALSE; /* Use OTP/SPROM as global variables */ + + int sel = 0; /* where to read the srom. 0 - nowhere, 1 - otp, 2 - sprom */ + uint sz = 0; /* srom size in bytes */ + void *oh = NULL; + int rc = BCME_OK; + + /* Bail out if we've dealt with OTP/SPROM before! */ + if (srvars) + return 0; + +#if defined(BCM4328) + if (sbh->chip == BCM4328_CHIP_ID) + { + /* Access the SPROM if it is present */ + if ((sz = srom_size (sbh, osh)) != 0) + { + sz <<= 1; + sel = 2; + } + } +#endif +#if defined(BCM4325) + if (sbh->chip == BCM4325_CHIP_ID) + { + uint32 cst = sbh->chipst & CST4325_SPROM_OTP_SEL_MASK; + + /* Access OTP if it is present, powered on, and programmed */ + if ((oh = otp_init (sbh)) != NULL && (otp_status (oh) & OTPS_GUP_SW)) + { + sz = otp_size (oh); + sel = 1; + } + /* Access the SPROM if it is present and allow to be accessed */ + else if ((cst == CST4325_OTP_PWRDN || cst == CST4325_SPROM_SEL) && + (sz = srom_size (sbh, osh)) != 0) + { + sz <<= 1; + sel = 2; + } + } +#endif /* BCM4325 */ + + /* Read CIS in OTP/SPROM */ + if (sel != 0) + { + uint16 *srom; + uint8 *body = NULL; + + ASSERT (sz); + + /* Allocate memory */ + if ((srom = (uint16 *) MALLOC (osh, sz)) == NULL) + return BCME_NOMEM; + + /* Read CIS */ + switch (sel) + { + case 1: + rc = otp_read_region (oh, OTP_SW_RGN, srom, sz); + body = (uint8 *) srom; + break; + case 2: + rc = srom_read (sbh, SB_BUS, curmap, osh, 0, sz, srom); + /* sprom has 8 byte h/w header */ + body = (uint8 *) srom + SBSDIO_SPROM_CIS_OFFSET; + break; + default: + /* impossible to come here */ + ASSERT (0); + break; + } - if (sb_pcmciarev(sbh) == 1) { - if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) { - MFREE(osh, cis, data_sz); - return (-1); + /* Parse CIS */ + if (rc == BCME_OK) + { + uint i, tpls = 0xffffffff; + /* # sdiod fns + common + extra */ + uint8 *cis[SBSDIO_NUM_FUNCTION + 2]; + uint ciss = 0; + + /* each word is in host endian */ + htol16_buf ((uint8 *) srom, sz); + + ASSERT (body); + + /* count cis tuple chains */ + for (i = 0; i < sz && ciss < ARRAYSIZE (cis) && tpls != 0; i++) + { + cis[ciss++] = &body[i]; + for (tpls = 0; i < sz - 1; tpls++) + { + if (body[i++] == CISTPL_END) + break; + i += body[i] + 1; } - /* fix up endianess for 16-bit data vs 8-bit parsing */ - ltoh16_buf((uint16 *)cis, data_sz); - } else - OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz); + } - rc = srom_parsecis(osh, &cis, 1, vars, count); + /* call parser routine only when there are tuple chains */ + if (ciss > 1) + rc = srom_parsecis (osh, cis, ciss, vars, varsz); + } + + /* Clean up */ + MFREE (osh, srom, sz); - MFREE(osh, cis, data_sz); + /* Make SROM variables global */ + if (rc == BCME_OK) + { + rc = nvram_append ((void *) sbh, *vars, *varsz); + srvars = TRUE; - return (rc); + /* Tell the caller there is no individual SROM variables */ + *vars = NULL; + *varsz = 0; + } + } + + return rc; +#else /* !BCMUSBDEV && !BCMSDIODEV */ + /* Search flash nvram section for srom variables */ + return initvars_flash_sb (sbh, vars, varsz); +#endif /* !BCMUSBDEV && !BCMSDIODEV */ } +#ifdef BCMUSBDEV +/* Return sprom size in 16-bit words */ +static uint +srom_size (sb_t * sbh, osl_t * osh) +{ + uint size = 0; + if (SPROMBUS == PCMCIA_BUS) + { + uint32 origidx; + sdpcmd_regs_t *pcmregs; + bool wasup; + + origidx = sb_coreidx (sbh); + pcmregs = sb_setcore (sbh, SB_PCMCIA, 0); + ASSERT (pcmregs); + + if (!(wasup = sb_iscoreup (sbh))) + sb_core_reset (sbh, 0, 0); + + /* not worry about earlier core revs */ + if (sb_corerev (sbh) < 8) + goto done; + + /* SPROM is accessible only in PCMCIA mode unless there is SDIO clock */ + if (!(R_REG (osh, &pcmregs->corestatus) & CS_PCMCIAMODE)) + goto done; + + switch (SB_PCMCIA_READ (osh, pcmregs, SROM_INFO) & SRI_SZ_MASK) + { + case 1: + size = 256; /* SROM_INFO == 1 means 4kbit */ + break; + case 2: + size = 1024; /* SROM_INFO == 2 means 16kbit */ + break; + default: + break; + } + + done: + if (!wasup) + sb_core_disable (sbh, 0); + + sb_setcoreidx (sbh, origidx); + } + return size; +} +#endif /* def BCMUSBDEV */