bcdc.c revision 8141083c48192b63a39b77adffd9a8e0dcfab034
15b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 25b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Copyright (c) 2010 Broadcom Corporation 35b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 45b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Permission to use, copy, modify, and/or distribute this software for any 55b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * purpose with or without fee is hereby granted, provided that the above 65b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * copyright notice and this permission notice appear in all copies. 75b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * 85b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 95b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 135b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 145b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/******************************************************************************* 185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Communicates with the dongle by using dcmd codes. 195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * For certain dcmd codes, the dongle interprets string data from the host. 205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ******************************************************************************/ 215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 225b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/types.h> 235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <linux/netdevice.h> 245b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_utils.h> 265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include <brcmu_wifi.h> 275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 285b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd.h" 295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_bus.h" 30349e7104ff662eeacca1fffbb480c287562c45a1Arend van Spriel#include "fwsignal.h" 315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#include "dhd_dbg.h" 32ea0737d6e24b44b632e9094108bb987b0338ea74Arend van Spriel#include "tracepoint.h" 3385b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman#include "proto.h" 3485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman#include "bcdc.h" 355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meulemanstruct brcmf_proto_bcdc_dcmd { 375b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 cmd; /* dongle command value */ 385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 len; /* lower 16: output buflen; 395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * upper 16: input buflen (excludes header) */ 405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 flags; /* flag defns given below */ 415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel __le32 status; /* status code returned from the device */ 425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* Max valid buffer size that can be sent to the dongle */ 45aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) 46aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman 47aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman/* BCDC flag definitions */ 48aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */ 49aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ 50aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */ 51aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_IF_SHIFT 12 52aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ 53aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ 54aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_DCMD_ID(flags) \ 55aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT) 565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel/* 58aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman * BCDC header - Broadcom specific extension of CDC. 595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * Used on data packets to convey priority across USB. 605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 61aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_HEADER_LEN 4 62aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_PROTO_VER 2 /* Protocol version */ 63aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ 64aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ 65aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ 66aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ 67aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_PRIORITY_MASK 0x7 68aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ 69aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_FLAG2_IF_SHIFT 0 70aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman 71aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_GET_IF_IDX(hdr) \ 72aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT)) 73aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman#define BCDC_SET_IF_IDX(hdr, idx) \ 74aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \ 75aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman ((idx) << BCDC_FLAG2_IF_SHIFT))) 765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 77bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel/** 78aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman * struct brcmf_proto_bcdc_header - BCDC header format 79bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * 80bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * @flags: flags contain protocol and checksum info. 81bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * @priority: 802.1d priority and USB flow control info (bit 4:7). 82bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * @flags2: additional flags containing dongle interface index. 83bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * @data_offset: start of packet data. header is following by firmware signals. 84bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel */ 85aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meulemanstruct brcmf_proto_bcdc_header { 865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 flags; 87bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel u8 priority; 885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 flags2; 89e40aed0638ac84d63a2ff33502e215ac81010a89Franky Lin u8 data_offset; 905b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 92bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel/* 93bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel * maximum length of firmware signal data between 94aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman * the BCDC header and packet data in the tx path. 95bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel */ 96bee1b848877b9e4512bdda480f73cda12b593e2fArend van Spriel#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12 975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ 996e3c712807237ab2b50e860d94dc8f15a81d03cdFranky Lin#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE 1005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * (amount of header tha might be added) 1015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel * plus any space that might be needed 1026e3c712807237ab2b50e860d94dc8f15a81d03cdFranky Lin * for bus alignment padding. 1035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel */ 10485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanstruct brcmf_bcdc { 1055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u16 reqid; 1065b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u8 bus_header[BUS_HEADER_LEN]; 107aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman struct brcmf_proto_bcdc_dcmd msg; 1088141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman unsigned char buf[BRCMF_DCMD_MAXLEN]; 1095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel}; 1105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1118141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman 1128141083c48192b63a39b77adffd9a8e0dcfab034Hante Meulemanstatic int 1138141083c48192b63a39b77adffd9a8e0dcfab034Hante Meulemanbrcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, 1148141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman uint len, bool set) 1155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 11685b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 1178141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 1188141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman u32 flags; 1195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 120aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter\n"); 1215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1228141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd)); 1238141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman 1248141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman msg->cmd = cpu_to_le32(cmd); 1258141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman msg->len = cpu_to_le32(len); 1268141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT); 1278141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman if (set) 1288141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman flags |= BCDC_DCMD_SET; 1298141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman flags = (flags & ~BCDC_DCMD_IF_MASK) | 1308141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman (ifidx << BCDC_DCMD_IF_SHIFT); 1318141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman msg->flags = cpu_to_le32(flags); 1328141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman 1338141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman if (buf) 1348141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman memcpy(bcdc->buf, buf, len); 1355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1365b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Send request */ 1378141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, 1388141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman len + sizeof(struct brcmf_proto_bcdc_dcmd)); 1395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 1405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 141aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meulemanstatic int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) 1425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 1435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret; 14485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 1455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 146aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter\n"); 147aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman len += sizeof(struct brcmf_proto_bcdc_dcmd); 1485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel do { 14985b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg, 150d9cb2596503d937ccf68b83d3aff1056765a6b1eArend van Spriel len); 1515b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) 1525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel break; 153aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id); 1545b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 1565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 1575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 15885b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanstatic int 15985b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanbrcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 16085b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman void *buf, uint len) 1615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 16285b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 163aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 1645b435de0d786869c95d1962121af0d7df2542009Arend van Spriel void *info; 1655b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret = 0, retries = 0; 1665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 id, flags; 1675b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 168aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 1695b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1708141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, false); 1715b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) { 172aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n", 1735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret); 1745b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 1755b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 1765b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1775b435de0d786869c95d1962121af0d7df2542009Arend van Sprielretry: 1785b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* wait for interrupt and get first fragment */ 179aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 1805b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) 1815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 1825b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1835b435de0d786869c95d1962121af0d7df2542009Arend van Spriel flags = le32_to_cpu(msg->flags); 184aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 1855b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 18685b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman if ((id < bcdc->reqid) && (++retries < RETRIES)) 1875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto retry; 18885b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman if (id != bcdc->reqid) { 1895e8149f5036afe2d94b5fafc9ff752283804a752Arend van Spriel brcmf_err("%s: unexpected request id %d (expected %d)\n", 19085b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman brcmf_ifname(drvr, ifidx), id, bcdc->reqid); 1915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -EINVAL; 1925b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 1935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 1945b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check info buffer */ 1965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel info = (void *)&msg[1]; 1975b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 1985b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Copy info buffer */ 1995b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (buf) { 2005b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < (int)len) 2015b435de0d786869c95d1962121af0d7df2542009Arend van Spriel len = ret; 2025b435de0d786869c95d1962121af0d7df2542009Arend van Spriel memcpy(buf, info, len); 2035b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2045b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check the ERROR flag */ 206aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (flags & BCDC_DCMD_ERROR) 2075b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = le32_to_cpu(msg->status); 2085b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2095b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone: 2105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 2115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 2125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 21385b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanstatic int 21485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanbrcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, 21585b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman void *buf, uint len) 2165b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 21785b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd; 218aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg; 2195b435de0d786869c95d1962121af0d7df2542009Arend van Spriel int ret = 0; 2205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel u32 flags, id; 2215b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 222aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len); 2235b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2248141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman ret = brcmf_proto_bcdc_msg(drvr, ifidx, cmd, buf, len, true); 2255b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) 2265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 2275b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 228aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len); 2295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (ret < 0) 2305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 2315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2325b435de0d786869c95d1962121af0d7df2542009Arend van Spriel flags = le32_to_cpu(msg->flags); 233aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT; 2345b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 23585b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman if (id != bcdc->reqid) { 2365e8149f5036afe2d94b5fafc9ff752283804a752Arend van Spriel brcmf_err("%s: unexpected request id %d (expected %d)\n", 23785b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman brcmf_ifname(drvr, ifidx), id, bcdc->reqid); 2385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = -EINVAL; 2395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto done; 2405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2415b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2425b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Check the ERROR flag */ 243aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (flags & BCDC_DCMD_ERROR) 2445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel ret = le32_to_cpu(msg->status); 2455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2465b435de0d786869c95d1962121af0d7df2542009Arend van Sprieldone: 2475b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return ret; 2485b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 2495b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 25085b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanstatic void 25185b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanbrcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset, 2525b435de0d786869c95d1962121af0d7df2542009Arend van Spriel struct sk_buff *pktbuf) 2535b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 254aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman struct brcmf_proto_bcdc_header *h; 2555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 256aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter\n"); 2575b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 2585b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* Push BDC header used to convey priority for buses that don't */ 259aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman skb_push(pktbuf, BCDC_HEADER_LEN); 2605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 261aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 2625b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 263aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT); 264aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (pktbuf->ip_summed == CHECKSUM_PARTIAL) 265aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman h->flags |= BCDC_FLAG_SUM_NEEDED; 2665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 267aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK); 2685b435de0d786869c95d1962121af0d7df2542009Arend van Spriel h->flags2 = 0; 2698f0c3b6d44e09f497f57ca2997d903c5602336a1Arend van Spriel h->data_offset = offset; 270aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman BCDC_SET_IF_IDX(h, ifidx); 271aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman trace_brcmf_bcdchdr(pktbuf->data); 2725b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 2735b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 27485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanstatic int 27585b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanbrcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx, 27685b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct sk_buff *pktbuf) 2775b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 278aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman struct brcmf_proto_bcdc_header *h; 2795b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 280aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "Enter\n"); 2815b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 282aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman /* Pop BCDC header used to convey priority for buses that don't */ 283aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (pktbuf->len <= BCDC_HEADER_LEN) { 2845cd02c7747596078e6b01f07f978fa8a10f4e9daPiotr Haber brcmf_dbg(INFO, "rx data too short (%d <= %d)\n", 285aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman pktbuf->len, BCDC_HEADER_LEN); 2865b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 2875b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2885b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 289aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman trace_brcmf_bcdchdr(pktbuf->data); 290aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman h = (struct brcmf_proto_bcdc_header *)(pktbuf->data); 2915b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 292aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman *ifidx = BCDC_GET_IF_IDX(h); 2935b435de0d786869c95d1962121af0d7df2542009Arend van Spriel if (*ifidx >= BRCMF_MAX_IFS) { 2945e8149f5036afe2d94b5fafc9ff752283804a752Arend van Spriel brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); 2955b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 2965b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 2972880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman /* The ifidx is the idx to map to matching netdev/ifp. When receiving 2982880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman * events this is easy because it contains the bssidx which maps 2992880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. 3002880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman * bssidx 1 is used for p2p0 and no data can be received or 3012880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 3022880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman */ 3032880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman if (*ifidx) 3042880b86859967af710c72f7d34fb421a86a71e22Hante Meuleman (*ifidx)++; 3055b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 306aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) != 307aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman BCDC_PROTO_VER) { 308aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_err("%s: non-BCDC packet received, flags 0x%x\n", 3095b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_ifname(drvr, *ifidx), h->flags); 3105b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -EBADE; 3115b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3125b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 313aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman if (h->flags & BCDC_FLAG_SUM_GOOD) { 314aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n", 3155b435de0d786869c95d1962121af0d7df2542009Arend van Spriel brcmf_ifname(drvr, *ifidx), h->flags); 316aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman pktbuf->ip_summed = CHECKSUM_UNNECESSARY; 3175b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3185b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 319aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman pktbuf->priority = h->priority & BCDC_PRIORITY_MASK; 3205b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 321aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman skb_pull(pktbuf, BCDC_HEADER_LEN); 322349e7104ff662eeacca1fffbb480c287562c45a1Arend van Spriel if (do_fws) 323349e7104ff662eeacca1fffbb480c287562c45a1Arend van Spriel brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf); 324349e7104ff662eeacca1fffbb480c287562c45a1Arend van Spriel else 325349e7104ff662eeacca1fffbb480c287562c45a1Arend van Spriel skb_pull(pktbuf, h->data_offset << 2); 3265b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 327a43af515f6252e62604a1bfc139d43fa43ef5b6fArend van Spriel if (pktbuf->len == 0) 328a43af515f6252e62604a1bfc139d43fa43ef5b6fArend van Spriel return -ENODATA; 3295b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 3305b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3315b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33285b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanint brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) 3335b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 33485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman struct brcmf_bcdc *bcdc; 3355b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 33685b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC); 33785b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman if (!bcdc) 3385b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 3395b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3405b435de0d786869c95d1962121af0d7df2542009Arend van Spriel /* ensure that the msg buf directly follows the cdc msg struct */ 34185b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) { 34285b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n"); 3435b435de0d786869c95d1962121af0d7df2542009Arend van Spriel goto fail; 3445b435de0d786869c95d1962121af0d7df2542009Arend van Spriel } 3455b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 34685b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush; 34785b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull; 34885b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd; 34985b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd; 35085b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->pd = bcdc; 35185b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman 352aec87ce2f38c54dc7ef9bff2038e3b102a4e6c0cHante Meuleman drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; 353b01a6b3ca714e2bb86ee387aee487c7360363c93Franky Lin drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN + 3548141083c48192b63a39b77adffd9a8e0dcfab034Hante Meuleman sizeof(struct brcmf_proto_bcdc_dcmd); 3555b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return 0; 3565b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 3575b435de0d786869c95d1962121af0d7df2542009Arend van Sprielfail: 35885b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman kfree(bcdc); 3595b435de0d786869c95d1962121af0d7df2542009Arend van Spriel return -ENOMEM; 3605b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 3615b435de0d786869c95d1962121af0d7df2542009Arend van Spriel 36285b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meulemanvoid brcmf_proto_bcdc_detach(struct brcmf_pub *drvr) 3635b435de0d786869c95d1962121af0d7df2542009Arend van Spriel{ 36485b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman kfree(drvr->proto->pd); 36585b8413371225e9bcbbb30cf3caa5889fed5f6a4Hante Meuleman drvr->proto->pd = NULL; 3665b435de0d786869c95d1962121af0d7df2542009Arend van Spriel} 367