]> Pileus Git - ~andy/linux/blob - drivers/staging/brcm80211/util/bcmsrom.c
staging: brcm80211: remove support functions for older chipsets from bcmsrom
[~andy/linux] / drivers / staging / brcm80211 / util / bcmsrom.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/etherdevice.h>
19 #include <bcmdefs.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
22 #include <stdarg.h>
23 #include <bcmutils.h>
24 #include <hndsoc.h>
25 #include <sbchipc.h>
26 #include <bcmdevs.h>
27 #include <pcicfg.h>
28 #include <siutils.h>
29 #include <bcmsrom.h>
30 #include <bcmsrom_tbl.h>
31
32 #include <bcmnvram.h>
33 #include <bcmotp.h>
34
35 #define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
36         (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
37          ((u8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
38         ((u8 *)curmap + PCI_BAR0_SPROM_OFFSET))
39
40 #if defined(BCMDBG)
41 #define WRITE_ENABLE_DELAY      500     /* 500 ms after write enable/disable toggle */
42 #define WRITE_WORD_DELAY        20      /* 20 ms between each word write */
43 #endif
44
45 typedef struct varbuf {
46         char *base;             /* pointer to buffer base */
47         char *buf;              /* pointer to current position */
48         unsigned int size;      /* current (residual) size in bytes */
49 } varbuf_t;
50 extern char *_vars;
51 extern uint _varsz;
52
53 static int initvars_srom_si(si_t *sih, void *curmap, char **vars, uint *count);
54 static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, varbuf_t *b);
55 static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count);
56 static int initvars_flash_si(si_t *sih, char **vars, uint *count);
57 static int sprom_read_pci(si_t *sih, u16 *sprom,
58                           uint wordoff, u16 *buf, uint nwords, bool check_crc);
59 #if defined(BCMNVRAMR)
60 static int otp_read_pci(si_t *sih, u16 *buf, uint bufsz);
61 #endif
62 static u16 srom_cc_cmd(si_t *sih, void *ccregs, u32 cmd,
63                           uint wordoff, u16 data);
64
65 static int initvars_table(char *start, char *end,
66                           char **vars, uint *count);
67 static int initvars_flash(si_t *sih, char **vp,
68                           uint len);
69
70 /* Initialization of varbuf structure */
71 static void varbuf_init(varbuf_t *b, char *buf, uint size)
72 {
73         b->size = size;
74         b->base = b->buf = buf;
75 }
76
77 /* append a null terminated var=value string */
78 static int varbuf_append(varbuf_t *b, const char *fmt, ...)
79 {
80         va_list ap;
81         int r;
82         size_t len;
83         char *s;
84
85         if (b->size < 2)
86                 return 0;
87
88         va_start(ap, fmt);
89         r = vsnprintf(b->buf, b->size, fmt, ap);
90         va_end(ap);
91
92         /* C99 snprintf behavior returns r >= size on overflow,
93          * others return -1 on overflow.
94          * All return -1 on format error.
95          * We need to leave room for 2 null terminations, one for the current var
96          * string, and one for final null of the var table. So check that the
97          * strlen written, r, leaves room for 2 chars.
98          */
99         if ((r == -1) || (r > (int)(b->size - 2))) {
100                 b->size = 0;
101                 return 0;
102         }
103
104         /* Remove any earlier occurrence of the same variable */
105         s = strchr(b->buf, '=');
106         if (s != NULL) {
107                 len = (size_t) (s - b->buf);
108                 for (s = b->base; s < b->buf;) {
109                         if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') {
110                                 len = strlen(s) + 1;
111                                 memmove(s, (s + len),
112                                         ((b->buf + r + 1) - (s + len)));
113                                 b->buf -= len;
114                                 b->size += (unsigned int)len;
115                                 break;
116                         }
117
118                         while (*s++)
119                                 ;
120                 }
121         }
122
123         /* skip over this string's null termination */
124         r++;
125         b->size -= r;
126         b->buf += r;
127
128         return r;
129 }
130
131 /*
132  * Initialize local vars from the right source for this platform.
133  * Return 0 on success, nonzero on error.
134  */
135 int srom_var_init(si_t *sih, uint bustype, void *curmap,
136                   char **vars, uint *count)
137 {
138         uint len;
139
140         len = 0;
141
142         ASSERT(bustype == bustype);
143         if (vars == NULL || count == NULL)
144                 return 0;
145
146         *vars = NULL;
147         *count = 0;
148
149         switch (bustype) {
150         case SI_BUS:
151         case JTAG_BUS:
152                 return initvars_srom_si(sih, curmap, vars, count);
153
154         case PCI_BUS:
155                 ASSERT(curmap != NULL);
156                 if (curmap == NULL)
157                         return -1;
158
159                 return initvars_srom_pci(sih, curmap, vars, count);
160
161         default:
162                 ASSERT(0);
163         }
164         return -1;
165 }
166
167 /* In chips with chipcommon rev 32 and later, the srom is in chipcommon,
168  * not in the bus cores.
169  */
170 static u16
171 srom_cc_cmd(si_t *sih, void *ccregs, u32 cmd,
172             uint wordoff, u16 data)
173 {
174         chipcregs_t *cc = (chipcregs_t *) ccregs;
175         uint wait_cnt = 1000;
176
177         if ((cmd == SRC_OP_READ) || (cmd == SRC_OP_WRITE)) {
178                 W_REG(&cc->sromaddress, wordoff * 2);
179                 if (cmd == SRC_OP_WRITE)
180                         W_REG(&cc->sromdata, data);
181         }
182
183         W_REG(&cc->sromcontrol, SRC_START | cmd);
184
185         while (wait_cnt--) {
186                 if ((R_REG(&cc->sromcontrol) & SRC_BUSY) == 0)
187                         break;
188         }
189
190         if (!wait_cnt) {
191                 return 0xffff;
192         }
193         if (cmd == SRC_OP_READ)
194                 return (u16) R_REG(&cc->sromdata);
195         else
196                 return 0xffff;
197 }
198
199 static inline void ltoh16_buf(u16 *buf, unsigned int size)
200 {
201         for (size /= 2; size; size--)
202                 *(buf + size) = le16_to_cpu(*(buf + size));
203 }
204
205 static inline void htol16_buf(u16 *buf, unsigned int size)
206 {
207         for (size /= 2; size; size--)
208                 *(buf + size) = cpu_to_le16(*(buf + size));
209 }
210
211 /*
212  * Read in and validate sprom.
213  * Return 0 on success, nonzero on error.
214  */
215 static int
216 sprom_read_pci(si_t *sih, u16 *sprom, uint wordoff,
217                u16 *buf, uint nwords, bool check_crc)
218 {
219         int err = 0;
220         uint i;
221         void *ccregs = NULL;
222
223         /* read the sprom */
224         for (i = 0; i < nwords; i++) {
225
226                 if (sih->ccrev > 31 && ISSIM_ENAB(sih)) {
227                         /* use indirect since direct is too slow on QT */
228                         if ((sih->cccaps & CC_CAP_SROM) == 0)
229                                 return 1;
230
231                         ccregs = (void *)((u8 *) sprom - CC_SROM_OTP);
232                         buf[i] =
233                             srom_cc_cmd(sih, ccregs, SRC_OP_READ,
234                                         wordoff + i, 0);
235
236                 } else {
237                         if (ISSIM_ENAB(sih))
238                                 buf[i] = R_REG(&sprom[wordoff + i]);
239
240                         buf[i] = R_REG(&sprom[wordoff + i]);
241                 }
242
243         }
244
245         /* bypass crc checking for simulation to allow srom hack */
246         if (ISSIM_ENAB(sih))
247                 return err;
248
249         if (check_crc) {
250
251                 if (buf[0] == 0xffff) {
252                         /* The hardware thinks that an srom that starts with 0xffff
253                          * is blank, regardless of the rest of the content, so declare
254                          * it bad.
255                          */
256                         return 1;
257                 }
258
259                 /* fixup the endianness so crc8 will pass */
260                 htol16_buf(buf, nwords * 2);
261                 if (hndcrc8((u8 *) buf, nwords * 2, CRC8_INIT_VALUE) !=
262                     CRC8_GOOD_VALUE) {
263                         /* DBG only pci always read srom4 first, then srom8/9 */
264                         err = 1;
265                 }
266                 /* now correct the endianness of the byte array */
267                 ltoh16_buf(buf, nwords * 2);
268         }
269         return err;
270 }
271
272 #if defined(BCMNVRAMR)
273 static int otp_read_pci(si_t *sih, u16 *buf, uint bufsz)
274 {
275         u8 *otp;
276         uint sz = OTP_SZ_MAX / 2;       /* size in words */
277         int err = 0;
278
279         ASSERT(bufsz <= OTP_SZ_MAX);
280
281         otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
282         if (otp == NULL) {
283                 return BCME_ERROR;
284         }
285
286         err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
287
288         memcpy(buf, otp, bufsz);
289
290         kfree(otp);
291
292         /* Check CRC */
293         if (buf[0] == 0xffff) {
294                 /* The hardware thinks that an srom that starts with 0xffff
295                  * is blank, regardless of the rest of the content, so declare
296                  * it bad.
297                  */
298                 return 1;
299         }
300
301         /* fixup the endianness so crc8 will pass */
302         htol16_buf(buf, bufsz);
303         if (hndcrc8((u8 *) buf, SROM4_WORDS * 2, CRC8_INIT_VALUE) !=
304             CRC8_GOOD_VALUE) {
305                 err = 1;
306         }
307         /* now correct the endianness of the byte array */
308         ltoh16_buf(buf, bufsz);
309
310         return err;
311 }
312 #endif                          /* defined(BCMNVRAMR) */
313 /*
314 * Create variable table from memory.
315 * Return 0 on success, nonzero on error.
316 */
317 static int initvars_table(char *start, char *end,
318                           char **vars, uint *count)
319 {
320         int c = (int)(end - start);
321
322         /* do it only when there is more than just the null string */
323         if (c > 1) {
324                 char *vp = kmalloc(c, GFP_ATOMIC);
325                 ASSERT(vp != NULL);
326                 if (!vp)
327                         return BCME_NOMEM;
328                 memcpy(vp, start, c);
329                 *vars = vp;
330                 *count = c;
331         } else {
332                 *vars = NULL;
333                 *count = 0;
334         }
335
336         return 0;
337 }
338
339 /*
340  * Find variables with <devpath> from flash. 'base' points to the beginning
341  * of the table upon enter and to the end of the table upon exit when success.
342  * Return 0 on success, nonzero on error.
343  */
344 static int initvars_flash(si_t *sih, char **base, uint len)
345 {
346         char *vp = *base;
347         char *flash;
348         int err;
349         char *s;
350         uint l, dl, copy_len;
351         char devpath[SI_DEVPATH_BUFSZ];
352
353         /* allocate memory and read in flash */
354         flash = kmalloc(NVRAM_SPACE, GFP_ATOMIC);
355         if (!flash)
356                 return BCME_NOMEM;
357         err = nvram_getall(flash, NVRAM_SPACE);
358         if (err)
359                 goto exit;
360
361         si_devpath(sih, devpath, sizeof(devpath));
362
363         /* grab vars with the <devpath> prefix in name */
364         dl = strlen(devpath);
365         for (s = flash; s && *s; s += l + 1) {
366                 l = strlen(s);
367
368                 /* skip non-matching variable */
369                 if (strncmp(s, devpath, dl))
370                         continue;
371
372                 /* is there enough room to copy? */
373                 copy_len = l - dl + 1;
374                 if (len < copy_len) {
375                         err = BCME_BUFTOOSHORT;
376                         goto exit;
377                 }
378
379                 /* no prefix, just the name=value */
380                 strncpy(vp, &s[dl], copy_len);
381                 vp += copy_len;
382                 len -= copy_len;
383         }
384
385         /* add null string as terminator */
386         if (len < 1) {
387                 err = BCME_BUFTOOSHORT;
388                 goto exit;
389         }
390         *vp++ = '\0';
391
392         *base = vp;
393
394  exit:  kfree(flash);
395         return err;
396 }
397
398 /*
399  * Initialize nonvolatile variable table from flash.
400  * Return 0 on success, nonzero on error.
401  */
402 static int initvars_flash_si(si_t *sih, char **vars, uint *count)
403 {
404         char *vp, *base;
405         int err;
406
407         ASSERT(vars != NULL);
408         ASSERT(count != NULL);
409
410         base = vp = kmalloc(MAXSZ_NVRAM_VARS, GFP_ATOMIC);
411         ASSERT(vp != NULL);
412         if (!vp)
413                 return BCME_NOMEM;
414
415         err = initvars_flash(sih, &vp, MAXSZ_NVRAM_VARS);
416         if (err == 0)
417                 err = initvars_table(base, vp, vars, count);
418
419         kfree(base);
420
421         return err;
422 }
423
424 /* Parse SROM and create name=value pairs. 'srom' points to
425  * the SROM word array. 'off' specifies the offset of the
426  * first word 'srom' points to, which should be either 0 or
427  * SROM3_SWRG_OFF (full SROM or software region).
428  */
429
430 static uint mask_shift(u16 mask)
431 {
432         uint i;
433         for (i = 0; i < (sizeof(mask) << 3); i++) {
434                 if (mask & (1 << i))
435                         return i;
436         }
437         ASSERT(mask);
438         return 0;
439 }
440
441 static uint mask_width(u16 mask)
442 {
443         int i;
444         for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
445                 if (mask & (1 << i))
446                         return (uint) (i - mask_shift(mask) + 1);
447         }
448         ASSERT(mask);
449         return 0;
450 }
451
452 #if defined(BCMDBG)
453 static bool mask_valid(u16 mask)
454 {
455         uint shift = mask_shift(mask);
456         uint width = mask_width(mask);
457         return mask == ((~0 << shift) & ~(~0 << (shift + width)));
458 }
459 #endif                          /* BCMDBG */
460
461 static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, varbuf_t *b)
462 {
463         u16 w;
464         u32 val;
465         const sromvar_t *srv;
466         uint width;
467         uint flags;
468         u32 sr = (1 << sromrev);
469
470         varbuf_append(b, "sromrev=%d", sromrev);
471
472         for (srv = pci_sromvars; srv->name != NULL; srv++) {
473                 const char *name;
474
475                 if ((srv->revmask & sr) == 0)
476                         continue;
477
478                 if (srv->off < off)
479                         continue;
480
481                 flags = srv->flags;
482                 name = srv->name;
483
484                 /* This entry is for mfgc only. Don't generate param for it, */
485                 if (flags & SRFL_NOVAR)
486                         continue;
487
488                 if (flags & SRFL_ETHADDR) {
489                         u8 ea[ETH_ALEN];
490
491                         ea[0] = (srom[srv->off - off] >> 8) & 0xff;
492                         ea[1] = srom[srv->off - off] & 0xff;
493                         ea[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
494                         ea[3] = srom[srv->off + 1 - off] & 0xff;
495                         ea[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
496                         ea[5] = srom[srv->off + 2 - off] & 0xff;
497
498                         varbuf_append(b, "%s=%pM", name, ea);
499                 } else {
500                         ASSERT(mask_valid(srv->mask));
501                         ASSERT(mask_width(srv->mask));
502
503                         w = srom[srv->off - off];
504                         val = (w & srv->mask) >> mask_shift(srv->mask);
505                         width = mask_width(srv->mask);
506
507                         while (srv->flags & SRFL_MORE) {
508                                 srv++;
509                                 ASSERT(srv->name != NULL);
510
511                                 if (srv->off == 0 || srv->off < off)
512                                         continue;
513
514                                 ASSERT(mask_valid(srv->mask));
515                                 ASSERT(mask_width(srv->mask));
516
517                                 w = srom[srv->off - off];
518                                 val +=
519                                     ((w & srv->mask) >> mask_shift(srv->
520                                                                    mask)) <<
521                                     width;
522                                 width += mask_width(srv->mask);
523                         }
524
525                         if ((flags & SRFL_NOFFS)
526                             && ((int)val == (1 << width) - 1))
527                                 continue;
528
529                         if (flags & SRFL_CCODE) {
530                                 if (val == 0)
531                                         varbuf_append(b, "ccode=");
532                                 else
533                                         varbuf_append(b, "ccode=%c%c",
534                                                       (val >> 8), (val & 0xff));
535                         }
536                         /* LED Powersave duty cycle has to be scaled:
537                          *(oncount >> 24) (offcount >> 8)
538                          */
539                         else if (flags & SRFL_LEDDC) {
540                                 u32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */
541                                     (((val & 0xff)) << 8);      /* offcount */
542                                 varbuf_append(b, "leddc=%d", w32);
543                         } else if (flags & SRFL_PRHEX)
544                                 varbuf_append(b, "%s=0x%x", name, val);
545                         else if ((flags & SRFL_PRSIGN)
546                                  && (val & (1 << (width - 1))))
547                                 varbuf_append(b, "%s=%d", name,
548                                               (int)(val | (~0 << width)));
549                         else
550                                 varbuf_append(b, "%s=%u", name, val);
551                 }
552         }
553
554         if (sromrev >= 4) {
555                 /* Do per-path variables */
556                 uint p, pb, psz;
557
558                 if (sromrev >= 8) {
559                         pb = SROM8_PATH0;
560                         psz = SROM8_PATH1 - SROM8_PATH0;
561                 } else {
562                         pb = SROM4_PATH0;
563                         psz = SROM4_PATH1 - SROM4_PATH0;
564                 }
565
566                 for (p = 0; p < MAX_PATH_SROM; p++) {
567                         for (srv = perpath_pci_sromvars; srv->name != NULL;
568                              srv++) {
569                                 if ((srv->revmask & sr) == 0)
570                                         continue;
571
572                                 if (pb + srv->off < off)
573                                         continue;
574
575                                 /* This entry is for mfgc only. Don't generate param for it, */
576                                 if (srv->flags & SRFL_NOVAR)
577                                         continue;
578
579                                 w = srom[pb + srv->off - off];
580
581                                 ASSERT(mask_valid(srv->mask));
582                                 val = (w & srv->mask) >> mask_shift(srv->mask);
583                                 width = mask_width(srv->mask);
584
585                                 /* Cheating: no per-path var is more than 1 word */
586
587                                 if ((srv->flags & SRFL_NOFFS)
588                                     && ((int)val == (1 << width) - 1))
589                                         continue;
590
591                                 if (srv->flags & SRFL_PRHEX)
592                                         varbuf_append(b, "%s%d=0x%x", srv->name,
593                                                       p, val);
594                                 else
595                                         varbuf_append(b, "%s%d=%d", srv->name,
596                                                       p, val);
597                         }
598                         pb += psz;
599                 }
600         }
601 }
602
603 /*
604  * Initialize nonvolatile variable table from sprom.
605  * Return 0 on success, nonzero on error.
606  */
607 static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count)
608 {
609         u16 *srom, *sromwindow;
610         u8 sromrev = 0;
611         u32 sr;
612         varbuf_t b;
613         char *vp, *base = NULL;
614         bool flash = false;
615         int err = 0;
616
617         /*
618          * Apply CRC over SROM content regardless SROM is present or not,
619          * and use variable <devpath>sromrev's existance in flash to decide
620          * if we should return an error when CRC fails or read SROM variables
621          * from flash.
622          */
623         srom = kmalloc(SROM_MAX, GFP_ATOMIC);
624         ASSERT(srom != NULL);
625         if (!srom)
626                 return -2;
627
628         sromwindow = (u16 *) SROM_OFFSET(sih);
629         if (si_is_sprom_available(sih)) {
630                 err =
631                     sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
632                                    true);
633
634                 if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
635                     (((sih->buscoretype == PCIE_CORE_ID)
636                       && (sih->buscorerev >= 6))
637                      || ((sih->buscoretype == PCI_CORE_ID)
638                          && (sih->buscorerev >= 0xe)))) {
639                         /* sromrev >= 4, read more */
640                         err =
641                             sprom_read_pci(sih, sromwindow, 0, srom,
642                                            SROM4_WORDS, true);
643                         sromrev = srom[SROM4_CRCREV] & 0xff;
644                 } else if (err == 0) {
645                         /* srom is good and is rev < 4 */
646                         /* top word of sprom contains version and crc8 */
647                         sromrev = srom[SROM_CRCREV] & 0xff;
648                         /* bcm4401 sroms misprogrammed */
649                         if (sromrev == 0x10)
650                                 sromrev = 1;
651                 }
652         }
653 #if defined(BCMNVRAMR)
654         /* Use OTP if SPROM not available */
655         else {
656                 err = otp_read_pci(sih, srom, SROM_MAX);
657                 if (err == 0)
658                         /* OTP only contain SROM rev8/rev9 for now */
659                         sromrev = srom[SROM4_CRCREV] & 0xff;
660                 else
661                         err = 1;
662         }
663 #else
664         else
665                 err = 1;
666 #endif
667
668         /*
669          * We want internal/wltest driver to come up with default
670          * sromvars so we can program a blank SPROM/OTP.
671          */
672         if (err) {
673                 char *value;
674                 u32 val;
675                 val = 0;
676
677                 value = si_getdevpathvar(sih, "sromrev");
678                 if (value) {
679                         sromrev = (u8) simple_strtoul(value, NULL, 0);
680                         flash = true;
681                         goto varscont;
682                 }
683
684                 value = si_getnvramflvar(sih, "sromrev");
685                 if (value) {
686                         err = 0;
687                         goto errout;
688                 }
689
690                 {
691                         err = -1;
692                         goto errout;
693                 }
694         }
695
696  varscont:
697         /* Bitmask for the sromrev */
698         sr = 1 << sromrev;
699
700         /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
701         if ((sr & 0x33e) == 0) {
702                 err = -2;
703                 goto errout;
704         }
705
706         ASSERT(vars != NULL);
707         ASSERT(count != NULL);
708
709         base = vp = kmalloc(MAXSZ_NVRAM_VARS, GFP_ATOMIC);
710         ASSERT(vp != NULL);
711         if (!vp) {
712                 err = -2;
713                 goto errout;
714         }
715
716         /* read variables from flash */
717         if (flash) {
718                 err = initvars_flash(sih, &vp, MAXSZ_NVRAM_VARS);
719                 if (err)
720                         goto errout;
721                 goto varsdone;
722         }
723
724         varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
725
726         /* parse SROM into name=value pairs. */
727         _initvars_srom_pci(sromrev, srom, 0, &b);
728
729         /* final nullbyte terminator */
730         ASSERT(b.size >= 1);
731         vp = b.buf;
732         *vp++ = '\0';
733
734         ASSERT((vp - base) <= MAXSZ_NVRAM_VARS);
735
736  varsdone:
737         err = initvars_table(base, vp, vars, count);
738
739  errout:
740         if (base)
741                 kfree(base);
742
743         kfree(srom);
744         return err;
745 }
746
747
748 static int initvars_srom_si(si_t *sih, void *curmap, char **vars, uint *varsz)
749 {
750         /* Search flash nvram section for srom variables */
751         return initvars_flash_si(sih, vars, varsz);
752 }