aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFranky Lin <frankyl@broadcom.com>2012-10-22 13:36:24 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-10-29 15:28:28 -0400
commit9d7d6f95bda1fdc10847996ab849b5dd065bf047 (patch)
tree6e77d582bc15289e2b1b26323771daacab0941a5 /drivers
parentac24be6fe6593564be99a88e41cddc6c0fc1899f (diff)
brcmfmac: streamline header parse code of sdio glom read
Use brcmf_sdio_hdparser to handle header of super frame and sub frame in glomming frame read. Signed-off-by: Franky Lin <frankyl@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c174
1 files changed, 62 insertions, 112 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 3564686add9a..415f2be36375 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -614,6 +614,12 @@ static const uint max_roundup = 512;
614 614
615#define ALIGNMENT 4 615#define ALIGNMENT 4
616 616
617enum brcmf_sdio_frmtype {
618 BRCMF_SDIO_FT_NORMAL,
619 BRCMF_SDIO_FT_SUPER,
620 BRCMF_SDIO_FT_SUB,
621};
622
617static void pkt_align(struct sk_buff *p, int len, int align) 623static void pkt_align(struct sk_buff *p, int len, int align)
618{ 624{
619 uint datalign; 625 uint datalign;
@@ -1032,7 +1038,8 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
1032} 1038}
1033 1039
1034static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, 1040static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1035 struct brcmf_sdio_read *rd) 1041 struct brcmf_sdio_read *rd,
1042 enum brcmf_sdio_frmtype type)
1036{ 1043{
1037 u16 len, checksum; 1044 u16 len, checksum;
1038 u8 rx_seq, fc, tx_seq_max; 1045 u8 rx_seq, fc, tx_seq_max;
@@ -1059,6 +1066,15 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1059 brcmf_dbg(ERROR, "HW header length error\n"); 1066 brcmf_dbg(ERROR, "HW header length error\n");
1060 return false; 1067 return false;
1061 } 1068 }
1069 if (type == BRCMF_SDIO_FT_SUPER &&
1070 (roundup(len, bus->blocksize) != rd->len)) {
1071 brcmf_dbg(ERROR, "HW superframe header length error\n");
1072 return false;
1073 }
1074 if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
1075 brcmf_dbg(ERROR, "HW subframe header length error\n");
1076 return false;
1077 }
1062 rd->len = len; 1078 rd->len = len;
1063 1079
1064 /* 1080 /*
@@ -1071,9 +1087,16 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1071 * Byte 5: Maximum Sequence number allow for Tx 1087 * Byte 5: Maximum Sequence number allow for Tx
1072 * Byte 6~7: Reserved 1088 * Byte 6~7: Reserved
1073 */ 1089 */
1090 if (type == BRCMF_SDIO_FT_SUPER &&
1091 SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
1092 brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n");
1093 rd->len = 0;
1094 return false;
1095 }
1074 rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]); 1096 rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
1075 rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]); 1097 rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
1076 if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL) { 1098 if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL &&
1099 type != BRCMF_SDIO_FT_SUPER) {
1077 brcmf_dbg(ERROR, "HW header length too long\n"); 1100 brcmf_dbg(ERROR, "HW header length too long\n");
1078 bus->sdiodev->bus_if->dstats.rx_errors++; 1101 bus->sdiodev->bus_if->dstats.rx_errors++;
1079 bus->sdcnt.rx_toolong++; 1102 bus->sdcnt.rx_toolong++;
@@ -1081,6 +1104,17 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1081 rd->len = 0; 1104 rd->len = 0;
1082 return false; 1105 return false;
1083 } 1106 }
1107 if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
1108 brcmf_dbg(ERROR, "Wrong channel for superframe\n");
1109 rd->len = 0;
1110 return false;
1111 }
1112 if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
1113 rd->channel != SDPCM_EVENT_CHANNEL) {
1114 brcmf_dbg(ERROR, "Wrong channel for subframe\n");
1115 rd->len = 0;
1116 return false;
1117 }
1084 rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]); 1118 rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
1085 if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) { 1119 if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
1086 brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq); 1120 brcmf_dbg(ERROR, "seq %d: bad data offset\n", rx_seq);
@@ -1095,6 +1129,9 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
1095 bus->sdcnt.rx_badseq++; 1129 bus->sdcnt.rx_badseq++;
1096 rd->seq_num = rx_seq; 1130 rd->seq_num = rx_seq;
1097 } 1131 }
1132 /* no need to check the reset for subframe */
1133 if (type == BRCMF_SDIO_FT_SUB)
1134 return true;
1098 rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; 1135 rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
1099 if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) { 1136 if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
1100 /* only warm for NON glom packet */ 1137 /* only warm for NON glom packet */
@@ -1126,16 +1163,16 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
1126 u16 dlen, totlen; 1163 u16 dlen, totlen;
1127 u8 *dptr, num = 0; 1164 u8 *dptr, num = 0;
1128 1165
1129 u16 sublen, check; 1166 u16 sublen;
1130 struct sk_buff *pfirst, *pnext; 1167 struct sk_buff *pfirst, *pnext;
1131 1168
1132 int errcode; 1169 int errcode;
1133 u8 chan, seq, doff, sfdoff; 1170 u8 doff, sfdoff;
1134 u8 txmax;
1135 1171
1136 int ifidx = 0; 1172 int ifidx = 0;
1137 bool usechain = bus->use_rxchain; 1173 bool usechain = bus->use_rxchain;
1138 u16 next_len; 1174
1175 struct brcmf_sdio_read rd_new;
1139 1176
1140 /* If packets, issue read(s) and send up packet chain */ 1177 /* If packets, issue read(s) and send up packet chain */
1141 /* Return sequence numbers consumed? */ 1178 /* Return sequence numbers consumed? */
@@ -1279,68 +1316,15 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
1279 pfirst->data, min_t(int, pfirst->len, 48), 1316 pfirst->data, min_t(int, pfirst->len, 48),
1280 "SUPERFRAME:\n"); 1317 "SUPERFRAME:\n");
1281 1318
1282 /* Validate the superframe header */ 1319 rd_new.seq_num = rxseq;
1283 dptr = (u8 *) (pfirst->data); 1320 rd_new.len = dlen;
1284 sublen = get_unaligned_le16(dptr); 1321 errcode = -!brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
1285 check = get_unaligned_le16(dptr + sizeof(u16)); 1322 BRCMF_SDIO_FT_SUPER);
1286 1323 bus->cur_read.len = rd_new.len_nxtfrm << 4;
1287 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
1288 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
1289 next_len = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
1290 if ((next_len << 4) > MAX_RX_DATASZ) {
1291 brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
1292 next_len, seq);
1293 next_len = 0;
1294 }
1295 bus->cur_read.len = next_len << 4;
1296 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
1297 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
1298
1299 errcode = 0;
1300 if ((u16)~(sublen ^ check)) {
1301 brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
1302 sublen, check);
1303 errcode = -1;
1304 } else if (roundup(sublen, bus->blocksize) != dlen) {
1305 brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
1306 sublen, roundup(sublen, bus->blocksize),
1307 dlen);
1308 errcode = -1;
1309 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
1310 SDPCM_GLOM_CHANNEL) {
1311 brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
1312 SDPCM_PACKET_CHANNEL(
1313 &dptr[SDPCM_FRAMETAG_LEN]));
1314 errcode = -1;
1315 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
1316 brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
1317 errcode = -1;
1318 } else if ((doff < SDPCM_HDRLEN) ||
1319 (doff > (pfirst->len - SDPCM_HDRLEN))) {
1320 brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
1321 doff, sublen, pfirst->len, SDPCM_HDRLEN);
1322 errcode = -1;
1323 }
1324
1325 /* Check sequence number of superframe SW header */
1326 if (rxseq != seq) {
1327 brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
1328 seq, rxseq);
1329 bus->sdcnt.rx_badseq++;
1330 rxseq = seq;
1331 }
1332
1333 /* Check window for sanity */
1334 if ((u8) (txmax - bus->tx_seq) > 0x40) {
1335 brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
1336 txmax, bus->tx_seq);
1337 txmax = bus->tx_seq + 2;
1338 }
1339 bus->tx_max = txmax;
1340 1324
1341 /* Remove superframe header, remember offset */ 1325 /* Remove superframe header, remember offset */
1342 skb_pull(pfirst, doff); 1326 skb_pull(pfirst, rd_new.dat_offset);
1343 sfdoff = doff; 1327 sfdoff = rd_new.dat_offset;
1344 num = 0; 1328 num = 0;
1345 1329
1346 /* Validate all the subframe headers */ 1330 /* Validate all the subframe headers */
@@ -1349,34 +1333,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
1349 if (errcode) 1333 if (errcode)
1350 break; 1334 break;
1351 1335
1352 dptr = (u8 *) (pnext->data); 1336 rd_new.len = pnext->len;
1353 dlen = (u16) (pnext->len); 1337 rd_new.seq_num = rxseq++;
1354 sublen = get_unaligned_le16(dptr); 1338 errcode = -!brcmf_sdio_hdparser(bus, pnext->data,
1355 check = get_unaligned_le16(dptr + sizeof(u16)); 1339 &rd_new,
1356 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); 1340 BRCMF_SDIO_FT_SUB);
1357 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
1358 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), 1341 brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
1359 dptr, 32, "subframe:\n"); 1342 pnext->data, 32, "subframe:\n");
1360 1343
1361 if ((u16)~(sublen ^ check)) {
1362 brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
1363 num, sublen, check);
1364 errcode = -1;
1365 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
1366 brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
1367 num, sublen, dlen);
1368 errcode = -1;
1369 } else if ((chan != SDPCM_DATA_CHANNEL) &&
1370 (chan != SDPCM_EVENT_CHANNEL)) {
1371 brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
1372 num, chan);
1373 errcode = -1;
1374 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
1375 brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
1376 num, doff, sublen, SDPCM_HDRLEN);
1377 errcode = -1;
1378 }
1379 /* increase the subframe count */
1380 num++; 1344 num++;
1381 } 1345 }
1382 1346
@@ -1402,27 +1366,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
1402 skb_queue_walk_safe(&bus->glom, pfirst, pnext) { 1366 skb_queue_walk_safe(&bus->glom, pfirst, pnext) {
1403 dptr = (u8 *) (pfirst->data); 1367 dptr = (u8 *) (pfirst->data);
1404 sublen = get_unaligned_le16(dptr); 1368 sublen = get_unaligned_le16(dptr);
1405 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
1406 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
1407 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); 1369 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
1408 1370
1409 brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
1410 num, pfirst, pfirst->data,
1411 pfirst->len, sublen, chan, seq);
1412
1413 /* precondition: chan == SDPCM_DATA_CHANNEL ||
1414 chan == SDPCM_EVENT_CHANNEL */
1415
1416 if (rxseq != seq) {
1417 brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
1418 seq, rxseq);
1419 bus->sdcnt.rx_badseq++;
1420 rxseq = seq;
1421 }
1422 rxseq++;
1423
1424 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(), 1371 brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_DATA_ON(),
1425 dptr, dlen, "Rx Subframe Data:\n"); 1372 dptr, pfirst->len,
1373 "Rx Subframe Data:\n");
1426 1374
1427 __skb_trim(pfirst, sublen); 1375 __skb_trim(pfirst, sublen);
1428 skb_pull(pfirst, doff); 1376 skb_pull(pfirst, doff);
@@ -1642,7 +1590,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
1642 bus->rxhdr, SDPCM_HDRLEN, 1590 bus->rxhdr, SDPCM_HDRLEN,
1643 "RxHdr:\n"); 1591 "RxHdr:\n");
1644 1592
1645 if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd)) { 1593 if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
1594 BRCMF_SDIO_FT_NORMAL)) {
1646 if (!bus->rxpending) 1595 if (!bus->rxpending)
1647 break; 1596 break;
1648 else 1597 else
@@ -1701,7 +1650,8 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
1701 } else { 1650 } else {
1702 memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN); 1651 memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
1703 rd_new.seq_num = rd->seq_num; 1652 rd_new.seq_num = rd->seq_num;
1704 if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new)) { 1653 if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
1654 BRCMF_SDIO_FT_NORMAL)) {
1705 rd->len = 0; 1655 rd->len = 0;
1706 brcmu_pkt_buf_free_skb(pkt); 1656 brcmu_pkt_buf_free_skb(pkt);
1707 } 1657 }