Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
0002 /* from src/prism2/download/prism2dl.c
0003  *
0004  * utility for downloading prism2 images moved into kernelspace
0005  *
0006  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
0007  * --------------------------------------------------------------------
0008  *
0009  * linux-wlan
0010  *
0011  *   The contents of this file are subject to the Mozilla Public
0012  *   License Version 1.1 (the "License"); you may not use this file
0013  *   except in compliance with the License. You may obtain a copy of
0014  *   the License at http://www.mozilla.org/MPL/
0015  *
0016  *   Software distributed under the License is distributed on an "AS
0017  *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0018  *   implied. See the License for the specific language governing
0019  *   rights and limitations under the License.
0020  *
0021  *   Alternatively, the contents of this file may be used under the
0022  *   terms of the GNU Public License version 2 (the "GPL"), in which
0023  *   case the provisions of the GPL are applicable instead of the
0024  *   above.  If you wish to allow the use of your version of this file
0025  *   only under the terms of the GPL and not to allow others to use
0026  *   your version of this file under the MPL, indicate your decision
0027  *   by deleting the provisions above and replace them with the notice
0028  *   and other provisions required by the GPL.  If you do not delete
0029  *   the provisions above, a recipient may use your version of this
0030  *   file under either the MPL or the GPL.
0031  *
0032  * --------------------------------------------------------------------
0033  *
0034  * Inquiries regarding the linux-wlan Open Source project can be
0035  * made directly to:
0036  *
0037  * AbsoluteValue Systems Inc.
0038  * info@linux-wlan.com
0039  * http://www.linux-wlan.com
0040  *
0041  * --------------------------------------------------------------------
0042  *
0043  * Portions of the development of this software were funded by
0044  * Intersil Corporation as part of PRISM(R) chipset product development.
0045  *
0046  * --------------------------------------------------------------------
0047  */
0048 
0049 /*================================================================*/
0050 /* System Includes */
0051 #include <linux/ihex.h>
0052 #include <linux/slab.h>
0053 
0054 /*================================================================*/
0055 /* Local Constants */
0056 
0057 #define PRISM2_USB_FWFILE   "prism2_ru.fw"
0058 MODULE_FIRMWARE(PRISM2_USB_FWFILE);
0059 
0060 #define S3DATA_MAX      5000
0061 #define S3PLUG_MAX      200
0062 #define S3CRC_MAX       200
0063 #define S3INFO_MAX      50
0064 
0065 #define S3ADDR_PLUG     (0xff000000UL)
0066 #define S3ADDR_CRC      (0xff100000UL)
0067 #define S3ADDR_INFO     (0xff200000UL)
0068 #define S3ADDR_START        (0xff400000UL)
0069 
0070 #define CHUNKS_MAX      100
0071 
0072 #define WRITESIZE_MAX       4096
0073 
0074 /*================================================================*/
0075 /* Local Types */
0076 
0077 struct s3datarec {
0078     u32 len;
0079     u32 addr;
0080     u8 checksum;
0081     u8 *data;
0082 };
0083 
0084 struct s3plugrec {
0085     u32 itemcode;
0086     u32 addr;
0087     u32 len;
0088 };
0089 
0090 struct s3crcrec {
0091     u32 addr;
0092     u32 len;
0093     unsigned int dowrite;
0094 };
0095 
0096 struct s3inforec {
0097     u16 len;
0098     u16 type;
0099     union {
0100         struct hfa384x_compident version;
0101         struct hfa384x_caplevel compat;
0102         u16 buildseq;
0103         struct hfa384x_compident platform;
0104     } info;
0105 };
0106 
0107 struct pda {
0108     u8 buf[HFA384x_PDA_LEN_MAX];
0109     struct hfa384x_pdrec *rec[HFA384x_PDA_RECS_MAX];
0110     unsigned int nrec;
0111 };
0112 
0113 struct imgchunk {
0114     u32 addr;   /* start address */
0115     u32 len;    /* in bytes */
0116     u16 crc;    /* CRC value (if it falls at a chunk boundary) */
0117     u8 *data;
0118 };
0119 
0120 /*================================================================*/
0121 /* Local Static Definitions */
0122 
0123 /*----------------------------------------------------------------*/
0124 /* s-record image processing */
0125 
0126 /* Data records */
0127 static unsigned int ns3data;
0128 static struct s3datarec *s3data;
0129 
0130 /* Plug records */
0131 static unsigned int ns3plug;
0132 static struct s3plugrec s3plug[S3PLUG_MAX];
0133 
0134 /* CRC records */
0135 static unsigned int ns3crc;
0136 static struct s3crcrec s3crc[S3CRC_MAX];
0137 
0138 /* Info records */
0139 static unsigned int ns3info;
0140 static struct s3inforec s3info[S3INFO_MAX];
0141 
0142 /* S7 record (there _better_ be only one) */
0143 static u32 startaddr;
0144 
0145 /* Load image chunks */
0146 static unsigned int nfchunks;
0147 static struct imgchunk fchunk[CHUNKS_MAX];
0148 
0149 /* Note that for the following pdrec_t arrays, the len and code */
0150 /*   fields are stored in HOST byte order. The mkpdrlist() function */
0151 /*   does the conversion.  */
0152 /*----------------------------------------------------------------*/
0153 /* PDA, built from [card|newfile]+[addfile1+addfile2...] */
0154 
0155 static struct pda pda;
0156 static struct hfa384x_compident nicid;
0157 static struct hfa384x_caplevel rfid;
0158 static struct hfa384x_caplevel macid;
0159 static struct hfa384x_caplevel priid;
0160 
0161 /*================================================================*/
0162 /* Local Function Declarations */
0163 
0164 static int prism2_fwapply(const struct ihex_binrec *rfptr,
0165               struct wlandevice *wlandev);
0166 
0167 static int read_fwfile(const struct ihex_binrec *rfptr);
0168 
0169 static int mkimage(struct imgchunk *clist, unsigned int *ccnt);
0170 
0171 static int read_cardpda(struct pda *pda, struct wlandevice *wlandev);
0172 
0173 static int mkpdrlist(struct pda *pda);
0174 
0175 static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
0176              struct s3plugrec *s3plug, unsigned int ns3plug,
0177              struct pda *pda);
0178 
0179 static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
0180             struct s3crcrec *s3crc, unsigned int ns3crc);
0181 
0182 static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
0183               unsigned int nfchunks);
0184 
0185 static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks);
0186 
0187 static void free_srecs(void);
0188 
0189 static int validate_identity(void);
0190 
0191 /*================================================================*/
0192 /* Function Definitions */
0193 
0194 /*----------------------------------------------------------------
0195  * prism2_fwtry
0196  *
0197  * Try and get firmware into memory
0198  *
0199  * Arguments:
0200  *  udev    usb device structure
0201  *  wlandev wlan device structure
0202  *
0203  * Returns:
0204  *  0   - success
0205  *  ~0  - failure
0206  *----------------------------------------------------------------
0207  */
0208 static int prism2_fwtry(struct usb_device *udev, struct wlandevice *wlandev)
0209 {
0210     const struct firmware *fw_entry = NULL;
0211 
0212     netdev_info(wlandev->netdev, "prism2_usb: Checking for firmware %s\n",
0213             PRISM2_USB_FWFILE);
0214     if (request_ihex_firmware(&fw_entry,
0215                   PRISM2_USB_FWFILE, &udev->dev) != 0) {
0216         netdev_info(wlandev->netdev,
0217                 "prism2_usb: Firmware not available, but not essential\n");
0218         netdev_info(wlandev->netdev,
0219                 "prism2_usb: can continue to use card anyway.\n");
0220         return 1;
0221     }
0222 
0223     netdev_info(wlandev->netdev,
0224             "prism2_usb: %s will be processed, size %zu\n",
0225             PRISM2_USB_FWFILE, fw_entry->size);
0226     prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
0227 
0228     release_firmware(fw_entry);
0229     return 0;
0230 }
0231 
0232 /*----------------------------------------------------------------
0233  * prism2_fwapply
0234  *
0235  * Apply the firmware loaded into memory
0236  *
0237  * Arguments:
0238  *  rfptr   firmware image in kernel memory
0239  *  wlandev device
0240  *
0241  * Returns:
0242  *  0   - success
0243  *  ~0  - failure
0244  *----------------------------------------------------------------
0245  */
0246 static int prism2_fwapply(const struct ihex_binrec *rfptr,
0247               struct wlandevice *wlandev)
0248 {
0249     signed int result = 0;
0250     struct p80211msg_dot11req_mibget getmsg;
0251     struct p80211itemd *item;
0252     u32 *data;
0253 
0254     /* Initialize the data structures */
0255     ns3data = 0;
0256     s3data = kcalloc(S3DATA_MAX, sizeof(*s3data), GFP_KERNEL);
0257     if (!s3data) {
0258         result = -ENOMEM;
0259         goto out;
0260     }
0261 
0262     ns3plug = 0;
0263     memset(s3plug, 0, sizeof(s3plug));
0264     ns3crc = 0;
0265     memset(s3crc, 0, sizeof(s3crc));
0266     ns3info = 0;
0267     memset(s3info, 0, sizeof(s3info));
0268     startaddr = 0;
0269 
0270     nfchunks = 0;
0271     memset(fchunk, 0, sizeof(fchunk));
0272     memset(&nicid, 0, sizeof(nicid));
0273     memset(&rfid, 0, sizeof(rfid));
0274     memset(&macid, 0, sizeof(macid));
0275     memset(&priid, 0, sizeof(priid));
0276 
0277     /* clear the pda and add an initial END record */
0278     memset(&pda, 0, sizeof(pda));
0279     pda.rec[0] = (struct hfa384x_pdrec *)pda.buf;
0280     pda.rec[0]->len = cpu_to_le16(2);   /* len in words */
0281     pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
0282     pda.nrec = 1;
0283 
0284     /*-----------------------------------------------------*/
0285     /* Put card into fwload state */
0286     prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
0287 
0288     /* Build the PDA we're going to use. */
0289     if (read_cardpda(&pda, wlandev)) {
0290         netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n");
0291         result = 1;
0292         goto out;
0293     }
0294 
0295     /* read the card's PRI-SUP */
0296     memset(&getmsg, 0, sizeof(getmsg));
0297     getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET;
0298     getmsg.msglen = sizeof(getmsg);
0299     strscpy(getmsg.devname, wlandev->name, sizeof(getmsg.devname));
0300 
0301     getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE;
0302     getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
0303     getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE;
0304     getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
0305 
0306     item = (struct p80211itemd *)getmsg.mibattribute.data;
0307     item->did = DIDMIB_P2_NIC_PRISUPRANGE;
0308     item->status = P80211ENUM_msgitem_status_no_value;
0309 
0310     data = (u32 *)item->data;
0311 
0312     /* DIDmsg_dot11req_mibget */
0313     prism2mgmt_mibset_mibget(wlandev, &getmsg);
0314     if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
0315         netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n");
0316 
0317     /* Already in host order */
0318     priid.role = *data++;
0319     priid.id = *data++;
0320     priid.variant = *data++;
0321     priid.bottom = *data++;
0322     priid.top = *data++;
0323 
0324     /* Read the S3 file */
0325     result = read_fwfile(rfptr);
0326     if (result) {
0327         netdev_err(wlandev->netdev,
0328                "Failed to read the data exiting.\n");
0329         goto out;
0330     }
0331 
0332     result = validate_identity();
0333     if (result) {
0334         netdev_err(wlandev->netdev, "Incompatible firmware image.\n");
0335         goto out;
0336     }
0337 
0338     if (startaddr == 0x00000000) {
0339         netdev_err(wlandev->netdev,
0340                "Can't RAM download a Flash image!\n");
0341         result = 1;
0342         goto out;
0343     }
0344 
0345     /* Make the image chunks */
0346     result = mkimage(fchunk, &nfchunks);
0347     if (result) {
0348         netdev_err(wlandev->netdev, "Failed to make image chunk.\n");
0349         goto free_chunks;
0350     }
0351 
0352     /* Do any plugging */
0353     result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
0354     if (result) {
0355         netdev_err(wlandev->netdev, "Failed to plug data.\n");
0356         goto free_chunks;
0357     }
0358 
0359     /* Insert any CRCs */
0360     result = crcimage(fchunk, nfchunks, s3crc, ns3crc);
0361     if (result) {
0362         netdev_err(wlandev->netdev, "Failed to insert all CRCs\n");
0363         goto free_chunks;
0364     }
0365 
0366     /* Write the image */
0367     result = writeimage(wlandev, fchunk, nfchunks);
0368     if (result) {
0369         netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n");
0370         goto free_chunks;
0371     }
0372 
0373     netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n");
0374 
0375 free_chunks:
0376     /* clear any allocated memory */
0377     free_chunks(fchunk, &nfchunks);
0378     free_srecs();
0379 
0380 out:
0381     return result;
0382 }
0383 
0384 /*----------------------------------------------------------------
0385  * crcimage
0386  *
0387  * Adds a CRC16 in the two bytes prior to each block identified by
0388  * an S3 CRC record.  Currently, we don't actually do a CRC we just
0389  * insert the value 0xC0DE in hfa384x order.
0390  *
0391  * Arguments:
0392  *  fchunk      Array of image chunks
0393  *  nfchunks    Number of image chunks
0394  *  s3crc       Array of crc records
0395  *  ns3crc      Number of crc records
0396  *
0397  * Returns:
0398  *  0   success
0399  *  ~0  failure
0400  *----------------------------------------------------------------
0401  */
0402 static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
0403             struct s3crcrec *s3crc, unsigned int ns3crc)
0404 {
0405     int result = 0;
0406     int i;
0407     int c;
0408     u32 crcstart;
0409     u32 cstart = 0;
0410     u32 cend;
0411     u8 *dest;
0412     u32 chunkoff;
0413 
0414     for (i = 0; i < ns3crc; i++) {
0415         if (!s3crc[i].dowrite)
0416             continue;
0417         crcstart = s3crc[i].addr;
0418         /* Find chunk */
0419         for (c = 0; c < nfchunks; c++) {
0420             cstart = fchunk[c].addr;
0421             cend = fchunk[c].addr + fchunk[c].len;
0422             /* the line below does an address & len match search */
0423             /* unfortunately, I've found that the len fields of */
0424             /* some crc records don't match with the length of */
0425             /* the actual data, so we're not checking right now */
0426             /* if (crcstart-2 >= cstart && crcend <= cend) break; */
0427 
0428             /* note the -2 below, it's to make sure the chunk has */
0429             /* space for the CRC value */
0430             if (crcstart - 2 >= cstart && crcstart < cend)
0431                 break;
0432         }
0433         if (c >= nfchunks) {
0434             pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n",
0435                    i, s3crc[i].addr, s3crc[i].len);
0436             return 1;
0437         }
0438 
0439         /* Insert crc */
0440         pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
0441         chunkoff = crcstart - cstart - 2;
0442         dest = fchunk[c].data + chunkoff;
0443         *dest = 0xde;
0444         *(dest + 1) = 0xc0;
0445     }
0446     return result;
0447 }
0448 
0449 /*----------------------------------------------------------------
0450  * free_chunks
0451  *
0452  * Clears the chunklist data structures in preparation for a new file.
0453  *
0454  * Arguments:
0455  *  none
0456  *
0457  * Returns:
0458  *  nothing
0459  *----------------------------------------------------------------
0460  */
0461 static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
0462 {
0463     int i;
0464 
0465     for (i = 0; i < *nfchunks; i++)
0466         kfree(fchunk[i].data);
0467 
0468     *nfchunks = 0;
0469     memset(fchunk, 0, sizeof(*fchunk));
0470 }
0471 
0472 /*----------------------------------------------------------------
0473  * free_srecs
0474  *
0475  * Clears the srec data structures in preparation for a new file.
0476  *
0477  * Arguments:
0478  *  none
0479  *
0480  * Returns:
0481  *  nothing
0482  *----------------------------------------------------------------
0483  */
0484 static void free_srecs(void)
0485 {
0486     ns3data = 0;
0487     kfree(s3data);
0488     ns3plug = 0;
0489     memset(s3plug, 0, sizeof(s3plug));
0490     ns3crc = 0;
0491     memset(s3crc, 0, sizeof(s3crc));
0492     ns3info = 0;
0493     memset(s3info, 0, sizeof(s3info));
0494     startaddr = 0;
0495 }
0496 
0497 /*----------------------------------------------------------------
0498  * mkimage
0499  *
0500  * Scans the currently loaded set of S records for data residing
0501  * in contiguous memory regions.  Each contiguous region is then
0502  * made into a 'chunk'.  This function assumes that we're building
0503  * a new chunk list.  Assumes the s3data items are in sorted order.
0504  *
0505  * Arguments:   none
0506  *
0507  * Returns:
0508  *  0   - success
0509  *  ~0  - failure (probably an errno)
0510  *----------------------------------------------------------------
0511  */
0512 static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
0513 {
0514     int result = 0;
0515     int i;
0516     int j;
0517     int currchunk = 0;
0518     u32 nextaddr = 0;
0519     u32 s3start;
0520     u32 s3end;
0521     u32 cstart = 0;
0522     u32 cend;
0523     u32 coffset;
0524 
0525     /* There may already be data in the chunklist */
0526     *ccnt = 0;
0527 
0528     /* Establish the location and size of each chunk */
0529     for (i = 0; i < ns3data; i++) {
0530         if (s3data[i].addr == nextaddr) {
0531             /* existing chunk, grow it */
0532             clist[currchunk].len += s3data[i].len;
0533             nextaddr += s3data[i].len;
0534         } else {
0535             /* New chunk */
0536             (*ccnt)++;
0537             currchunk = *ccnt - 1;
0538             clist[currchunk].addr = s3data[i].addr;
0539             clist[currchunk].len = s3data[i].len;
0540             nextaddr = s3data[i].addr + s3data[i].len;
0541             /* Expand the chunk if there is a CRC record at */
0542             /* their beginning bound */
0543             for (j = 0; j < ns3crc; j++) {
0544                 if (s3crc[j].dowrite &&
0545                     s3crc[j].addr == clist[currchunk].addr) {
0546                     clist[currchunk].addr -= 2;
0547                     clist[currchunk].len += 2;
0548                 }
0549             }
0550         }
0551     }
0552 
0553     /* We're currently assuming there aren't any overlapping chunks */
0554     /*  if this proves false, we'll need to add code to coalesce. */
0555 
0556     /* Allocate buffer space for chunks */
0557     for (i = 0; i < *ccnt; i++) {
0558         clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
0559         if (!clist[i].data)
0560             return 1;
0561 
0562         pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
0563              i, clist[i].addr, clist[i].len);
0564     }
0565 
0566     /* Copy srec data to chunks */
0567     for (i = 0; i < ns3data; i++) {
0568         s3start = s3data[i].addr;
0569         s3end = s3start + s3data[i].len - 1;
0570         for (j = 0; j < *ccnt; j++) {
0571             cstart = clist[j].addr;
0572             cend = cstart + clist[j].len - 1;
0573             if (s3start >= cstart && s3end <= cend)
0574                 break;
0575         }
0576         if (((unsigned int)j) >= (*ccnt)) {
0577             pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
0578                    s3start, s3data[i].len);
0579             return 1;
0580         }
0581         coffset = s3start - cstart;
0582         memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
0583     }
0584 
0585     return result;
0586 }
0587 
0588 /*----------------------------------------------------------------
0589  * mkpdrlist
0590  *
0591  * Reads a raw PDA and builds an array of pdrec_t structures.
0592  *
0593  * Arguments:
0594  *  pda buffer containing raw PDA bytes
0595  *  pdrec   ptr to an array of pdrec_t's.  Will be filled on exit.
0596  *  nrec    ptr to a variable that will contain the count of PDRs
0597  *
0598  * Returns:
0599  *  0   - success
0600  *  ~0  - failure (probably an errno)
0601  *----------------------------------------------------------------
0602  */
0603 static int mkpdrlist(struct pda *pda)
0604 {
0605     __le16 *pda16 = (__le16 *)pda->buf;
0606     int curroff;        /* in 'words' */
0607 
0608     pda->nrec = 0;
0609     curroff = 0;
0610     while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) &&
0611            le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
0612         pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
0613 
0614         if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
0615             HFA384x_PDR_NICID) {
0616             memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
0617                    sizeof(nicid));
0618             le16_to_cpus(&nicid.id);
0619             le16_to_cpus(&nicid.variant);
0620             le16_to_cpus(&nicid.major);
0621             le16_to_cpus(&nicid.minor);
0622         }
0623         if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
0624             HFA384x_PDR_MFISUPRANGE) {
0625             memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
0626                    sizeof(rfid));
0627             le16_to_cpus(&rfid.id);
0628             le16_to_cpus(&rfid.variant);
0629             le16_to_cpus(&rfid.bottom);
0630             le16_to_cpus(&rfid.top);
0631         }
0632         if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
0633             HFA384x_PDR_CFISUPRANGE) {
0634             memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
0635                    sizeof(macid));
0636             le16_to_cpus(&macid.id);
0637             le16_to_cpus(&macid.variant);
0638             le16_to_cpus(&macid.bottom);
0639             le16_to_cpus(&macid.top);
0640         }
0641 
0642         (pda->nrec)++;
0643         curroff += le16_to_cpu(pda16[curroff]) + 1;
0644     }
0645     if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) {
0646         pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n",
0647                curroff, pda->nrec);
0648         return 1;
0649     }
0650     pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
0651     (pda->nrec)++;
0652     return 0;
0653 }
0654 
0655 /*----------------------------------------------------------------
0656  * plugimage
0657  *
0658  * Plugs the given image using the given plug records from the given
0659  * PDA and filename.
0660  *
0661  * Arguments:
0662  *  fchunk      Array of image chunks
0663  *  nfchunks    Number of image chunks
0664  *  s3plug      Array of plug records
0665  *  ns3plug     Number of plug records
0666  *  pda     Current pda data
0667  *
0668  * Returns:
0669  *  0   success
0670  *  ~0  failure
0671  *----------------------------------------------------------------
0672  */
0673 static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
0674              struct s3plugrec *s3plug, unsigned int ns3plug,
0675              struct pda *pda)
0676 {
0677     int result = 0;
0678     int i;          /* plug index */
0679     int j;          /* index of PDR or -1 if fname plug */
0680     int c;          /* chunk index */
0681     u32 pstart;
0682     u32 pend;
0683     u32 cstart = 0;
0684     u32 cend;
0685     u32 chunkoff;
0686     u8 *dest;
0687 
0688     /* for each plug record */
0689     for (i = 0; i < ns3plug; i++) {
0690         pstart = s3plug[i].addr;
0691         pend = s3plug[i].addr + s3plug[i].len;
0692         /* find the matching PDR (or filename) */
0693         if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */
0694             for (j = 0; j < pda->nrec; j++) {
0695                 if (s3plug[i].itemcode ==
0696                     le16_to_cpu(pda->rec[j]->code))
0697                     break;
0698             }
0699         } else {
0700             j = -1;
0701         }
0702         if (j >= pda->nrec && j != -1) { /*  if no matching PDR, fail */
0703             pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
0704                 s3plug[i].itemcode);
0705             continue;   /* and move on to the next PDR */
0706 
0707             /* MSM: They swear that unless it's the MAC address,
0708              * the serial number, or the TX calibration records,
0709              * then there's reasonable defaults in the f/w
0710              * image.  Therefore, missing PDRs in the card
0711              * should only be a warning, not fatal.
0712              * TODO: add fatals for the PDRs mentioned above.
0713              */
0714         }
0715 
0716         /* Validate plug len against PDR len */
0717         if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
0718             pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n",
0719                    s3plug[i].itemcode);
0720             result = 1;
0721             continue;
0722         }
0723 
0724         /*
0725          * Validate plug address against
0726          * chunk data and identify chunk
0727          */
0728         for (c = 0; c < nfchunks; c++) {
0729             cstart = fchunk[c].addr;
0730             cend = fchunk[c].addr + fchunk[c].len;
0731             if (pstart >= cstart && pend <= cend)
0732                 break;
0733         }
0734         if (c >= nfchunks) {
0735             pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n",
0736                    s3plug[i].itemcode);
0737             result = 1;
0738             continue;
0739         }
0740 
0741         /* Plug data */
0742         chunkoff = pstart - cstart;
0743         dest = fchunk[c].data + chunkoff;
0744         pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n",
0745              s3plug[i].itemcode, pstart, s3plug[i].len,
0746              c, chunkoff);
0747 
0748         if (j == -1) {  /* plug the filename */
0749             memset(dest, 0, s3plug[i].len);
0750             strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
0751         } else {    /* plug a PDR */
0752             memcpy(dest, &pda->rec[j]->data, s3plug[i].len);
0753         }
0754     }
0755     return result;
0756 }
0757 
0758 /*----------------------------------------------------------------
0759  * read_cardpda
0760  *
0761  * Sends the command for the driver to read the pda from the card
0762  * named in the device variable.  Upon success, the card pda is
0763  * stored in the "cardpda" variables.  Note that the pda structure
0764  * is considered 'well formed' after this function.  That means
0765  * that the nrecs is valid, the rec array has been set up, and there's
0766  * a valid PDAEND record in the raw PDA data.
0767  *
0768  * Arguments:
0769  *  pda     pda structure
0770  *  wlandev     device
0771  *
0772  * Returns:
0773  *  0   - success
0774  *  ~0  - failure (probably an errno)
0775  *----------------------------------------------------------------
0776  */
0777 static int read_cardpda(struct pda *pda, struct wlandevice *wlandev)
0778 {
0779     int result = 0;
0780     struct p80211msg_p2req_readpda *msg;
0781 
0782     msg = kzalloc(sizeof(*msg), GFP_KERNEL);
0783     if (!msg)
0784         return -ENOMEM;
0785 
0786     /* set up the msg */
0787     msg->msgcode = DIDMSG_P2REQ_READPDA;
0788     msg->msglen = sizeof(msg);
0789     strscpy(msg->devname, wlandev->name, sizeof(msg->devname));
0790     msg->pda.did = DIDMSG_P2REQ_READPDA_PDA;
0791     msg->pda.len = HFA384x_PDA_LEN_MAX;
0792     msg->pda.status = P80211ENUM_msgitem_status_no_value;
0793     msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE;
0794     msg->resultcode.len = sizeof(u32);
0795     msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
0796 
0797     if (prism2mgmt_readpda(wlandev, msg) != 0) {
0798         /* prism2mgmt_readpda prints an errno if appropriate */
0799         result = -1;
0800     } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
0801         memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
0802         result = mkpdrlist(pda);
0803     } else {
0804         /* resultcode must've been something other than success */
0805         result = -1;
0806     }
0807 
0808     kfree(msg);
0809     return result;
0810 }
0811 
0812 /*----------------------------------------------------------------
0813  * read_fwfile
0814  *
0815  * Reads the given fw file which should have been compiled from an srec
0816  * file. Each record in the fw file will either be a plain data record,
0817  * a start address record, or other records used for plugging.
0818  *
0819  * Note that data records are expected to be sorted into
0820  * ascending address order in the fw file.
0821  *
0822  * Note also that the start address record, originally an S7 record in
0823  * the srec file, is expected in the fw file to be like a data record but
0824  * with a certain address to make it identifiable.
0825  *
0826  * Here's the SREC format that the fw should have come from:
0827  * S[37]nnaaaaaaaaddd...dddcc
0828  *
0829  *       nn - number of bytes starting with the address field
0830  * aaaaaaaa - address in readable (or big endian) format
0831  * dd....dd - 0-245 data bytes (two chars per byte)
0832  *       cc - checksum
0833  *
0834  * The S7 record's (there should be only one) address value gets
0835  * converted to an S3 record with address of 0xff400000, with the
0836  * start address being stored as a 4 byte data word. That address is
0837  * the start execution address used for RAM downloads.
0838  *
0839  * The S3 records have a collection of subformats indicated by the
0840  * value of aaaaaaaa:
0841  *   0xff000000 - Plug record, data field format:
0842  *                xxxxxxxxaaaaaaaassssssss
0843  *                x - PDR code number (little endian)
0844  *                a - Address in load image to plug (little endian)
0845  *                s - Length of plug data area (little endian)
0846  *
0847  *   0xff100000 - CRC16 generation record, data field format:
0848  *                aaaaaaaassssssssbbbbbbbb
0849  *                a - Start address for CRC calculation (little endian)
0850  *                s - Length of data to  calculate over (little endian)
0851  *                b - Boolean, true=write crc, false=don't write
0852  *
0853  *   0xff200000 - Info record, data field format:
0854  *                ssssttttdd..dd
0855  *                s - Size in words (little endian)
0856  *                t - Info type (little endian), see #defines and
0857  *                    struct s3inforec for details about types.
0858  *                d - (s - 1) little endian words giving the contents of
0859  *                    the given info type.
0860  *
0861  *   0xff400000 - Start address record, data field format:
0862  *                aaaaaaaa
0863  *                a - Address in load image to plug (little endian)
0864  *
0865  * Arguments:
0866  *  record  firmware image (ihex record structure) in kernel memory
0867  *
0868  * Returns:
0869  *  0   - success
0870  *  ~0  - failure (probably an errno)
0871  *----------------------------------------------------------------
0872  */
0873 static int read_fwfile(const struct ihex_binrec *record)
0874 {
0875     int     i;
0876     int     rcnt = 0;
0877     u16     *tmpinfo;
0878     u16     *ptr16;
0879     u32     *ptr32, len, addr;
0880 
0881     pr_debug("Reading fw file ...\n");
0882 
0883     while (record) {
0884         rcnt++;
0885 
0886         len = be16_to_cpu(record->len);
0887         addr = be32_to_cpu(record->addr);
0888 
0889         /* Point into data for different word lengths */
0890         ptr32 = (u32 *)record->data;
0891         ptr16 = (u16 *)record->data;
0892 
0893         /* parse what was an S3 srec and put it in the right array */
0894         switch (addr) {
0895         case S3ADDR_START:
0896             startaddr = *ptr32;
0897             pr_debug("  S7 start addr, record=%d addr=0x%08x\n",
0898                  rcnt,
0899                  startaddr);
0900             break;
0901         case S3ADDR_PLUG:
0902             s3plug[ns3plug].itemcode = *ptr32;
0903             s3plug[ns3plug].addr = *(ptr32 + 1);
0904             s3plug[ns3plug].len = *(ptr32 + 2);
0905 
0906             pr_debug("  S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n",
0907                  rcnt,
0908                  s3plug[ns3plug].itemcode,
0909                  s3plug[ns3plug].addr,
0910                  s3plug[ns3plug].len);
0911 
0912             ns3plug++;
0913             if (ns3plug == S3PLUG_MAX) {
0914                 pr_err("S3 plugrec limit reached - aborting\n");
0915                 return 1;
0916             }
0917             break;
0918         case S3ADDR_CRC:
0919             s3crc[ns3crc].addr = *ptr32;
0920             s3crc[ns3crc].len = *(ptr32 + 1);
0921             s3crc[ns3crc].dowrite = *(ptr32 + 2);
0922 
0923             pr_debug("  S3 crcrec, record=%d addr=0x%08x len=%d write=0x%08x\n",
0924                  rcnt,
0925                  s3crc[ns3crc].addr,
0926                  s3crc[ns3crc].len,
0927                  s3crc[ns3crc].dowrite);
0928             ns3crc++;
0929             if (ns3crc == S3CRC_MAX) {
0930                 pr_err("S3 crcrec limit reached - aborting\n");
0931                 return 1;
0932             }
0933             break;
0934         case S3ADDR_INFO:
0935             s3info[ns3info].len = *ptr16;
0936             s3info[ns3info].type = *(ptr16 + 1);
0937 
0938             pr_debug("  S3 inforec, record=%d len=0x%04x type=0x%04x\n",
0939                  rcnt,
0940                  s3info[ns3info].len,
0941                  s3info[ns3info].type);
0942             if (((s3info[ns3info].len - 1) * sizeof(u16)) >
0943                sizeof(s3info[ns3info].info)) {
0944                 pr_err("S3 inforec length too long - aborting\n");
0945                 return 1;
0946             }
0947 
0948             tmpinfo = (u16 *)&s3info[ns3info].info.version;
0949             pr_debug("            info=");
0950             for (i = 0; i < s3info[ns3info].len - 1; i++) {
0951                 tmpinfo[i] = *(ptr16 + 2 + i);
0952                 pr_debug("%04x ", tmpinfo[i]);
0953             }
0954             pr_debug("\n");
0955 
0956             ns3info++;
0957             if (ns3info == S3INFO_MAX) {
0958                 pr_err("S3 inforec limit reached - aborting\n");
0959                 return 1;
0960             }
0961             break;
0962         default:    /* Data record */
0963             s3data[ns3data].addr = addr;
0964             s3data[ns3data].len = len;
0965             s3data[ns3data].data = (uint8_t *)record->data;
0966             ns3data++;
0967             if (ns3data == S3DATA_MAX) {
0968                 pr_err("S3 datarec limit reached - aborting\n");
0969                 return 1;
0970             }
0971             break;
0972         }
0973         record = ihex_next_binrec(record);
0974     }
0975     return 0;
0976 }
0977 
0978 /*----------------------------------------------------------------
0979  * writeimage
0980  *
0981  * Takes the chunks, builds p80211 messages and sends them down
0982  * to the driver for writing to the card.
0983  *
0984  * Arguments:
0985  *  wlandev     device
0986  *  fchunk      Array of image chunks
0987  *  nfchunks    Number of image chunks
0988  *
0989  * Returns:
0990  *  0   success
0991  *  ~0  failure
0992  *----------------------------------------------------------------
0993  */
0994 static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
0995               unsigned int nfchunks)
0996 {
0997     int result = 0;
0998     struct p80211msg_p2req_ramdl_state *rstmsg;
0999     struct p80211msg_p2req_ramdl_write *rwrmsg;
1000     u32 resultcode;
1001     int i;
1002     int j;
1003     unsigned int nwrites;
1004     u32 curroff;
1005     u32 currlen;
1006     u32 currdaddr;
1007 
1008     rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL);
1009     rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL);
1010     if (!rstmsg || !rwrmsg) {
1011         kfree(rstmsg);
1012         kfree(rwrmsg);
1013         netdev_err(wlandev->netdev,
1014                "%s: no memory for firmware download, aborting download\n",
1015                __func__);
1016         return -ENOMEM;
1017     }
1018 
1019     /* Initialize the messages */
1020     strscpy(rstmsg->devname, wlandev->name, sizeof(rstmsg->devname));
1021     rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE;
1022     rstmsg->msglen = sizeof(*rstmsg);
1023     rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE;
1024     rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR;
1025     rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE;
1026     rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
1027     rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
1028     rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1029     rstmsg->enable.len = sizeof(u32);
1030     rstmsg->exeaddr.len = sizeof(u32);
1031     rstmsg->resultcode.len = sizeof(u32);
1032 
1033     strscpy(rwrmsg->devname, wlandev->name, sizeof(rwrmsg->devname));
1034     rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE;
1035     rwrmsg->msglen = sizeof(*rwrmsg);
1036     rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR;
1037     rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN;
1038     rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA;
1039     rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE;
1040     rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
1041     rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
1042     rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
1043     rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1044     rwrmsg->addr.len = sizeof(u32);
1045     rwrmsg->len.len = sizeof(u32);
1046     rwrmsg->data.len = WRITESIZE_MAX;
1047     rwrmsg->resultcode.len = sizeof(u32);
1048 
1049     /* Send xxx_state(enable) */
1050     pr_debug("Sending dl_state(enable) message.\n");
1051     rstmsg->enable.data = P80211ENUM_truth_true;
1052     rstmsg->exeaddr.data = startaddr;
1053 
1054     result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1055     if (result) {
1056         netdev_err(wlandev->netdev,
1057                "%s state enable failed w/ result=%d, aborting download\n",
1058                __func__, result);
1059         goto free_result;
1060     }
1061     resultcode = rstmsg->resultcode.data;
1062     if (resultcode != P80211ENUM_resultcode_success) {
1063         netdev_err(wlandev->netdev,
1064                "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1065                __func__, resultcode);
1066         result = 1;
1067         goto free_result;
1068     }
1069 
1070     /* Now, loop through the data chunks and send WRITESIZE_MAX data */
1071     for (i = 0; i < nfchunks; i++) {
1072         nwrites = fchunk[i].len / WRITESIZE_MAX;
1073         nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1074         curroff = 0;
1075         for (j = 0; j < nwrites; j++) {
1076             /* TODO Move this to a separate function */
1077             int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
1078 
1079             if (fchunk[i].len > WRITESIZE_MAX)
1080                 currlen = WRITESIZE_MAX;
1081             else
1082                 currlen = lenleft;
1083             curroff = j * WRITESIZE_MAX;
1084             currdaddr = fchunk[i].addr + curroff;
1085             /* Setup the message */
1086             rwrmsg->addr.data = currdaddr;
1087             rwrmsg->len.data = currlen;
1088             memcpy(rwrmsg->data.data,
1089                    fchunk[i].data + curroff, currlen);
1090 
1091             /* Send flashdl_write(pda) */
1092             pr_debug
1093                 ("Sending xxxdl_write message addr=%06x len=%d.\n",
1094                  currdaddr, currlen);
1095 
1096             result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
1097 
1098             /* Check the results */
1099             if (result) {
1100                 netdev_err(wlandev->netdev,
1101                        "%s chunk write failed w/ result=%d, aborting download\n",
1102                        __func__, result);
1103                 goto free_result;
1104             }
1105             resultcode = rstmsg->resultcode.data;
1106             if (resultcode != P80211ENUM_resultcode_success) {
1107                 pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n",
1108                        __func__, resultcode);
1109                 result = 1;
1110                 goto free_result;
1111             }
1112         }
1113     }
1114 
1115     /* Send xxx_state(disable) */
1116     pr_debug("Sending dl_state(disable) message.\n");
1117     rstmsg->enable.data = P80211ENUM_truth_false;
1118     rstmsg->exeaddr.data = 0;
1119 
1120     result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1121     if (result) {
1122         netdev_err(wlandev->netdev,
1123                "%s state disable failed w/ result=%d, aborting download\n",
1124                __func__, result);
1125         goto free_result;
1126     }
1127     resultcode = rstmsg->resultcode.data;
1128     if (resultcode != P80211ENUM_resultcode_success) {
1129         netdev_err(wlandev->netdev,
1130                "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1131                __func__, resultcode);
1132         result = 1;
1133         goto free_result;
1134     }
1135 
1136 free_result:
1137     kfree(rstmsg);
1138     kfree(rwrmsg);
1139     return result;
1140 }
1141 
1142 static int validate_identity(void)
1143 {
1144     int i;
1145     int result = 1;
1146     int trump = 0;
1147 
1148     pr_debug("NIC ID: %#x v%d.%d.%d\n",
1149          nicid.id, nicid.major, nicid.minor, nicid.variant);
1150     pr_debug("MFI ID: %#x v%d %d->%d\n",
1151          rfid.id, rfid.variant, rfid.bottom, rfid.top);
1152     pr_debug("CFI ID: %#x v%d %d->%d\n",
1153          macid.id, macid.variant, macid.bottom, macid.top);
1154     pr_debug("PRI ID: %#x v%d %d->%d\n",
1155          priid.id, priid.variant, priid.bottom, priid.top);
1156 
1157     for (i = 0; i < ns3info; i++) {
1158         switch (s3info[i].type) {
1159         case 1:
1160             pr_debug("Version:  ID %#x %d.%d.%d\n",
1161                  s3info[i].info.version.id,
1162                  s3info[i].info.version.major,
1163                  s3info[i].info.version.minor,
1164                  s3info[i].info.version.variant);
1165             break;
1166         case 2:
1167             pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1168                  s3info[i].info.compat.role,
1169                  s3info[i].info.compat.id,
1170                  s3info[i].info.compat.variant,
1171                  s3info[i].info.compat.bottom,
1172                  s3info[i].info.compat.top);
1173 
1174             /* MAC compat range */
1175             if ((s3info[i].info.compat.role == 1) &&
1176                 (s3info[i].info.compat.id == 2)) {
1177                 if (s3info[i].info.compat.variant !=
1178                     macid.variant) {
1179                     result = 2;
1180                 }
1181             }
1182 
1183             /* PRI compat range */
1184             if ((s3info[i].info.compat.role == 1) &&
1185                 (s3info[i].info.compat.id == 3)) {
1186                 if ((s3info[i].info.compat.bottom >
1187                      priid.top) ||
1188                     (s3info[i].info.compat.top <
1189                      priid.bottom)) {
1190                     result = 3;
1191                 }
1192             }
1193             /* SEC compat range */
1194             if ((s3info[i].info.compat.role == 1) &&
1195                 (s3info[i].info.compat.id == 4)) {
1196                 /* FIXME: isn't something missing here? */
1197             }
1198 
1199             break;
1200         case 3:
1201             pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1202 
1203             break;
1204         case 4:
1205             pr_debug("Platform:  ID %#x %d.%d.%d\n",
1206                  s3info[i].info.version.id,
1207                  s3info[i].info.version.major,
1208                  s3info[i].info.version.minor,
1209                  s3info[i].info.version.variant);
1210 
1211             if (nicid.id != s3info[i].info.version.id)
1212                 continue;
1213             if (nicid.major != s3info[i].info.version.major)
1214                 continue;
1215             if (nicid.minor != s3info[i].info.version.minor)
1216                 continue;
1217             if ((nicid.variant != s3info[i].info.version.variant) &&
1218                 (nicid.id != 0x8008))
1219                 continue;
1220 
1221             trump = 1;
1222             break;
1223         case 0x8001:
1224             pr_debug("name inforec len %d\n", s3info[i].len);
1225 
1226             break;
1227         default:
1228             pr_debug("Unknown inforec type %d\n", s3info[i].type);
1229         }
1230     }
1231     /* walk through */
1232 
1233     if (trump && (result != 2))
1234         result = 0;
1235     return result;
1236 }