Merge tag 'please-pull-fix-ia64-warnings' of git://git.kernel.org/pub/scm/linux/kerne...
[firefly-linux-kernel-4.4.55.git] / drivers / staging / csr / csr_wifi_hip_xbv.c
1 /*****************************************************************************
2
3             (c) Cambridge Silicon Radio Limited 2012
4             All rights reserved and confidential information of CSR
5
6             Refer to LICENSE.txt included with this source for details
7             on the license terms.
8
9 *****************************************************************************/
10
11 /*
12  * ---------------------------------------------------------------------------
13  * FILE: csr_wifi_hip_xbv.c
14  *
15  * PURPOSE:
16  *      Routines for downloading firmware to UniFi.
17  *
18  *      UniFi firmware files use a nested TLV (Tag-Length-Value) format.
19  *
20  * ---------------------------------------------------------------------------
21  */
22 #include <linux/slab.h>
23
24 #ifdef CSR_WIFI_XBV_TEST
25 /* Standalone test harness */
26 #include "unifi_xbv.h"
27 #include "csr_wifi_hip_unifihw.h"
28 #else
29 /* Normal driver build */
30 #include "csr_wifi_hip_unifiversion.h"
31 #include "csr_wifi_hip_card.h"
32 #define DBG_TAG(t)
33 #endif
34
35 #include "csr_wifi_hip_xbv.h"
36
37 #define STREAM_CHECKSUM 0x6d34        /* Sum of uint16s in each patch stream */
38
39 /* XBV sizes used in patch conversion
40  */
41 #define PTDL_MAX_SIZE 2048            /* Max bytes allowed per PTDL */
42 #define PTDL_HDR_SIZE (4 + 2 + 6 + 2) /* sizeof(fw_id, sec_len, patch_cmd, csum) */
43
44 /* Struct to represent a buffer for reading firmware file */
45
46 typedef struct
47 {
48     void      *dlpriv;
49     s32   ioffset;
50     fwreadfn_t iread;
51 } ct_t;
52
53 /* Struct to represent a TLV field */
54 typedef struct
55 {
56     char t_name[4];
57     u32     t_len;
58 } tag_t;
59
60
61 #define TAG_EQ(i, v)    (((i)[0] == (v)[0]) &&  \
62                          ((i)[1] == (v)[1]) &&  \
63                          ((i)[2] == (v)[2]) &&  \
64                          ((i)[3] == (v)[3]))
65
66 /* We create a small stack on the stack that contains an enum
67  * indicating the containing list segments, and the offset at which
68  * those lists end.  This enables a lot more error checking. */
69 typedef enum
70 {
71     xbv_xbv1,
72     /*xbv_info,*/
73     xbv_fw,
74     xbv_vers,
75     xbv_vand,
76     xbv_ptch,
77     xbv_other
78 } xbv_container;
79
80 #define XBV_STACK_SIZE 6
81 #define XBV_MAX_OFFS   0x7fffffff
82
83 typedef struct
84 {
85     struct
86     {
87         xbv_container container;
88         s32      ioffset_end;
89     } s[XBV_STACK_SIZE];
90     u32 ptr;
91 } xbv_stack_t;
92
93 static s32 read_tag(card_t *card, ct_t *ct, tag_t *tag);
94 static s32 read_bytes(card_t *card, ct_t *ct, void *buf, u32 len);
95 static s32 read_uint(card_t *card, ct_t *ct, u32 *u, u32 len);
96 static s32 xbv_check(xbv1_t *fwinfo, const xbv_stack_t *stack,
97                           xbv_mode new_mode, xbv_container old_cont);
98 static s32 xbv_push(xbv1_t *fwinfo, xbv_stack_t *stack,
99                          xbv_mode new_mode, xbv_container old_cont,
100                          xbv_container new_cont, u32 ioff);
101
102 static u32 write_uint16(void *buf, const u32 offset,
103                               const u16 val);
104 static u32 write_uint32(void *buf, const u32 offset,
105                               const u32 val);
106 static u32 write_bytes(void *buf, const u32 offset,
107                              const u8 *data, const u32 len);
108 static u32 write_tag(void *buf, const u32 offset,
109                            const char *tag_str);
110 static u32 write_chunk(void *buf, const u32 offset,
111                              const char *tag_str,
112                              const u32 payload_len);
113 static u16 calc_checksum(void *buf, const u32 offset,
114                                const u32 bytes_len);
115 static u32 calc_patch_size(const xbv1_t *fwinfo);
116
117 static u32 write_xbv_header(void *buf, const u32 offset,
118                                   const u32 file_payload_length);
119 static u32 write_ptch_header(void *buf, const u32 offset,
120                                    const u32 fw_id);
121 static u32 write_patchcmd(void *buf, const u32 offset,
122                                 const u32 dst_genaddr, const u16 len);
123 static u32 write_reset_ptdl(void *buf, const u32 offset,
124                                   const xbv1_t *fwinfo, u32 fw_id);
125 static u32 write_fwdl_to_ptdl(void *buf, const u32 offset,
126                                     fwreadfn_t readfn, const struct FWDL *fwdl,
127                                     const void *fw_buf, const u32 fw_id,
128                                     void *rdbuf);
129
130 /*
131  * ---------------------------------------------------------------------------
132  *  parse_xbv1
133  *
134  *      Scan the firmware file to find the TLVs we are interested in.
135  *      Actions performed:
136  *        - check we support the file format version in VERF
137  *      Store these TLVs if we have a firmware image:
138  *        - SLTP Symbol Lookup Table Pointer
139  *        - FWDL firmware download segments
140  *        - FWOL firmware overlay segment
141  *        - VMEQ Register probe tests to verify matching h/w
142  *      Store these TLVs if we have a patch file:
143  *        - FWID the firmware build ID that this file patches
144  *        - PTDL The actual patches
145  *
146  *      The structure pointed to by fwinfo is cleared and
147  *      'fwinfo->mode' is set to 'unknown'.  The 'fwinfo->mode'
148  *      variable is set to 'firmware' or 'patch' once we know which
149  *      sort of XBV file we have.
150  *
151  *  Arguments:
152  *      readfn          Pointer to function to call to read from the file.
153  *      dlpriv          Opaque pointer arg to pass to readfn.
154  *      fwinfo          Pointer to fwinfo struct to fill in.
155  *
156  *  Returns:
157  *      CSR_RESULT_SUCCESS on success, CSR error code on failure
158  * ---------------------------------------------------------------------------
159  */
160 CsrResult xbv1_parse(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo)
161 {
162     ct_t ct;
163     tag_t tag;
164     xbv_stack_t stack;
165
166     ct.dlpriv = dlpriv;
167     ct.ioffset = 0;
168     ct.iread = readfn;
169
170     memset(fwinfo, 0, sizeof(xbv1_t));
171     fwinfo->mode = xbv_unknown;
172
173     /* File must start with XBV1 triplet */
174     if (read_tag(card, &ct, &tag) <= 0)
175     {
176         unifi_error(NULL, "File is not UniFi firmware\n");
177         return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
178     }
179
180     DBG_TAG(tag.t_name);
181
182     if (!TAG_EQ(tag.t_name, "XBV1"))
183     {
184         unifi_error(NULL, "File is not UniFi firmware (%s)\n", tag.t_name);
185         return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
186     }
187
188     stack.ptr = 0;
189     stack.s[stack.ptr].container = xbv_xbv1;
190     stack.s[stack.ptr].ioffset_end = XBV_MAX_OFFS;
191
192     /* Now scan the file */
193     while (1)
194     {
195         s32 n;
196
197         n = read_tag(card, &ct, &tag);
198         if (n < 0)
199         {
200             unifi_error(NULL, "No tag\n");
201             return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
202         }
203         if (n == 0)
204         {
205             /* End of file */
206             break;
207         }
208
209         DBG_TAG(tag.t_name);
210
211         /* File format version */
212         if (TAG_EQ(tag.t_name, "VERF"))
213         {
214             u32 version;
215
216             if (xbv_check(fwinfo, &stack, xbv_unknown, xbv_xbv1) ||
217                 (tag.t_len != 2) ||
218                 read_uint(card, &ct, &version, 2))
219             {
220                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
221             }
222             if (version != 0)
223             {
224                 unifi_error(NULL, "Unsupported firmware file version: %d.%d\n",
225                             version >> 8, version & 0xFF);
226                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
227             }
228         }
229         else if (TAG_EQ(tag.t_name, "LIST"))
230         {
231             char name[4];
232             u32 list_end;
233
234             list_end = ct.ioffset + tag.t_len;
235
236             if (read_bytes(card, &ct, name, 4))
237             {
238                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
239             }
240
241             DBG_TAG(name);
242             if (TAG_EQ(name, "FW  "))
243             {
244                 if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_xbv1, xbv_fw, list_end))
245                 {
246                     return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
247                 }
248             }
249             else if (TAG_EQ(name, "VERS"))
250             {
251                 if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_fw, xbv_vers, list_end) ||
252                     (fwinfo->vers.num_vand != 0))
253                 {
254                     return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
255                 }
256             }
257             else if (TAG_EQ(name, "VAND"))
258             {
259                 struct VAND *vand;
260
261                 if (xbv_push(fwinfo, &stack, xbv_firmware, xbv_vers, xbv_vand, list_end) ||
262                     (fwinfo->vers.num_vand >= MAX_VAND))
263                 {
264                     return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
265                 }
266
267                 /* Get a new VAND */
268                 vand = fwinfo->vand + fwinfo->vers.num_vand++;
269
270                 /* Fill it in */
271                 vand->first = fwinfo->num_vmeq;
272                 vand->count = 0;
273             }
274             else if (TAG_EQ(name, "PTCH"))
275             {
276                 if (xbv_push(fwinfo, &stack, xbv_patch, xbv_xbv1, xbv_ptch, list_end))
277                 {
278                     return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
279                 }
280             }
281             else
282             {
283                 /* Skip over any other lists.  We dont bother to push
284                  * the new list type now as we would only pop it at
285                  * the end of the outer loop. */
286                 ct.ioffset += tag.t_len - 4;
287             }
288         }
289         else if (TAG_EQ(tag.t_name, "SLTP"))
290         {
291             u32 addr;
292
293             if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
294                 (tag.t_len != 4) ||
295                 (fwinfo->slut_addr != 0) ||
296                 read_uint(card, &ct, &addr, 4))
297             {
298                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
299             }
300
301             fwinfo->slut_addr = addr;
302         }
303         else if (TAG_EQ(tag.t_name, "FWDL"))
304         {
305             u32 addr;
306             struct FWDL *fwdl;
307
308             if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
309                 (fwinfo->num_fwdl >= MAX_FWDL) ||
310                 (read_uint(card, &ct, &addr, 4)))
311             {
312                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
313             }
314
315             fwdl = fwinfo->fwdl + fwinfo->num_fwdl++;
316
317             fwdl->dl_size = tag.t_len - 4;
318             fwdl->dl_addr = addr;
319             fwdl->dl_offset = ct.ioffset;
320
321             ct.ioffset += tag.t_len - 4;
322         }
323         else if (TAG_EQ(tag.t_name, "FWOV"))
324         {
325             if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_fw) ||
326                 (fwinfo->fwov.dl_size != 0) ||
327                 (fwinfo->fwov.dl_offset != 0))
328             {
329                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
330             }
331
332             fwinfo->fwov.dl_size = tag.t_len;
333             fwinfo->fwov.dl_offset = ct.ioffset;
334
335             ct.ioffset += tag.t_len;
336         }
337         else if (TAG_EQ(tag.t_name, "VMEQ"))
338         {
339             u32 temp[3];
340             struct VAND *vand;
341             struct VMEQ *vmeq;
342
343             if (xbv_check(fwinfo, &stack, xbv_firmware, xbv_vand) ||
344                 (fwinfo->num_vmeq >= MAX_VMEQ) ||
345                 (fwinfo->vers.num_vand == 0) ||
346                 (tag.t_len != 8) ||
347                 read_uint(card, &ct, &temp[0], 4) ||
348                 read_uint(card, &ct, &temp[1], 2) ||
349                 read_uint(card, &ct, &temp[2], 2))
350             {
351                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
352             }
353
354             /* Get the last VAND */
355             vand = fwinfo->vand + (fwinfo->vers.num_vand - 1);
356
357             /* Get a new VMEQ */
358             vmeq = fwinfo->vmeq + fwinfo->num_vmeq++;
359
360             /* Note that this VAND contains another VMEQ */
361             vand->count++;
362
363             /* Fill in the VMEQ */
364             vmeq->addr = temp[0];
365             vmeq->mask = (u16)temp[1];
366             vmeq->value = (u16)temp[2];
367         }
368         else if (TAG_EQ(tag.t_name, "FWID"))
369         {
370             u32 build_id;
371
372             if (xbv_check(fwinfo, &stack, xbv_patch, xbv_ptch) ||
373                 (tag.t_len != 4) ||
374                 (fwinfo->build_id != 0) ||
375                 read_uint(card, &ct, &build_id, 4))
376             {
377                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
378             }
379
380             fwinfo->build_id = build_id;
381         }
382         else if (TAG_EQ(tag.t_name, "PTDL"))
383         {
384             struct PTDL *ptdl;
385
386             if (xbv_check(fwinfo, &stack, xbv_patch, xbv_ptch) ||
387                 (fwinfo->num_ptdl >= MAX_PTDL))
388             {
389                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
390             }
391
392             /* Allocate a new PTDL */
393             ptdl = fwinfo->ptdl + fwinfo->num_ptdl++;
394
395             ptdl->dl_size = tag.t_len;
396             ptdl->dl_offset = ct.ioffset;
397
398             ct.ioffset += tag.t_len;
399         }
400         else
401         {
402             /*
403              * If we get here it is a tag we are not interested in,
404              * just skip over it.
405              */
406             ct.ioffset += tag.t_len;
407         }
408
409         /* Check to see if we are at the end of the currently stacked
410          * segment.  We could finish more than one list at a time. */
411         while (ct.ioffset >= stack.s[stack.ptr].ioffset_end)
412         {
413             if (ct.ioffset > stack.s[stack.ptr].ioffset_end)
414             {
415                 unifi_error(NULL,
416                             "XBV file has overrun stack'd segment %d (%d > %d)\n",
417                             stack.ptr, ct.ioffset, stack.s[stack.ptr].ioffset_end);
418                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
419             }
420             if (stack.ptr <= 0)
421             {
422                 unifi_error(NULL, "XBV file has underrun stack pointer\n");
423                 return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
424             }
425             stack.ptr--;
426         }
427     }
428
429     if (stack.ptr != 0)
430     {
431         unifi_error(NULL, "Last list of XBV is not complete.\n");
432         return CSR_WIFI_HIP_RESULT_INVALID_VALUE;
433     }
434
435     return CSR_RESULT_SUCCESS;
436 } /* xbv1_parse() */
437
438
439 /* Check the the XBV file is of a consistant sort (either firmware or
440  * patch) and that we are in the correct containing list type. */
441 static s32 xbv_check(xbv1_t *fwinfo, const xbv_stack_t *stack,
442                           xbv_mode new_mode, xbv_container old_cont)
443 {
444     /* If the new file mode is unknown the current packet could be in
445      * either (any) type of XBV file, and we cant make a decission at
446      * this time. */
447     if (new_mode != xbv_unknown)
448     {
449         if (fwinfo->mode == xbv_unknown)
450         {
451             fwinfo->mode = new_mode;
452         }
453         else if (fwinfo->mode != new_mode)
454         {
455             return -1;
456         }
457     }
458     /* If the current stack top doesn't match what we expect then the
459      * file is corrupt. */
460     if (stack->s[stack->ptr].container != old_cont)
461     {
462         return -1;
463     }
464     return 0;
465 }
466
467
468 /* Make checks as above and then enter a new list */
469 static s32 xbv_push(xbv1_t *fwinfo, xbv_stack_t *stack,
470                          xbv_mode new_mode, xbv_container old_cont,
471                          xbv_container new_cont, u32 new_ioff)
472 {
473     if (xbv_check(fwinfo, stack, new_mode, old_cont))
474     {
475         return -1;
476     }
477
478     /* Check that our stack won't overflow. */
479     if (stack->ptr >= (XBV_STACK_SIZE - 1))
480     {
481         return -1;
482     }
483
484     /* Add the new list element to the top of the stack. */
485     stack->ptr++;
486     stack->s[stack->ptr].container = new_cont;
487     stack->s[stack->ptr].ioffset_end = new_ioff;
488
489     return 0;
490 }
491
492
493 static u32 xbv2uint(u8 *ptr, s32 len)
494 {
495     u32 u = 0;
496     s16 i;
497
498     for (i = 0; i < len; i++)
499     {
500         u32 b;
501         b = ptr[i];
502         u += b << (i * 8);
503     }
504     return u;
505 }
506
507
508 static s32 read_tag(card_t *card, ct_t *ct, tag_t *tag)
509 {
510     u8 buf[8];
511     s32 n;
512
513     n = (*ct->iread)(card->ospriv, ct->dlpriv, ct->ioffset, buf, 8);
514     if (n <= 0)
515     {
516         return n;
517     }
518
519     /* read the tag and length */
520     if (n != 8)
521     {
522         return -1;
523     }
524
525     /* get section tag */
526     memcpy(tag->t_name, buf, 4);
527
528     /* get section length */
529     tag->t_len = xbv2uint(buf + 4, 4);
530
531     ct->ioffset += 8;
532
533     return 8;
534 } /* read_tag() */
535
536
537 static s32 read_bytes(card_t *card, ct_t *ct, void *buf, u32 len)
538 {
539     /* read the tag value */
540     if ((*ct->iread)(card->ospriv, ct->dlpriv, ct->ioffset, buf, len) != (s32)len)
541     {
542         return -1;
543     }
544
545     ct->ioffset += len;
546
547     return 0;
548 } /* read_bytes() */
549
550
551 static s32 read_uint(card_t *card, ct_t *ct, u32 *u, u32 len)
552 {
553     u8 buf[4];
554
555     /* Integer cannot be more than 4 bytes */
556     if (len > 4)
557     {
558         return -1;
559     }
560
561     if (read_bytes(card, ct, buf, len))
562     {
563         return -1;
564     }
565
566     *u = xbv2uint(buf, len);
567
568     return 0;
569 } /* read_uint() */
570
571
572 static u32 write_uint16(void *buf, const u32 offset, const u16 val)
573 {
574     u8 *dst = (u8 *)buf + offset;
575     *dst++ = (u8)(val & 0xff); /* LSB first */
576     *dst = (u8)(val >> 8);
577     return sizeof(u16);
578 }
579
580
581 static u32 write_uint32(void *buf, const u32 offset, const u32 val)
582 {
583     (void)write_uint16(buf, offset + 0, (u16)(val & 0xffff));
584     (void)write_uint16(buf, offset + 2, (u16)(val >> 16));
585     return sizeof(u32);
586 }
587
588
589 static u32 write_bytes(void *buf, const u32 offset, const u8 *data, const u32 len)
590 {
591     u32 i;
592     u8 *dst = (u8 *)buf + offset;
593
594     for (i = 0; i < len; i++)
595     {
596         *dst++ = *((u8 *)data + i);
597     }
598     return len;
599 }
600
601
602 static u32 write_tag(void *buf, const u32 offset, const char *tag_str)
603 {
604     u8 *dst = (u8 *)buf + offset;
605     memcpy(dst, tag_str, 4);
606     return 4;
607 }
608
609
610 static u32 write_chunk(void *buf, const u32 offset, const char *tag_str, const u32 payload_len)
611 {
612     u32 written = 0;
613     written += write_tag(buf, offset, tag_str);
614     written += write_uint32(buf, written + offset, (u32)payload_len);
615
616     return written;
617 }
618
619
620 static u16 calc_checksum(void *buf, const u32 offset, const u32 bytes_len)
621 {
622     u32 i;
623     u8 *src = (u8 *)buf + offset;
624     u16 sum = 0;
625     u16 val;
626
627     for (i = 0; i < bytes_len / 2; i++)
628     {
629         /* Contents copied to file is LE, host might not be */
630         val = (u16) * src++;         /* LSB */
631         val += (u16)(*src++) << 8;   /* MSB */
632         sum += val;
633     }
634
635     /* Total of uint16s in the stream plus the stored check value
636      * should equal STREAM_CHECKSUM when decoded.
637      */
638     return (STREAM_CHECKSUM - sum);
639 }
640
641
642 #define PTDL_RESET_DATA_SIZE  20  /* Size of reset vectors PTDL */
643
644 static u32 calc_patch_size(const xbv1_t *fwinfo)
645 {
646     s16 i;
647     u32 size = 0;
648
649     /*
650      * Work out how big an equivalent patch format file must be for this image.
651      * This only needs to be approximate, so long as it's large enough.
652      */
653     if (fwinfo->mode != xbv_firmware)
654     {
655         return 0;
656     }
657
658     /* Payload (which will get put into a series of PTDLs) */
659     for (i = 0; i < fwinfo->num_fwdl; i++)
660     {
661         size += fwinfo->fwdl[i].dl_size;
662     }
663
664     /* Another PTDL at the end containing reset vectors */
665     size += PTDL_RESET_DATA_SIZE;
666
667     /* PTDL headers. Add one for remainder, one for reset vectors */
668     size += ((fwinfo->num_fwdl / PTDL_MAX_SIZE) + 2) * PTDL_HDR_SIZE;
669
670     /* Another 1K sufficient to cover miscellaneous headers */
671     size += 1024;
672
673     return size;
674 }
675
676
677 static u32 write_xbv_header(void *buf, const u32 offset, const u32 file_payload_length)
678 {
679     u32 written = 0;
680
681     /* The length value given to the XBV chunk is the length of all subsequent
682      * contents of the file, excluding the 8 byte size of the XBV1 header itself
683      * (The added 6 bytes thus accounts for the size of the VERF)
684      */
685     written += write_chunk(buf, offset + written, (char *)"XBV1", file_payload_length + 6);
686
687     written += write_chunk(buf, offset + written, (char *)"VERF", 2);
688     written += write_uint16(buf,  offset + written, 0);      /* File version */
689
690     return written;
691 }
692
693
694 static u32 write_ptch_header(void *buf, const u32 offset, const u32 fw_id)
695 {
696     u32 written = 0;
697
698     /* LIST is written with a zero length, to be updated later */
699     written += write_chunk(buf, offset + written, (char *)"LIST", 0);
700     written += write_tag(buf, offset + written, (char *)"PTCH");        /* List type */
701
702     written += write_chunk(buf, offset + written, (char *)"FWID", 4);
703     written += write_uint32(buf, offset + written, fw_id);
704
705
706     return written;
707 }
708
709
710 #define UF_REGION_PHY  1
711 #define UF_REGION_MAC  2
712 #define UF_MEMPUT_MAC  0x0000
713 #define UF_MEMPUT_PHY  0x1000
714
715 static u32 write_patchcmd(void *buf, const u32 offset, const u32 dst_genaddr, const u16 len)
716 {
717     u32 written = 0;
718     u32 region = (dst_genaddr >> 28);
719     u16 cmd_and_len = UF_MEMPUT_MAC;
720
721     if (region == UF_REGION_PHY)
722     {
723         cmd_and_len = UF_MEMPUT_PHY;
724     }
725     else if (region != UF_REGION_MAC)
726     {
727         return 0; /* invalid */
728     }
729
730     /* Write the command and data length */
731     cmd_and_len |= len;
732     written += write_uint16(buf, offset + written, cmd_and_len);
733
734     /* Write the destination generic address */
735     written += write_uint16(buf, offset + written, (u16)(dst_genaddr >> 16));
736     written += write_uint16(buf, offset + written, (u16)(dst_genaddr & 0xffff));
737
738     /* The data payload should be appended to the command */
739     return written;
740 }
741
742
743 static u32 write_fwdl_to_ptdl(void *buf, const u32 offset, fwreadfn_t readfn,
744                                     const struct FWDL *fwdl, const void *dlpriv,
745                                     const u32 fw_id, void *fw_buf)
746 {
747     u32 written = 0;
748     s16 chunks = 0;
749     u32 left = fwdl->dl_size;      /* Bytes left in this fwdl */
750     u32 dl_addr = fwdl->dl_addr;   /* Target address of fwdl image on XAP */
751     u32 dl_offs = fwdl->dl_offset; /* Offset of fwdl image data in source */
752     u16 csum;
753     u32 csum_start_offs;           /* first offset to include in checksum */
754     u32 sec_data_len;              /* section data byte count */
755     u32 sec_len;                   /* section data + header byte count */
756
757     /* FWDL maps to one or more PTDLs, as max size for a PTDL is 1K words */
758     while (left)
759     {
760         /* Calculate amount to be transferred */
761         sec_data_len = min_t(u32, left, PTDL_MAX_SIZE - PTDL_HDR_SIZE);
762         sec_len = sec_data_len + PTDL_HDR_SIZE;
763
764         /* Write PTDL header + entire PTDL size */
765         written += write_chunk(buf, offset + written, (char *)"PTDL", sec_len);
766         /* bug digest implies 4 bytes of padding here, but that seems wrong */
767
768         /* Checksum starts here */
769         csum_start_offs = offset + written;
770
771         /* Patch-chunk header: fw_id. Note that this is in XAP word order */
772         written += write_uint16(buf, offset + written, (u16)(fw_id >> 16));
773         written += write_uint16(buf, offset + written, (u16)(fw_id & 0xffff));
774
775         /* Patch-chunk header: section length in uint16s */
776         written += write_uint16(buf, offset + written, (u16)(sec_len / 2));
777
778
779         /* Write the appropriate patch command for the data's destination ptr */
780         written += write_patchcmd(buf, offset + written, dl_addr, (u16)(sec_data_len / 2));
781
782         /* Write the data itself (limited to the max chunk length) */
783         if (readfn(NULL, (void *)dlpriv, dl_offs, fw_buf, sec_data_len) < 0)
784         {
785             return 0;
786         }
787
788         written += write_bytes(buf,
789                                offset + written,
790                                fw_buf,
791                                sec_data_len);
792
793         /* u16 checksum calculated over data written */
794         csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
795         written += write_uint16(buf, offset + written, csum);
796
797         left -= sec_data_len;
798         dl_addr += sec_data_len;
799         dl_offs += sec_data_len;
800         chunks++;
801     }
802
803     return written;
804 }
805
806
807 #define SEC_CMD_LEN         ((4 + 2) * 2) /* sizeof(cmd, vector) per XAP */
808 #define PTDL_VEC_HDR_SIZE   (4 + 2 + 2)   /* sizeof(fw_id, sec_len, csum) */
809 #define UF_MAC_START_VEC    0x00c00000    /* Start address of image on MAC */
810 #define UF_PHY_START_VEC    0x00c00000    /* Start address of image on PHY */
811 #define UF_MAC_START_CMD    0x6000        /* MAC "Set start address" command */
812 #define UF_PHY_START_CMD    0x7000        /* PHY "Set start address" command */
813
814 static u32 write_reset_ptdl(void *buf, const u32 offset, const xbv1_t *fwinfo, u32 fw_id)
815 {
816     u32 written = 0;
817     u16 csum;
818     u32 csum_start_offs;                 /* first offset to include in checksum */
819     u32 sec_len;                         /* section data + header byte count */
820
821     sec_len = SEC_CMD_LEN + PTDL_VEC_HDR_SIZE; /* Total section byte length */
822
823     /* Write PTDL header + entire PTDL size */
824     written += write_chunk(buf, offset + written, (char *)"PTDL", sec_len);
825
826     /* Checksum starts here */
827     csum_start_offs = offset + written;
828
829     /* Patch-chunk header: fw_id. Note that this is in XAP word order */
830     written += write_uint16(buf, offset + written, (u16)(fw_id >> 16));
831     written += write_uint16(buf, offset + written, (u16)(fw_id & 0xffff));
832
833     /* Patch-chunk header: section length in uint16s */
834     written += write_uint16(buf, offset + written, (u16)(sec_len / 2));
835
836     /*
837      * Restart addresses to be executed on subsequent loader restart command.
838      */
839
840     /* Setup the MAC start address, note word ordering */
841     written += write_uint16(buf, offset + written, UF_MAC_START_CMD);
842     written += write_uint16(buf, offset + written, (UF_MAC_START_VEC >> 16));
843     written += write_uint16(buf, offset + written, (UF_MAC_START_VEC & 0xffff));
844
845     /* Setup the PHY start address, note word ordering */
846     written += write_uint16(buf, offset + written, UF_PHY_START_CMD);
847     written += write_uint16(buf, offset + written, (UF_PHY_START_VEC >> 16));
848     written += write_uint16(buf, offset + written, (UF_PHY_START_VEC & 0xffff));
849
850     /* u16 checksum calculated over data written */
851     csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
852     written += write_uint16(buf, offset + written, csum);
853
854     return written;
855 }
856
857
858 /*
859  * ---------------------------------------------------------------------------
860  *  read_slut
861  *
862  *      desc
863  *
864  *  Arguments:
865  *      readfn          Pointer to function to call to read from the file.
866  *      dlpriv          Opaque pointer arg to pass to readfn.
867  *      addr            Offset into firmware image of SLUT.
868  *      fwinfo          Pointer to fwinfo struct to fill in.
869  *
870  *  Returns:
871  *      Number of SLUT entries in the f/w, or -1 if the image was corrupt.
872  * ---------------------------------------------------------------------------
873  */
874 s32 xbv1_read_slut(card_t *card, fwreadfn_t readfn, void *dlpriv, xbv1_t *fwinfo,
875                         symbol_t *slut, u32 slut_len)
876 {
877     s16 i;
878     s32 offset;
879     u32 magic;
880     u32 count = 0;
881     ct_t ct;
882
883     if (fwinfo->mode != xbv_firmware)
884     {
885         return -1;
886     }
887
888     /* Find the d/l segment containing the SLUT */
889     /* This relies on the SLUT being entirely contained in one segment */
890     offset = -1;
891     for (i = 0; i < fwinfo->num_fwdl; i++)
892     {
893         if ((fwinfo->slut_addr >= fwinfo->fwdl[i].dl_addr) &&
894             (fwinfo->slut_addr < (fwinfo->fwdl[i].dl_addr + fwinfo->fwdl[i].dl_size)))
895         {
896             offset = fwinfo->fwdl[i].dl_offset +
897                      (fwinfo->slut_addr - fwinfo->fwdl[i].dl_addr);
898         }
899     }
900     if (offset < 0)
901     {
902         return -1;
903     }
904
905     ct.dlpriv = dlpriv;
906     ct.ioffset = offset;
907     ct.iread = readfn;
908
909     if (read_uint(card, &ct, &magic, 2))
910     {
911         return -1;
912     }
913     if (magic != SLUT_FINGERPRINT)
914     {
915         return -1;
916     }
917
918     while (count < slut_len)
919     {
920         u32 id, obj;
921
922         /* Read Symbol Id */
923         if (read_uint(card, &ct, &id, 2))
924         {
925             return -1;
926         }
927
928         /* Check for end of table marker */
929         if (id == CSR_SLT_END)
930         {
931             break;
932         }
933
934         /* Read Symbol Value */
935         if (read_uint(card, &ct, &obj, 4))
936         {
937             return -1;
938         }
939
940         slut[count].id  = (u16)id;
941         slut[count].obj = obj;
942         count++;
943     }
944
945     return count;
946 } /* read_slut() */
947
948
949 /*
950  * ---------------------------------------------------------------------------
951  *  xbv_to_patch
952  *
953  *      Convert (the relevant parts of) a firmware xbv file into a patch xbv
954  *
955  *  Arguments:
956  *      card
957  *      fw_buf - pointer to xbv firmware image
958  *      fwinfo - structure describing the firmware image
959  *      size   - pointer to location into which size of f/w is written.
960  *
961  *  Returns:
962  *      Pointer to firmware image, or NULL on error. Caller must free this
963  *      buffer via kfree() once it's finished with.
964  *
965  *  Notes:
966  *      The input fw_buf should have been checked via xbv1_parse prior to
967  *      calling this function, so the input image is assumed valid.
968  * ---------------------------------------------------------------------------
969  */
970 #define PTCH_LIST_SIZE 16         /* sizeof PTCH+FWID chunk in LIST header */
971
972 void* xbv_to_patch(card_t *card, fwreadfn_t readfn,
973                    const void *fw_buf, const xbv1_t *fwinfo, u32 *size)
974 {
975     void *patch_buf = NULL;
976     u32 patch_buf_size;
977     u32 payload_offs = 0;           /* Start of XBV payload */
978     s16 i;
979     u32 patch_offs = 0;
980     u32 list_len_offs = 0;          /* Offset of PTDL LIST length parameter */
981     u32 ptdl_start_offs = 0;        /* Offset of first PTDL chunk */
982     u32 fw_id;
983     void *rdbuf;
984
985     if (!fw_buf || !fwinfo || !card)
986     {
987         return NULL;
988     }
989
990     if (fwinfo->mode != xbv_firmware)
991     {
992         unifi_error(NULL, "Not a firmware file\n");
993         return NULL;
994     }
995
996     /* Pre-allocate read buffer for chunk conversion */
997     rdbuf = kmalloc(PTDL_MAX_SIZE, GFP_KERNEL);
998     if (!rdbuf)
999     {
1000         unifi_error(card, "Couldn't alloc conversion buffer\n");
1001         return NULL;
1002     }
1003
1004     /* Loader requires patch file's build ID to match the running firmware's */
1005     fw_id = card->build_id;
1006
1007     /* Firmware XBV1 contains VERF, optional INFO, SLUT(s), FWDL(s)          */
1008     /* Other chunks should get skipped.                                      */
1009     /* VERF should be sanity-checked against chip version                    */
1010
1011     /* Patch    XBV1 contains VERF, optional INFO, PTCH                      */
1012     /*          PTCH contains FWID, optional INFO, PTDL(s), PTDL(start_vec)  */
1013     /* Each FWDL is split into PTDLs (each is 1024 XAP words max)            */
1014     /* Each PTDL contains running ROM f/w version, and checksum              */
1015     /* MAC/PHY reset addresses (known) are added into a final PTDL           */
1016
1017     /* The input image has already been parsed, and loaded into fwinfo, so we
1018      * can use that to build the output image
1019      */
1020     patch_buf_size = calc_patch_size(fwinfo);
1021
1022     patch_buf = kmalloc(patch_buf_size, GFP_KERNEL);
1023     if (!patch_buf)
1024     {
1025         kfree(rdbuf);
1026         unifi_error(NULL, "Can't malloc buffer for patch conversion\n");
1027         return NULL;
1028     }
1029
1030     memset(patch_buf, 0xdd, patch_buf_size);
1031
1032     /* Write XBV + VERF headers */
1033     patch_offs += write_xbv_header(patch_buf, patch_offs, 0);
1034     payload_offs = patch_offs;
1035
1036     /* Write patch (LIST) header */
1037     list_len_offs = patch_offs + 4;    /* Save LIST.length offset for later update */
1038     patch_offs += write_ptch_header(patch_buf, patch_offs, fw_id);
1039
1040     /* Save start offset of the PTDL chunks */
1041     ptdl_start_offs = patch_offs;
1042
1043     /* Write LIST of firmware PTDL blocks */
1044     for (i = 0; i < fwinfo->num_fwdl; i++)
1045     {
1046         patch_offs += write_fwdl_to_ptdl(patch_buf,
1047                                          patch_offs,
1048                                          readfn,
1049                                          &fwinfo->fwdl[i],
1050                                          fw_buf,
1051                                          fw_id,
1052                                          rdbuf);
1053     }
1054
1055     /* Write restart-vector PTDL last */
1056     patch_offs += write_reset_ptdl(patch_buf, patch_offs, fwinfo, fw_id);
1057
1058     /* Now the length is known, update the LIST.length */
1059     (void)write_uint32(patch_buf, list_len_offs,
1060                        (patch_offs - ptdl_start_offs) + PTCH_LIST_SIZE);
1061
1062     /* Re write XBV headers just to fill in the correct file size */
1063     (void)write_xbv_header(patch_buf, 0, (patch_offs - payload_offs));
1064
1065     unifi_trace(card->ospriv, UDBG1, "XBV:PTCH size %u, fw_id %u\n",
1066                 patch_offs, fw_id);
1067     if (size)
1068     {
1069         *size = patch_offs;
1070     }
1071     kfree(rdbuf);
1072
1073     return patch_buf;
1074 }
1075
1076