22 #include <linux/slab.h>
24 #ifdef CSR_WIFI_XBV_TEST
26 #include "unifi_xbv.h"
37 #define STREAM_CHECKSUM 0x6d34
41 #define PTDL_MAX_SIZE 2048
42 #define PTDL_HDR_SIZE (4 + 2 + 6 + 2)
61 #define TAG_EQ(i, v) (((i)[0] == (v)[0]) && \
62 ((i)[1] == (v)[1]) && \
63 ((i)[2] == (v)[2]) && \
80 #define XBV_STACK_SIZE 6
81 #define XBV_MAX_OFFS 0x7fffffff
109 const char *tag_str);
114 const u32 bytes_len);
115 static u32 calc_patch_size(
const xbv1_t *fwinfo);
118 const u32 file_payload_length);
122 const u32 dst_genaddr,
const u16 len);
127 const void *fw_buf,
const u32 fw_id,
174 if (read_tag(card, &ct, &tag) <= 0)
197 n = read_tag(card, &ct, &tag);
218 read_uint(card, &ct, &version, 2))
225 version >> 8, version & 0xFF);
236 if (read_bytes(card, &ct, name, 4))
249 else if (
TAG_EQ(name,
"VERS"))
252 (fwinfo->
vers.num_vand != 0))
257 else if (
TAG_EQ(name,
"VAND"))
268 vand = fwinfo->
vand + fwinfo->
vers.num_vand++;
274 else if (
TAG_EQ(name,
"PTCH"))
296 read_uint(card, &ct, &addr, 4))
310 (read_uint(card, &ct, &addr, 4)))
326 (fwinfo->
fwov.dl_size != 0) ||
327 (fwinfo->
fwov.dl_offset != 0))
345 (fwinfo->
vers.num_vand == 0) ||
347 read_uint(card, &ct, &temp[0], 4) ||
348 read_uint(card, &ct, &temp[1], 2) ||
349 read_uint(card, &ct, &temp[2], 2))
355 vand = fwinfo->
vand + (fwinfo->
vers.num_vand - 1);
364 vmeq->
addr = temp[0];
375 read_uint(card, &ct, &build_id, 4))
411 while (ct.
ioffset >= stack.
s[stack.
ptr].ioffset_end)
416 "XBV file has overrun stack'd segment %d (%d > %d)\n",
451 fwinfo->
mode = new_mode;
453 else if (fwinfo->
mode != new_mode)
460 if (stack->
s[stack->
ptr].container != old_cont)
473 if (xbv_check(fwinfo, stack, new_mode, old_cont))
486 stack->
s[stack->
ptr].container = new_cont;
487 stack->
s[stack->
ptr].ioffset_end = new_ioff;
498 for (i = 0; i < len; i++)
529 tag->
t_len = xbv2uint(buf + 4, 4);
561 if (read_bytes(card, ct, buf, len))
566 *u = xbv2uint(buf, len);
575 *dst++ = (
u8)(val & 0xff);
576 *dst = (
u8)(val >> 8);
581 static u32 write_uint32(
void *buf,
const u32 offset,
const u32 val)
583 (
void)write_uint16(buf, offset + 0, (
u16)(val & 0xffff));
584 (
void)write_uint16(buf, offset + 2, (
u16)(val >> 16));
589 static u32 write_bytes(
void *buf,
const u32 offset,
const u8 *
data,
const u32 len)
592 u8 *dst = (
u8 *)buf + offset;
594 for (i = 0; i < len; i++)
596 *dst++ = *((
u8 *)data + i);
602 static u32 write_tag(
void *buf,
const u32 offset,
const char *tag_str)
604 u8 *dst = (
u8 *)buf + offset;
613 written += write_tag(buf, offset, tag_str);
614 written += write_uint32(buf, written + offset, (
u32)payload_len);
620 static u16 calc_checksum(
void *buf,
const u32 offset,
const u32 bytes_len)
627 for (i = 0; i < bytes_len / 2; i++)
631 val += (
u16)(*src++) << 8;
642 #define PTDL_RESET_DATA_SIZE 20
644 static u32 calc_patch_size(
const xbv1_t *fwinfo)
659 for (i = 0; i < fwinfo->
num_fwdl; i++)
661 size += fwinfo->
fwdl[
i].dl_size;
677 static u32 write_xbv_header(
void *buf,
const u32 offset,
const u32 file_payload_length)
685 written += write_chunk(buf, offset + written, (
char *)
"XBV1", file_payload_length + 6);
687 written += write_chunk(buf, offset + written, (
char *)
"VERF", 2);
688 written += write_uint16(buf, offset + written, 0);
694 static u32 write_ptch_header(
void *buf,
const u32 offset,
const u32 fw_id)
699 written += write_chunk(buf, offset + written, (
char *)
"LIST", 0);
700 written += write_tag(buf, offset + written, (
char *)
"PTCH");
702 written += write_chunk(buf, offset + written, (
char *)
"FWID", 4);
703 written += write_uint32(buf, offset + written, fw_id);
710 #define UF_REGION_PHY 1
711 #define UF_REGION_MAC 2
712 #define UF_MEMPUT_MAC 0x0000
713 #define UF_MEMPUT_PHY 0x1000
715 static u32 write_patchcmd(
void *buf,
const u32 offset,
const u32 dst_genaddr,
const u16 len)
732 written += write_uint16(buf, offset + written, cmd_and_len);
735 written += write_uint16(buf, offset + written, (
u16)(dst_genaddr >> 16));
736 written += write_uint16(buf, offset + written, (
u16)(dst_genaddr & 0xffff));
743 static u32 write_fwdl_to_ptdl(
void *buf,
const u32 offset,
fwreadfn_t readfn,
745 const u32 fw_id,
void *fw_buf)
765 written += write_chunk(buf, offset + written, (
char *)
"PTDL", sec_len);
769 csum_start_offs = offset + written;
772 written += write_uint16(buf, offset + written, (
u16)(fw_id >> 16));
773 written += write_uint16(buf, offset + written, (
u16)(fw_id & 0xffff));
776 written += write_uint16(buf, offset + written, (
u16)(sec_len / 2));
780 written += write_patchcmd(buf, offset + written, dl_addr, (
u16)(sec_data_len / 2));
783 if (readfn(
NULL, (
void *)dlpriv, dl_offs, fw_buf, sec_data_len) < 0)
788 written += write_bytes(buf,
794 csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
795 written += write_uint16(buf, offset + written, csum);
797 left -= sec_data_len;
798 dl_addr += sec_data_len;
799 dl_offs += sec_data_len;
807 #define SEC_CMD_LEN ((4 + 2) * 2)
808 #define PTDL_VEC_HDR_SIZE (4 + 2 + 2)
809 #define UF_MAC_START_VEC 0x00c00000
810 #define UF_PHY_START_VEC 0x00c00000
811 #define UF_MAC_START_CMD 0x6000
812 #define UF_PHY_START_CMD 0x7000
814 static u32 write_reset_ptdl(
void *buf,
const u32 offset,
const xbv1_t *fwinfo,
u32 fw_id)
824 written += write_chunk(buf, offset + written, (
char *)
"PTDL", sec_len);
827 csum_start_offs = offset + written;
830 written += write_uint16(buf, offset + written, (
u16)(fw_id >> 16));
831 written += write_uint16(buf, offset + written, (
u16)(fw_id & 0xffff));
834 written += write_uint16(buf, offset + written, (
u16)(sec_len / 2));
843 written += write_uint16(buf, offset + written, (
UF_MAC_START_VEC & 0xffff));
848 written += write_uint16(buf, offset + written, (
UF_PHY_START_VEC & 0xffff));
851 csum = calc_checksum(buf, csum_start_offs, written - (csum_start_offs - offset));
852 written += write_uint16(buf, offset + written, csum);
891 for (i = 0; i < fwinfo->
num_fwdl; i++)
896 offset = fwinfo->
fwdl[
i].dl_offset +
909 if (read_uint(card, &ct, &magic, 2))
918 while (count < slut_len)
923 if (read_uint(card, &ct, &
id, 2))
935 if (read_uint(card, &ct, &obj, 4))
941 slut[
count].obj = obj;
970 #define PTCH_LIST_SIZE 16
975 void *patch_buf =
NULL;
977 u32 payload_offs = 0;
980 u32 list_len_offs = 0;
981 u32 ptdl_start_offs = 0;
985 if (!fw_buf || !fwinfo || !card)
1000 unifi_error(card,
"Couldn't alloc conversion buffer\n");
1005 fw_id = card->build_id;
1020 patch_buf_size = calc_patch_size(fwinfo);
1030 memset(patch_buf, 0xdd, patch_buf_size);
1033 patch_offs += write_xbv_header(patch_buf, patch_offs, 0);
1034 payload_offs = patch_offs;
1037 list_len_offs = patch_offs + 4;
1038 patch_offs += write_ptch_header(patch_buf, patch_offs, fw_id);
1041 ptdl_start_offs = patch_offs;
1044 for (i = 0; i < fwinfo->
num_fwdl; i++)
1046 patch_offs += write_fwdl_to_ptdl(patch_buf,
1056 patch_offs += write_reset_ptdl(patch_buf, patch_offs, fwinfo, fw_id);
1059 (
void)write_uint32(patch_buf, list_len_offs,
1063 (
void)write_xbv_header(patch_buf, 0, (patch_offs - payload_offs));