.. | .. |
---|
| 1 | +// SPDX-License-Identifier: ISC |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2010 Broadcom Corporation |
---|
3 | | - * |
---|
4 | | - * Permission to use, copy, modify, and/or distribute this software for any |
---|
5 | | - * purpose with or without fee is hereby granted, provided that the above |
---|
6 | | - * copyright notice and this permission notice appear in all copies. |
---|
7 | | - * |
---|
8 | | - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
9 | | - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
10 | | - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
---|
11 | | - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
12 | | - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
---|
13 | | - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
---|
14 | | - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
15 | 4 | */ |
---|
16 | 5 | #include <linux/types.h> |
---|
17 | 6 | #include <linux/module.h> |
---|
.. | .. |
---|
322 | 311 | /* How long to defer borrowing in jiffies */ |
---|
323 | 312 | #define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10) |
---|
324 | 313 | |
---|
325 | | -/** |
---|
326 | | - * enum brcmf_fws_fifo - fifo indices used by dongle firmware. |
---|
327 | | - * |
---|
328 | | - * @BRCMF_FWS_FIFO_FIRST: first fifo, ie. background. |
---|
329 | | - * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic. |
---|
330 | | - * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic. |
---|
331 | | - * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic. |
---|
332 | | - * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic. |
---|
333 | | - * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only). |
---|
334 | | - * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only). |
---|
335 | | - * @BRCMF_FWS_FIFO_COUNT: number of fifos. |
---|
336 | | - */ |
---|
337 | | -enum brcmf_fws_fifo { |
---|
338 | | - BRCMF_FWS_FIFO_FIRST, |
---|
339 | | - BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST, |
---|
340 | | - BRCMF_FWS_FIFO_AC_BE, |
---|
341 | | - BRCMF_FWS_FIFO_AC_VI, |
---|
342 | | - BRCMF_FWS_FIFO_AC_VO, |
---|
343 | | - BRCMF_FWS_FIFO_BCMC, |
---|
344 | | - BRCMF_FWS_FIFO_ATIM, |
---|
345 | | - BRCMF_FWS_FIFO_COUNT |
---|
346 | | -}; |
---|
347 | 314 | |
---|
348 | 315 | /** |
---|
349 | 316 | * enum brcmf_fws_txstatus - txstatus flag values. |
---|
.. | .. |
---|
356 | 323 | * firmware suppress the packet as device is already in PS mode. |
---|
357 | 324 | * @BRCMF_FWS_TXSTATUS_FW_TOSSED: |
---|
358 | 325 | * firmware tossed the packet. |
---|
| 326 | + * @BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK: |
---|
| 327 | + * firmware tossed the packet after retries. |
---|
| 328 | + * @BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED: |
---|
| 329 | + * firmware wrongly reported suppressed previously, now fixing to acked. |
---|
359 | 330 | * @BRCMF_FWS_TXSTATUS_HOST_TOSSED: |
---|
360 | 331 | * host tossed the packet. |
---|
361 | 332 | */ |
---|
.. | .. |
---|
364 | 335 | BRCMF_FWS_TXSTATUS_CORE_SUPPRESS, |
---|
365 | 336 | BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS, |
---|
366 | 337 | BRCMF_FWS_TXSTATUS_FW_TOSSED, |
---|
| 338 | + BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK, |
---|
| 339 | + BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED, |
---|
367 | 340 | BRCMF_FWS_TXSTATUS_HOST_TOSSED |
---|
368 | 341 | }; |
---|
369 | 342 | |
---|
.. | .. |
---|
381 | 354 | /** |
---|
382 | 355 | * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface |
---|
383 | 356 | * |
---|
| 357 | + * @name: name of the descriptor. |
---|
384 | 358 | * @occupied: slot is in use. |
---|
385 | 359 | * @mac_handle: handle for mac entry determined by firmware. |
---|
386 | 360 | * @interface_id: interface index. |
---|
.. | .. |
---|
389 | 363 | * @generation: generation bit. |
---|
390 | 364 | * @ac_bitmap: ac queue bitmap. |
---|
391 | 365 | * @requested_credit: credits requested by firmware. |
---|
| 366 | + * @requested_packet: packet requested by firmware. |
---|
392 | 367 | * @ea: ethernet address. |
---|
393 | 368 | * @seq: per-node free-running sequence. |
---|
394 | 369 | * @psq: power-save queue. |
---|
395 | 370 | * @transit_count: packet in transit to firmware. |
---|
| 371 | + * @suppr_transit_count: suppressed packet in transit to firmware. |
---|
| 372 | + * @send_tim_signal: if set tim signal will be sent. |
---|
| 373 | + * @traffic_pending_bmp: traffic pending bitmap. |
---|
| 374 | + * @traffic_lastreported_bmp: traffic last reported bitmap. |
---|
396 | 375 | */ |
---|
397 | 376 | struct brcmf_fws_mac_descriptor { |
---|
398 | 377 | char name[16]; |
---|
.. | .. |
---|
415 | 394 | u8 traffic_lastreported_bmp; |
---|
416 | 395 | }; |
---|
417 | 396 | |
---|
418 | | -#define BRCMF_FWS_HANGER_MAXITEMS 1024 |
---|
| 397 | +#define BRCMF_FWS_HANGER_MAXITEMS 3072 |
---|
| 398 | +#define BRCMF_BORROW_RATIO 3 |
---|
419 | 399 | |
---|
420 | 400 | /** |
---|
421 | 401 | * enum brcmf_fws_hanger_item_state - state of hanger item. |
---|
.. | .. |
---|
511 | 491 | struct work_struct fws_dequeue_work; |
---|
512 | 492 | u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT]; |
---|
513 | 493 | int fifo_credit[BRCMF_FWS_FIFO_COUNT]; |
---|
514 | | - int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1]; |
---|
| 494 | + int init_fifo_credit[BRCMF_FWS_FIFO_COUNT]; |
---|
| 495 | + int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1] |
---|
| 496 | + [BRCMF_FWS_FIFO_AC_VO + 1]; |
---|
515 | 497 | int deq_node_pos[BRCMF_FWS_FIFO_COUNT]; |
---|
516 | 498 | u32 fifo_credit_map; |
---|
517 | 499 | u32 fifo_delay_map; |
---|
.. | .. |
---|
520 | 502 | bool creditmap_received; |
---|
521 | 503 | u8 mode; |
---|
522 | 504 | bool avoid_queueing; |
---|
523 | | -}; |
---|
524 | | - |
---|
525 | | -/* |
---|
526 | | - * brcmf_fws_prio2fifo - mapping from 802.1d priority to firmware fifo index. |
---|
527 | | - */ |
---|
528 | | -static const int brcmf_fws_prio2fifo[] = { |
---|
529 | | - BRCMF_FWS_FIFO_AC_BE, |
---|
530 | | - BRCMF_FWS_FIFO_AC_BK, |
---|
531 | | - BRCMF_FWS_FIFO_AC_BK, |
---|
532 | | - BRCMF_FWS_FIFO_AC_BE, |
---|
533 | | - BRCMF_FWS_FIFO_AC_VI, |
---|
534 | | - BRCMF_FWS_FIFO_AC_VI, |
---|
535 | | - BRCMF_FWS_FIFO_AC_VO, |
---|
536 | | - BRCMF_FWS_FIFO_AC_VO |
---|
537 | 505 | }; |
---|
538 | 506 | |
---|
539 | 507 | #define BRCMF_FWS_TLV_DEF(name, id, len) \ |
---|
.. | .. |
---|
922 | 890 | wlh += wlh[1] + 2; |
---|
923 | 891 | |
---|
924 | 892 | if (entry->send_tim_signal) { |
---|
925 | | - entry->send_tim_signal = 0; |
---|
| 893 | + entry->send_tim_signal = false; |
---|
926 | 894 | wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP; |
---|
927 | 895 | wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN; |
---|
928 | 896 | wlh[2] = entry->mac_handle; |
---|
.. | .. |
---|
1223 | 1191 | |
---|
1224 | 1192 | fws->fifo_credit_map |= 1 << fifo; |
---|
1225 | 1193 | |
---|
1226 | | - if ((fifo == BRCMF_FWS_FIFO_AC_BE) && |
---|
1227 | | - (fws->credits_borrowed[0])) { |
---|
| 1194 | + if (fifo > BRCMF_FWS_FIFO_AC_BK && |
---|
| 1195 | + fifo <= BRCMF_FWS_FIFO_AC_VO) { |
---|
1228 | 1196 | for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0; |
---|
1229 | 1197 | lender_ac--) { |
---|
1230 | | - borrowed = &fws->credits_borrowed[lender_ac]; |
---|
| 1198 | + borrowed = &fws->credits_borrowed[fifo][lender_ac]; |
---|
1231 | 1199 | if (*borrowed) { |
---|
1232 | 1200 | fws->fifo_credit_map |= (1 << lender_ac); |
---|
1233 | 1201 | fifo_credit = &fws->fifo_credit[lender_ac]; |
---|
.. | .. |
---|
1244 | 1212 | } |
---|
1245 | 1213 | } |
---|
1246 | 1214 | |
---|
1247 | | - fws->fifo_credit[fifo] += credits; |
---|
| 1215 | + if (credits) { |
---|
| 1216 | + fws->fifo_credit[fifo] += credits; |
---|
| 1217 | + } |
---|
| 1218 | + |
---|
| 1219 | + if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo]) |
---|
| 1220 | + fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo]; |
---|
| 1221 | + |
---|
1248 | 1222 | } |
---|
1249 | 1223 | |
---|
1250 | 1224 | static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws) |
---|
.. | .. |
---|
1259 | 1233 | enum brcmf_fws_skb_state state, int fifo, |
---|
1260 | 1234 | struct sk_buff *p) |
---|
1261 | 1235 | { |
---|
| 1236 | + struct brcmf_pub *drvr = fws->drvr; |
---|
1262 | 1237 | int prec = 2 * fifo; |
---|
1263 | 1238 | u32 *qfull_stat = &fws->stats.delayq_full_error; |
---|
1264 | 1239 | struct brcmf_fws_mac_descriptor *entry; |
---|
.. | .. |
---|
1271 | 1246 | |
---|
1272 | 1247 | entry = brcmf_skbcb(p)->mac; |
---|
1273 | 1248 | if (entry == NULL) { |
---|
1274 | | - brcmf_err("no mac descriptor found for skb %p\n", p); |
---|
| 1249 | + bphy_err(drvr, "no mac descriptor found for skb %p\n", p); |
---|
1275 | 1250 | return -ENOENT; |
---|
1276 | 1251 | } |
---|
1277 | 1252 | |
---|
.. | .. |
---|
1459 | 1434 | |
---|
1460 | 1435 | static int |
---|
1461 | 1436 | brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, |
---|
1462 | | - u32 genbit, u16 seq) |
---|
| 1437 | + u32 genbit, u16 seq, u8 compcnt) |
---|
1463 | 1438 | { |
---|
| 1439 | + struct brcmf_pub *drvr = fws->drvr; |
---|
1464 | 1440 | u32 fifo; |
---|
| 1441 | + u8 cnt = 0; |
---|
1465 | 1442 | int ret; |
---|
1466 | 1443 | bool remove_from_hanger = true; |
---|
1467 | 1444 | struct sk_buff *skb; |
---|
.. | .. |
---|
1472 | 1449 | brcmf_dbg(DATA, "flags %d\n", flags); |
---|
1473 | 1450 | |
---|
1474 | 1451 | if (flags == BRCMF_FWS_TXSTATUS_DISCARD) |
---|
1475 | | - fws->stats.txs_discard++; |
---|
| 1452 | + fws->stats.txs_discard += compcnt; |
---|
1476 | 1453 | else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) { |
---|
1477 | | - fws->stats.txs_supp_core++; |
---|
| 1454 | + fws->stats.txs_supp_core += compcnt; |
---|
1478 | 1455 | remove_from_hanger = false; |
---|
1479 | 1456 | } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) { |
---|
1480 | | - fws->stats.txs_supp_ps++; |
---|
| 1457 | + fws->stats.txs_supp_ps += compcnt; |
---|
1481 | 1458 | remove_from_hanger = false; |
---|
1482 | 1459 | } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED) |
---|
1483 | | - fws->stats.txs_tossed++; |
---|
| 1460 | + fws->stats.txs_tossed += compcnt; |
---|
| 1461 | + else if (flags == BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK) |
---|
| 1462 | + fws->stats.txs_discard += compcnt; |
---|
| 1463 | + else if (flags == BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED) |
---|
| 1464 | + fws->stats.txs_discard += compcnt; |
---|
1484 | 1465 | else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) |
---|
1485 | | - fws->stats.txs_host_tossed++; |
---|
| 1466 | + fws->stats.txs_host_tossed += compcnt; |
---|
1486 | 1467 | else |
---|
1487 | | - brcmf_err("unexpected txstatus\n"); |
---|
| 1468 | + bphy_err(drvr, "unexpected txstatus\n"); |
---|
1488 | 1469 | |
---|
1489 | | - ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, |
---|
1490 | | - remove_from_hanger); |
---|
1491 | | - if (ret != 0) { |
---|
1492 | | - brcmf_err("no packet in hanger slot: hslot=%d\n", hslot); |
---|
1493 | | - return ret; |
---|
| 1470 | + while (cnt < compcnt) { |
---|
| 1471 | + ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, |
---|
| 1472 | + remove_from_hanger); |
---|
| 1473 | + if (ret != 0) { |
---|
| 1474 | + bphy_err(drvr, "no packet in hanger slot: hslot=%d\n", |
---|
| 1475 | + hslot); |
---|
| 1476 | + goto cont; |
---|
| 1477 | + } |
---|
| 1478 | + |
---|
| 1479 | + skcb = brcmf_skbcb(skb); |
---|
| 1480 | + entry = skcb->mac; |
---|
| 1481 | + if (WARN_ON(!entry)) { |
---|
| 1482 | + brcmu_pkt_buf_free_skb(skb); |
---|
| 1483 | + goto cont; |
---|
| 1484 | + } |
---|
| 1485 | + entry->transit_count--; |
---|
| 1486 | + if (entry->suppressed && entry->suppr_transit_count) |
---|
| 1487 | + entry->suppr_transit_count--; |
---|
| 1488 | + |
---|
| 1489 | + brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, |
---|
| 1490 | + flags, skcb->htod, seq); |
---|
| 1491 | + |
---|
| 1492 | + /* pick up the implicit credit from this packet */ |
---|
| 1493 | + fifo = brcmf_skb_htod_tag_get_field(skb, FIFO); |
---|
| 1494 | + if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT || |
---|
| 1495 | + (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) || |
---|
| 1496 | + flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) { |
---|
| 1497 | + brcmf_fws_return_credits(fws, fifo, 1); |
---|
| 1498 | + brcmf_fws_schedule_deq(fws); |
---|
| 1499 | + } |
---|
| 1500 | + brcmf_fws_macdesc_return_req_credit(skb); |
---|
| 1501 | + |
---|
| 1502 | + ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp); |
---|
| 1503 | + if (ret) { |
---|
| 1504 | + brcmu_pkt_buf_free_skb(skb); |
---|
| 1505 | + goto cont; |
---|
| 1506 | + } |
---|
| 1507 | + if (!remove_from_hanger) |
---|
| 1508 | + ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, |
---|
| 1509 | + genbit, seq); |
---|
| 1510 | + if (remove_from_hanger || ret) |
---|
| 1511 | + brcmf_txfinalize(ifp, skb, true); |
---|
| 1512 | + |
---|
| 1513 | +cont: |
---|
| 1514 | + hslot = (hslot + 1) & (BRCMF_FWS_TXSTAT_HSLOT_MASK >> |
---|
| 1515 | + BRCMF_FWS_TXSTAT_HSLOT_SHIFT); |
---|
| 1516 | + if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) |
---|
| 1517 | + seq = (seq + 1) & BRCMF_SKB_HTOD_SEQ_NR_MASK; |
---|
| 1518 | + |
---|
| 1519 | + cnt++; |
---|
1494 | 1520 | } |
---|
1495 | | - |
---|
1496 | | - skcb = brcmf_skbcb(skb); |
---|
1497 | | - entry = skcb->mac; |
---|
1498 | | - if (WARN_ON(!entry)) { |
---|
1499 | | - brcmu_pkt_buf_free_skb(skb); |
---|
1500 | | - return -EINVAL; |
---|
1501 | | - } |
---|
1502 | | - entry->transit_count--; |
---|
1503 | | - if (entry->suppressed && entry->suppr_transit_count) |
---|
1504 | | - entry->suppr_transit_count--; |
---|
1505 | | - |
---|
1506 | | - brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags, |
---|
1507 | | - skcb->htod, seq); |
---|
1508 | | - |
---|
1509 | | - /* pick up the implicit credit from this packet */ |
---|
1510 | | - fifo = brcmf_skb_htod_tag_get_field(skb, FIFO); |
---|
1511 | | - if ((fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT) || |
---|
1512 | | - (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) || |
---|
1513 | | - (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)) { |
---|
1514 | | - brcmf_fws_return_credits(fws, fifo, 1); |
---|
1515 | | - brcmf_fws_schedule_deq(fws); |
---|
1516 | | - } |
---|
1517 | | - brcmf_fws_macdesc_return_req_credit(skb); |
---|
1518 | | - |
---|
1519 | | - ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp); |
---|
1520 | | - if (ret) { |
---|
1521 | | - brcmu_pkt_buf_free_skb(skb); |
---|
1522 | | - return -EINVAL; |
---|
1523 | | - } |
---|
1524 | | - if (!remove_from_hanger) |
---|
1525 | | - ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, |
---|
1526 | | - genbit, seq); |
---|
1527 | | - if (remove_from_hanger || ret) |
---|
1528 | | - brcmf_txfinalize(ifp, skb, true); |
---|
1529 | 1521 | |
---|
1530 | 1522 | return 0; |
---|
1531 | 1523 | } |
---|
.. | .. |
---|
1551 | 1543 | return BRCMF_FWS_RET_OK_SCHEDULE; |
---|
1552 | 1544 | } |
---|
1553 | 1545 | |
---|
1554 | | -static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) |
---|
| 1546 | +static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 type, |
---|
| 1547 | + u8 *data) |
---|
1555 | 1548 | { |
---|
1556 | 1549 | __le32 status_le; |
---|
1557 | 1550 | __le16 seq_le; |
---|
.. | .. |
---|
1560 | 1553 | u32 genbit; |
---|
1561 | 1554 | u8 flags; |
---|
1562 | 1555 | u16 seq; |
---|
| 1556 | + u8 compcnt; |
---|
| 1557 | + u8 compcnt_offset = BRCMF_FWS_TYPE_TXSTATUS_LEN; |
---|
1563 | 1558 | |
---|
1564 | | - fws->stats.txs_indicate++; |
---|
1565 | 1559 | memcpy(&status_le, data, sizeof(status_le)); |
---|
1566 | 1560 | status = le32_to_cpu(status_le); |
---|
1567 | 1561 | flags = brcmf_txstatus_get_field(status, FLAGS); |
---|
1568 | 1562 | hslot = brcmf_txstatus_get_field(status, HSLOT); |
---|
1569 | 1563 | genbit = brcmf_txstatus_get_field(status, GENERATION); |
---|
1570 | 1564 | if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) { |
---|
1571 | | - memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN], |
---|
| 1565 | + memcpy(&seq_le, &data[BRCMF_FWS_TYPE_TXSTATUS_LEN], |
---|
1572 | 1566 | sizeof(seq_le)); |
---|
1573 | 1567 | seq = le16_to_cpu(seq_le); |
---|
| 1568 | + compcnt_offset += BRCMF_FWS_TYPE_SEQ_LEN; |
---|
1574 | 1569 | } else { |
---|
1575 | 1570 | seq = 0; |
---|
1576 | 1571 | } |
---|
1577 | 1572 | |
---|
| 1573 | + if (type == BRCMF_FWS_TYPE_COMP_TXSTATUS) |
---|
| 1574 | + compcnt = data[compcnt_offset]; |
---|
| 1575 | + else |
---|
| 1576 | + compcnt = 1; |
---|
| 1577 | + fws->stats.txs_indicate += compcnt; |
---|
| 1578 | + |
---|
1578 | 1579 | brcmf_fws_lock(fws); |
---|
1579 | | - brcmf_fws_txs_process(fws, flags, hslot, genbit, seq); |
---|
| 1580 | + brcmf_fws_txs_process(fws, flags, hslot, genbit, seq, compcnt); |
---|
1580 | 1581 | brcmf_fws_unlock(fws); |
---|
1581 | 1582 | return BRCMF_FWS_RET_OK_NOSCHEDULE; |
---|
1582 | 1583 | } |
---|
.. | .. |
---|
1595 | 1596 | const struct brcmf_event_msg *e, |
---|
1596 | 1597 | void *data) |
---|
1597 | 1598 | { |
---|
1598 | | - struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); |
---|
| 1599 | + struct brcmf_pub *drvr = ifp->drvr; |
---|
| 1600 | + struct brcmf_fws_info *fws = drvr_to_fws(drvr); |
---|
1599 | 1601 | int i; |
---|
1600 | 1602 | u8 *credits = data; |
---|
1601 | 1603 | |
---|
1602 | 1604 | if (e->datalen < BRCMF_FWS_FIFO_COUNT) { |
---|
1603 | | - brcmf_err("event payload too small (%d)\n", e->datalen); |
---|
| 1605 | + bphy_err(drvr, "event payload too small (%d)\n", e->datalen); |
---|
1604 | 1606 | return -EINVAL; |
---|
1605 | 1607 | } |
---|
1606 | | - if (fws->creditmap_received) |
---|
1607 | | - return 0; |
---|
1608 | 1608 | |
---|
1609 | 1609 | fws->creditmap_received = true; |
---|
1610 | 1610 | |
---|
1611 | 1611 | brcmf_dbg(TRACE, "enter: credits %pM\n", credits); |
---|
1612 | 1612 | brcmf_fws_lock(fws); |
---|
1613 | 1613 | for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) { |
---|
1614 | | - if (*credits) |
---|
| 1614 | + fws->fifo_credit[i] += credits[i] - fws->init_fifo_credit[i]; |
---|
| 1615 | + fws->init_fifo_credit[i] = credits[i]; |
---|
| 1616 | + if (fws->fifo_credit[i] > 0) |
---|
1615 | 1617 | fws->fifo_credit_map |= 1 << i; |
---|
1616 | 1618 | else |
---|
1617 | 1619 | fws->fifo_credit_map &= ~(1 << i); |
---|
1618 | | - fws->fifo_credit[i] = *credits++; |
---|
| 1620 | + WARN_ONCE(fws->fifo_credit[i] < 0, |
---|
| 1621 | + "fifo_credit[%d] is negative(%d)\n", i, |
---|
| 1622 | + fws->fifo_credit[i]); |
---|
1619 | 1623 | } |
---|
1620 | 1624 | brcmf_fws_schedule_deq(fws); |
---|
1621 | 1625 | brcmf_fws_unlock(fws); |
---|
.. | .. |
---|
1660 | 1664 | rfi->pend_pkts -= skb_queue_len(skb_list); |
---|
1661 | 1665 | } |
---|
1662 | 1666 | |
---|
1663 | | -void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt) |
---|
| 1667 | +void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt, bool inirq) |
---|
1664 | 1668 | { |
---|
| 1669 | + struct brcmf_pub *drvr = ifp->drvr; |
---|
1665 | 1670 | u8 *reorder_data; |
---|
1666 | 1671 | u8 flow_id, max_idx, cur_idx, exp_idx, end_idx; |
---|
1667 | 1672 | struct brcmf_ampdu_rx_reorder *rfi; |
---|
.. | .. |
---|
1676 | 1681 | |
---|
1677 | 1682 | /* validate flags and flow id */ |
---|
1678 | 1683 | if (flags == 0xFF) { |
---|
1679 | | - brcmf_err("invalid flags...so ignore this packet\n"); |
---|
1680 | | - brcmf_netif_rx(ifp, pkt); |
---|
| 1684 | + bphy_err(drvr, "invalid flags...so ignore this packet\n"); |
---|
| 1685 | + brcmf_netif_rx(ifp, pkt, inirq); |
---|
1681 | 1686 | return; |
---|
1682 | 1687 | } |
---|
1683 | 1688 | |
---|
.. | .. |
---|
1689 | 1694 | if (rfi == NULL) { |
---|
1690 | 1695 | brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n", |
---|
1691 | 1696 | flow_id); |
---|
1692 | | - brcmf_netif_rx(ifp, pkt); |
---|
| 1697 | + brcmf_netif_rx(ifp, pkt, inirq); |
---|
1693 | 1698 | return; |
---|
1694 | 1699 | } |
---|
1695 | 1700 | |
---|
.. | .. |
---|
1713 | 1718 | flow_id, max_idx); |
---|
1714 | 1719 | rfi = kzalloc(buf_size, GFP_ATOMIC); |
---|
1715 | 1720 | if (rfi == NULL) { |
---|
1716 | | - brcmf_err("failed to alloc buffer\n"); |
---|
1717 | | - brcmf_netif_rx(ifp, pkt); |
---|
| 1721 | + bphy_err(drvr, "failed to alloc buffer\n"); |
---|
| 1722 | + brcmf_netif_rx(ifp, pkt, inirq); |
---|
1718 | 1723 | return; |
---|
1719 | 1724 | } |
---|
1720 | 1725 | |
---|
.. | .. |
---|
1828 | 1833 | netif_rx: |
---|
1829 | 1834 | skb_queue_walk_safe(&reorder_list, pkt, pnext) { |
---|
1830 | 1835 | __skb_unlink(pkt, &reorder_list); |
---|
1831 | | - brcmf_netif_rx(ifp, pkt); |
---|
| 1836 | + brcmf_netif_rx(ifp, pkt, inirq); |
---|
1832 | 1837 | } |
---|
1833 | 1838 | } |
---|
1834 | 1839 | |
---|
.. | .. |
---|
1848 | 1853 | ifp->ifidx, skb->len, siglen); |
---|
1849 | 1854 | |
---|
1850 | 1855 | WARN_ON(siglen > skb->len); |
---|
| 1856 | + |
---|
| 1857 | + if (siglen > skb->len) |
---|
| 1858 | + siglen = skb->len; |
---|
1851 | 1859 | |
---|
1852 | 1860 | if (!siglen) |
---|
1853 | 1861 | return; |
---|
.. | .. |
---|
1890 | 1898 | |
---|
1891 | 1899 | err = BRCMF_FWS_RET_OK_NOSCHEDULE; |
---|
1892 | 1900 | switch (type) { |
---|
1893 | | - case BRCMF_FWS_TYPE_COMP_TXSTATUS: |
---|
1894 | | - break; |
---|
1895 | 1901 | case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: |
---|
1896 | 1902 | rd = (struct brcmf_skb_reorder_data *)skb->cb; |
---|
1897 | 1903 | rd->reorder = data; |
---|
.. | .. |
---|
1914 | 1920 | err = brcmf_fws_request_indicate(fws, type, data); |
---|
1915 | 1921 | break; |
---|
1916 | 1922 | case BRCMF_FWS_TYPE_TXSTATUS: |
---|
1917 | | - brcmf_fws_txstatus_indicate(fws, data); |
---|
| 1923 | + case BRCMF_FWS_TYPE_COMP_TXSTATUS: |
---|
| 1924 | + brcmf_fws_txstatus_indicate(fws, type, data); |
---|
1918 | 1925 | break; |
---|
1919 | 1926 | case BRCMF_FWS_TYPE_FIFO_CREDITBACK: |
---|
1920 | 1927 | err = brcmf_fws_fifocreditback_indicate(fws, data); |
---|
.. | .. |
---|
1978 | 1985 | static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, |
---|
1979 | 1986 | struct sk_buff *skb, int fifo) |
---|
1980 | 1987 | { |
---|
| 1988 | + struct brcmf_pub *drvr = fws->drvr; |
---|
1981 | 1989 | struct brcmf_fws_mac_descriptor *entry; |
---|
1982 | 1990 | struct sk_buff *pktout; |
---|
1983 | 1991 | int qidx, hslot; |
---|
.. | .. |
---|
1991 | 1999 | |
---|
1992 | 2000 | pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb); |
---|
1993 | 2001 | if (pktout == NULL) { |
---|
1994 | | - brcmf_err("%s queue %d full\n", entry->name, qidx); |
---|
| 2002 | + bphy_err(drvr, "%s queue %d full\n", entry->name, qidx); |
---|
1995 | 2003 | rc = -ENOSPC; |
---|
1996 | 2004 | } |
---|
1997 | 2005 | } else { |
---|
1998 | | - brcmf_err("%s entry removed\n", entry->name); |
---|
| 2006 | + bphy_err(drvr, "%s entry removed\n", entry->name); |
---|
1999 | 2007 | rc = -ENOENT; |
---|
2000 | 2008 | } |
---|
2001 | 2009 | |
---|
.. | .. |
---|
2003 | 2011 | fws->stats.rollback_failed++; |
---|
2004 | 2012 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); |
---|
2005 | 2013 | brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, |
---|
2006 | | - hslot, 0, 0); |
---|
| 2014 | + hslot, 0, 0, 1); |
---|
2007 | 2015 | } else { |
---|
2008 | 2016 | fws->stats.rollback_success++; |
---|
2009 | 2017 | brcmf_fws_return_credits(fws, fifo, 1); |
---|
.. | .. |
---|
2011 | 2019 | } |
---|
2012 | 2020 | } |
---|
2013 | 2021 | |
---|
2014 | | -static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws) |
---|
| 2022 | +static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws, |
---|
| 2023 | + int highest_lender_ac, int borrower_ac, |
---|
| 2024 | + bool borrow_all) |
---|
2015 | 2025 | { |
---|
2016 | | - int lender_ac; |
---|
| 2026 | + int lender_ac, borrow_limit = 0; |
---|
2017 | 2027 | |
---|
2018 | | - if (time_after(fws->borrow_defer_timestamp, jiffies)) { |
---|
2019 | | - fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE); |
---|
2020 | | - return -ENAVAIL; |
---|
2021 | | - } |
---|
| 2028 | + for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { |
---|
2022 | 2029 | |
---|
2023 | | - for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) { |
---|
2024 | | - if (fws->fifo_credit[lender_ac]) { |
---|
2025 | | - fws->credits_borrowed[lender_ac]++; |
---|
| 2030 | + if (!borrow_all) |
---|
| 2031 | + borrow_limit = |
---|
| 2032 | + fws->init_fifo_credit[lender_ac] / BRCMF_BORROW_RATIO; |
---|
| 2033 | + else |
---|
| 2034 | + borrow_limit = 0; |
---|
| 2035 | + |
---|
| 2036 | + if (fws->fifo_credit[lender_ac] > borrow_limit) { |
---|
| 2037 | + fws->credits_borrowed[borrower_ac][lender_ac]++; |
---|
2026 | 2038 | fws->fifo_credit[lender_ac]--; |
---|
2027 | 2039 | if (fws->fifo_credit[lender_ac] == 0) |
---|
2028 | 2040 | fws->fifo_credit_map &= ~(1 << lender_ac); |
---|
2029 | | - fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE); |
---|
| 2041 | + fws->fifo_credit_map |= (1 << borrower_ac); |
---|
2030 | 2042 | brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac); |
---|
2031 | 2043 | return 0; |
---|
2032 | 2044 | } |
---|
2033 | 2045 | } |
---|
2034 | | - fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE); |
---|
| 2046 | + fws->fifo_credit_map &= ~(1 << borrower_ac); |
---|
2035 | 2047 | return -ENAVAIL; |
---|
2036 | 2048 | } |
---|
2037 | 2049 | |
---|
.. | .. |
---|
2100 | 2112 | |
---|
2101 | 2113 | int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) |
---|
2102 | 2114 | { |
---|
2103 | | - struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); |
---|
| 2115 | + struct brcmf_pub *drvr = ifp->drvr; |
---|
| 2116 | + struct brcmf_fws_info *fws = drvr_to_fws(drvr); |
---|
2104 | 2117 | struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); |
---|
2105 | 2118 | struct ethhdr *eh = (struct ethhdr *)(skb->data); |
---|
2106 | 2119 | int fifo = BRCMF_FWS_FIFO_BCMC; |
---|
.. | .. |
---|
2113 | 2126 | skcb->if_flags = 0; |
---|
2114 | 2127 | skcb->state = BRCMF_FWS_SKBSTATE_NEW; |
---|
2115 | 2128 | brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx); |
---|
| 2129 | + |
---|
| 2130 | + /* mapping from 802.1d priority to firmware fifo index */ |
---|
2116 | 2131 | if (!multicast) |
---|
2117 | | - fifo = brcmf_fws_prio2fifo[skb->priority]; |
---|
| 2132 | + fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority); |
---|
2118 | 2133 | |
---|
2119 | 2134 | brcmf_fws_lock(fws); |
---|
2120 | 2135 | if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) |
---|
.. | .. |
---|
2128 | 2143 | brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb); |
---|
2129 | 2144 | brcmf_fws_schedule_deq(fws); |
---|
2130 | 2145 | } else { |
---|
2131 | | - brcmf_err("drop skb: no hanger slot\n"); |
---|
2132 | | - brcmf_txfinalize(ifp, skb, false); |
---|
| 2146 | + bphy_err(drvr, "no hanger slot available\n"); |
---|
2133 | 2147 | rc = -ENOMEM; |
---|
2134 | 2148 | } |
---|
2135 | 2149 | brcmf_fws_unlock(fws); |
---|
.. | .. |
---|
2220 | 2234 | } |
---|
2221 | 2235 | continue; |
---|
2222 | 2236 | } |
---|
2223 | | - while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) && |
---|
2224 | | - (fifo == BRCMF_FWS_FIFO_BCMC))) { |
---|
| 2237 | + |
---|
| 2238 | + while ((fws->fifo_credit[fifo]) || |
---|
| 2239 | + ((!fws->bcmc_credit_check) && |
---|
| 2240 | + (fifo == BRCMF_FWS_FIFO_BCMC))) { |
---|
2225 | 2241 | skb = brcmf_fws_deq(fws, fifo); |
---|
2226 | 2242 | if (!skb) |
---|
2227 | 2243 | break; |
---|
.. | .. |
---|
2231 | 2247 | if (fws->bus_flow_blocked) |
---|
2232 | 2248 | break; |
---|
2233 | 2249 | } |
---|
2234 | | - if ((fifo == BRCMF_FWS_FIFO_AC_BE) && |
---|
2235 | | - (fws->fifo_credit[fifo] == 0) && |
---|
2236 | | - (!fws->bus_flow_blocked)) { |
---|
2237 | | - while (brcmf_fws_borrow_credit(fws) == 0) { |
---|
| 2250 | + |
---|
| 2251 | + if (fifo >= BRCMF_FWS_FIFO_AC_BE && |
---|
| 2252 | + fifo <= BRCMF_FWS_FIFO_AC_VO && |
---|
| 2253 | + fws->fifo_credit[fifo] == 0 && |
---|
| 2254 | + !fws->bus_flow_blocked) { |
---|
| 2255 | + while (brcmf_fws_borrow_credit(fws, |
---|
| 2256 | + fifo - 1, fifo, |
---|
| 2257 | + true) == 0) { |
---|
2238 | 2258 | skb = brcmf_fws_deq(fws, fifo); |
---|
2239 | 2259 | if (!skb) { |
---|
2240 | 2260 | brcmf_fws_return_credits(fws, fifo, 1); |
---|
.. | .. |
---|
2339 | 2359 | fws->drvr = drvr; |
---|
2340 | 2360 | fws->fcmode = drvr->settings->fcmode; |
---|
2341 | 2361 | |
---|
2342 | | - if ((drvr->bus_if->always_use_fws_queue == false) && |
---|
| 2362 | + if (!drvr->bus_if->always_use_fws_queue && |
---|
2343 | 2363 | (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) { |
---|
2344 | 2364 | fws->avoid_queueing = true; |
---|
2345 | 2365 | brcmf_dbg(INFO, "FWS queueing will be avoided\n"); |
---|
.. | .. |
---|
2348 | 2368 | |
---|
2349 | 2369 | fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); |
---|
2350 | 2370 | if (fws->fws_wq == NULL) { |
---|
2351 | | - brcmf_err("workqueue creation failed\n"); |
---|
| 2371 | + bphy_err(drvr, "workqueue creation failed\n"); |
---|
2352 | 2372 | rc = -EBADF; |
---|
2353 | 2373 | goto fail; |
---|
2354 | 2374 | } |
---|
.. | .. |
---|
2364 | 2384 | rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP, |
---|
2365 | 2385 | brcmf_fws_notify_credit_map); |
---|
2366 | 2386 | if (rc < 0) { |
---|
2367 | | - brcmf_err("register credit map handler failed\n"); |
---|
| 2387 | + bphy_err(drvr, "register credit map handler failed\n"); |
---|
2368 | 2388 | goto fail; |
---|
2369 | 2389 | } |
---|
2370 | 2390 | rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT, |
---|
2371 | 2391 | brcmf_fws_notify_bcmc_credit_support); |
---|
2372 | 2392 | if (rc < 0) { |
---|
2373 | | - brcmf_err("register bcmc credit handler failed\n"); |
---|
| 2393 | + bphy_err(drvr, "register bcmc credit handler failed\n"); |
---|
2374 | 2394 | brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP); |
---|
2375 | 2395 | goto fail; |
---|
2376 | 2396 | } |
---|
.. | .. |
---|
2382 | 2402 | fws->fw_signals = true; |
---|
2383 | 2403 | ifp = brcmf_get_ifp(drvr, 0); |
---|
2384 | 2404 | if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) { |
---|
2385 | | - brcmf_err("failed to set bdcv2 tlv signaling\n"); |
---|
| 2405 | + bphy_err(drvr, "failed to set bdcv2 tlv signaling\n"); |
---|
2386 | 2406 | fws->fcmode = BRCMF_FWS_FCMODE_NONE; |
---|
2387 | 2407 | fws->fw_signals = false; |
---|
2388 | 2408 | } |
---|
.. | .. |
---|
2414 | 2434 | return fws; |
---|
2415 | 2435 | |
---|
2416 | 2436 | fail: |
---|
2417 | | - brcmf_fws_detach_pre_delif(fws); |
---|
2418 | | - brcmf_fws_detach_post_delif(fws); |
---|
| 2437 | + brcmf_fws_detach(fws); |
---|
2419 | 2438 | return ERR_PTR(rc); |
---|
2420 | 2439 | } |
---|
2421 | 2440 | |
---|
2422 | | -void brcmf_fws_detach_pre_delif(struct brcmf_fws_info *fws) |
---|
| 2441 | +void brcmf_fws_detach(struct brcmf_fws_info *fws) |
---|
2423 | 2442 | { |
---|
2424 | 2443 | if (!fws) |
---|
2425 | 2444 | return; |
---|
2426 | | - if (fws->fws_wq) { |
---|
2427 | | - destroy_workqueue(fws->fws_wq); |
---|
2428 | | - fws->fws_wq = NULL; |
---|
2429 | | - } |
---|
2430 | | -} |
---|
2431 | 2445 | |
---|
2432 | | -void brcmf_fws_detach_post_delif(struct brcmf_fws_info *fws) |
---|
2433 | | -{ |
---|
2434 | | - if (!fws) |
---|
2435 | | - return; |
---|
| 2446 | + if (fws->fws_wq) |
---|
| 2447 | + destroy_workqueue(fws->fws_wq); |
---|
2436 | 2448 | |
---|
2437 | 2449 | /* cleanup */ |
---|
2438 | 2450 | brcmf_fws_lock(fws); |
---|
.. | .. |
---|
2473 | 2485 | } |
---|
2474 | 2486 | brcmf_fws_lock(fws); |
---|
2475 | 2487 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); |
---|
2476 | | - brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0); |
---|
| 2488 | + brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0, |
---|
| 2489 | + 1); |
---|
2477 | 2490 | brcmf_fws_unlock(fws); |
---|
2478 | 2491 | } |
---|
2479 | 2492 | |
---|