diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 228 |
1 files changed, 123 insertions, 105 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 29b1f24c2d0f..82f9140f3d35 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | |||
@@ -422,9 +422,12 @@ struct brcmf_fws_macdesc_table { | |||
422 | 422 | ||
423 | struct brcmf_fws_info { | 423 | struct brcmf_fws_info { |
424 | struct brcmf_pub *drvr; | 424 | struct brcmf_pub *drvr; |
425 | spinlock_t spinlock; | ||
426 | ulong flags; | ||
425 | struct brcmf_fws_stats stats; | 427 | struct brcmf_fws_stats stats; |
426 | struct brcmf_fws_hanger hanger; | 428 | struct brcmf_fws_hanger hanger; |
427 | enum brcmf_fws_fcmode fcmode; | 429 | enum brcmf_fws_fcmode fcmode; |
430 | bool fw_signals; | ||
428 | bool bcmc_credit_check; | 431 | bool bcmc_credit_check; |
429 | struct brcmf_fws_macdesc_table desc; | 432 | struct brcmf_fws_macdesc_table desc; |
430 | struct workqueue_struct *fws_wq; | 433 | struct workqueue_struct *fws_wq; |
@@ -483,6 +486,18 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws, | |||
483 | } | 486 | } |
484 | #undef BRCMF_FWS_TLV_DEF | 487 | #undef BRCMF_FWS_TLV_DEF |
485 | 488 | ||
489 | static void brcmf_fws_lock(struct brcmf_fws_info *fws) | ||
490 | __acquires(&fws->spinlock) | ||
491 | { | ||
492 | spin_lock_irqsave(&fws->spinlock, fws->flags); | ||
493 | } | ||
494 | |||
495 | static void brcmf_fws_unlock(struct brcmf_fws_info *fws) | ||
496 | __releases(&fws->spinlock) | ||
497 | { | ||
498 | spin_unlock_irqrestore(&fws->spinlock, fws->flags); | ||
499 | } | ||
500 | |||
486 | static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg) | 501 | static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg) |
487 | { | 502 | { |
488 | u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX); | 503 | u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX); |
@@ -869,8 +884,11 @@ static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws, | |||
869 | skcb->state = BRCMF_FWS_SKBSTATE_TIM; | 884 | skcb->state = BRCMF_FWS_SKBSTATE_TIM; |
870 | bus = fws->drvr->bus_if; | 885 | bus = fws->drvr->bus_if; |
871 | err = brcmf_fws_hdrpush(fws, skb); | 886 | err = brcmf_fws_hdrpush(fws, skb); |
872 | if (err == 0) | 887 | if (err == 0) { |
888 | brcmf_fws_unlock(fws); | ||
873 | err = brcmf_bus_txdata(bus, skb); | 889 | err = brcmf_bus_txdata(bus, skb); |
890 | brcmf_fws_lock(fws); | ||
891 | } | ||
874 | if (err) | 892 | if (err) |
875 | brcmu_pkt_buf_free_skb(skb); | 893 | brcmu_pkt_buf_free_skb(skb); |
876 | return true; | 894 | return true; |
@@ -905,26 +923,10 @@ static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) | |||
905 | return 0; | 923 | return 0; |
906 | } | 924 | } |
907 | 925 | ||
908 | /* using macro so sparse checking does not complain | ||
909 | * about locking imbalance. | ||
910 | */ | ||
911 | #define brcmf_fws_lock(drvr, flags) \ | ||
912 | do { \ | ||
913 | flags = 0; \ | ||
914 | spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \ | ||
915 | } while (0) | ||
916 | |||
917 | /* using macro so sparse checking does not complain | ||
918 | * about locking imbalance. | ||
919 | */ | ||
920 | #define brcmf_fws_unlock(drvr, flags) \ | ||
921 | spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags)) | ||
922 | |||
923 | static | 926 | static |
924 | int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | 927 | int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) |
925 | { | 928 | { |
926 | struct brcmf_fws_mac_descriptor *entry, *existing; | 929 | struct brcmf_fws_mac_descriptor *entry, *existing; |
927 | ulong flags; | ||
928 | u8 mac_handle; | 930 | u8 mac_handle; |
929 | u8 ifidx; | 931 | u8 ifidx; |
930 | u8 *addr; | 932 | u8 *addr; |
@@ -938,10 +940,10 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
938 | if (entry->occupied) { | 940 | if (entry->occupied) { |
939 | brcmf_dbg(TRACE, "deleting %s mac %pM\n", | 941 | brcmf_dbg(TRACE, "deleting %s mac %pM\n", |
940 | entry->name, addr); | 942 | entry->name, addr); |
941 | brcmf_fws_lock(fws->drvr, flags); | 943 | brcmf_fws_lock(fws); |
942 | brcmf_fws_macdesc_cleanup(fws, entry, -1); | 944 | brcmf_fws_macdesc_cleanup(fws, entry, -1); |
943 | brcmf_fws_macdesc_deinit(entry); | 945 | brcmf_fws_macdesc_deinit(entry); |
944 | brcmf_fws_unlock(fws->drvr, flags); | 946 | brcmf_fws_unlock(fws); |
945 | } else | 947 | } else |
946 | fws->stats.mac_update_failed++; | 948 | fws->stats.mac_update_failed++; |
947 | return 0; | 949 | return 0; |
@@ -950,13 +952,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
950 | existing = brcmf_fws_macdesc_lookup(fws, addr); | 952 | existing = brcmf_fws_macdesc_lookup(fws, addr); |
951 | if (IS_ERR(existing)) { | 953 | if (IS_ERR(existing)) { |
952 | if (!entry->occupied) { | 954 | if (!entry->occupied) { |
953 | brcmf_fws_lock(fws->drvr, flags); | 955 | brcmf_fws_lock(fws); |
954 | entry->mac_handle = mac_handle; | 956 | entry->mac_handle = mac_handle; |
955 | brcmf_fws_macdesc_init(entry, addr, ifidx); | 957 | brcmf_fws_macdesc_init(entry, addr, ifidx); |
956 | brcmf_fws_macdesc_set_name(fws, entry); | 958 | brcmf_fws_macdesc_set_name(fws, entry); |
957 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, | 959 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, |
958 | BRCMF_FWS_PSQ_LEN); | 960 | BRCMF_FWS_PSQ_LEN); |
959 | brcmf_fws_unlock(fws->drvr, flags); | 961 | brcmf_fws_unlock(fws); |
960 | brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr); | 962 | brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr); |
961 | } else { | 963 | } else { |
962 | fws->stats.mac_update_failed++; | 964 | fws->stats.mac_update_failed++; |
@@ -964,13 +966,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
964 | } else { | 966 | } else { |
965 | if (entry != existing) { | 967 | if (entry != existing) { |
966 | brcmf_dbg(TRACE, "copy mac %s\n", existing->name); | 968 | brcmf_dbg(TRACE, "copy mac %s\n", existing->name); |
967 | brcmf_fws_lock(fws->drvr, flags); | 969 | brcmf_fws_lock(fws); |
968 | memcpy(entry, existing, | 970 | memcpy(entry, existing, |
969 | offsetof(struct brcmf_fws_mac_descriptor, psq)); | 971 | offsetof(struct brcmf_fws_mac_descriptor, psq)); |
970 | entry->mac_handle = mac_handle; | 972 | entry->mac_handle = mac_handle; |
971 | brcmf_fws_macdesc_deinit(existing); | 973 | brcmf_fws_macdesc_deinit(existing); |
972 | brcmf_fws_macdesc_set_name(fws, entry); | 974 | brcmf_fws_macdesc_set_name(fws, entry); |
973 | brcmf_fws_unlock(fws->drvr, flags); | 975 | brcmf_fws_unlock(fws); |
974 | brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name, | 976 | brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name, |
975 | addr); | 977 | addr); |
976 | } else { | 978 | } else { |
@@ -986,7 +988,6 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, | |||
986 | u8 type, u8 *data) | 988 | u8 type, u8 *data) |
987 | { | 989 | { |
988 | struct brcmf_fws_mac_descriptor *entry; | 990 | struct brcmf_fws_mac_descriptor *entry; |
989 | ulong flags; | ||
990 | u8 mac_handle; | 991 | u8 mac_handle; |
991 | int ret; | 992 | int ret; |
992 | 993 | ||
@@ -996,7 +997,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, | |||
996 | fws->stats.mac_ps_update_failed++; | 997 | fws->stats.mac_ps_update_failed++; |
997 | return -ESRCH; | 998 | return -ESRCH; |
998 | } | 999 | } |
999 | brcmf_fws_lock(fws->drvr, flags); | 1000 | brcmf_fws_lock(fws); |
1000 | /* a state update should wipe old credits */ | 1001 | /* a state update should wipe old credits */ |
1001 | entry->requested_credit = 0; | 1002 | entry->requested_credit = 0; |
1002 | entry->requested_packet = 0; | 1003 | entry->requested_packet = 0; |
@@ -1011,7 +1012,7 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, | |||
1011 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true); | 1012 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true); |
1012 | ret = BRCMF_FWS_RET_OK_NOSCHEDULE; | 1013 | ret = BRCMF_FWS_RET_OK_NOSCHEDULE; |
1013 | } | 1014 | } |
1014 | brcmf_fws_unlock(fws->drvr, flags); | 1015 | brcmf_fws_unlock(fws); |
1015 | return ret; | 1016 | return ret; |
1016 | } | 1017 | } |
1017 | 1018 | ||
@@ -1019,7 +1020,6 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, | |||
1019 | u8 type, u8 *data) | 1020 | u8 type, u8 *data) |
1020 | { | 1021 | { |
1021 | struct brcmf_fws_mac_descriptor *entry; | 1022 | struct brcmf_fws_mac_descriptor *entry; |
1022 | ulong flags; | ||
1023 | u8 ifidx; | 1023 | u8 ifidx; |
1024 | int ret; | 1024 | int ret; |
1025 | 1025 | ||
@@ -1038,7 +1038,7 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, | |||
1038 | 1038 | ||
1039 | brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type, | 1039 | brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type, |
1040 | entry->name); | 1040 | entry->name); |
1041 | brcmf_fws_lock(fws->drvr, flags); | 1041 | brcmf_fws_lock(fws); |
1042 | switch (type) { | 1042 | switch (type) { |
1043 | case BRCMF_FWS_TYPE_INTERFACE_OPEN: | 1043 | case BRCMF_FWS_TYPE_INTERFACE_OPEN: |
1044 | entry->state = BRCMF_FWS_STATE_OPEN; | 1044 | entry->state = BRCMF_FWS_STATE_OPEN; |
@@ -1050,10 +1050,10 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, | |||
1050 | break; | 1050 | break; |
1051 | default: | 1051 | default: |
1052 | ret = -EINVAL; | 1052 | ret = -EINVAL; |
1053 | brcmf_fws_unlock(fws->drvr, flags); | 1053 | brcmf_fws_unlock(fws); |
1054 | goto fail; | 1054 | goto fail; |
1055 | } | 1055 | } |
1056 | brcmf_fws_unlock(fws->drvr, flags); | 1056 | brcmf_fws_unlock(fws); |
1057 | return ret; | 1057 | return ret; |
1058 | 1058 | ||
1059 | fail: | 1059 | fail: |
@@ -1065,7 +1065,6 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, | |||
1065 | u8 *data) | 1065 | u8 *data) |
1066 | { | 1066 | { |
1067 | struct brcmf_fws_mac_descriptor *entry; | 1067 | struct brcmf_fws_mac_descriptor *entry; |
1068 | ulong flags; | ||
1069 | 1068 | ||
1070 | entry = &fws->desc.nodes[data[1] & 0x1F]; | 1069 | entry = &fws->desc.nodes[data[1] & 0x1F]; |
1071 | if (!entry->occupied) { | 1070 | if (!entry->occupied) { |
@@ -1079,14 +1078,14 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, | |||
1079 | brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n", | 1078 | brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n", |
1080 | brcmf_fws_get_tlv_name(type), type, entry->name, | 1079 | brcmf_fws_get_tlv_name(type), type, entry->name, |
1081 | data[0], data[2]); | 1080 | data[0], data[2]); |
1082 | brcmf_fws_lock(fws->drvr, flags); | 1081 | brcmf_fws_lock(fws); |
1083 | if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT) | 1082 | if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT) |
1084 | entry->requested_credit = data[0]; | 1083 | entry->requested_credit = data[0]; |
1085 | else | 1084 | else |
1086 | entry->requested_packet = data[0]; | 1085 | entry->requested_packet = data[0]; |
1087 | 1086 | ||
1088 | entry->ac_bitmap = data[2]; | 1087 | entry->ac_bitmap = data[2]; |
1089 | brcmf_fws_unlock(fws->drvr, flags); | 1088 | brcmf_fws_unlock(fws); |
1090 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1089 | return BRCMF_FWS_RET_OK_SCHEDULE; |
1091 | } | 1090 | } |
1092 | 1091 | ||
@@ -1160,7 +1159,8 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws, | |||
1160 | static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws) | 1159 | static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws) |
1161 | { | 1160 | { |
1162 | /* only schedule dequeue when there are credits for delayed traffic */ | 1161 | /* only schedule dequeue when there are credits for delayed traffic */ |
1163 | if (fws->fifo_credit_map & fws->fifo_delay_map) | 1162 | if ((fws->fifo_credit_map & fws->fifo_delay_map) || |
1163 | (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map)) | ||
1164 | queue_work(fws->fws_wq, &fws->fws_dequeue_work); | 1164 | queue_work(fws->fws_wq, &fws->fws_dequeue_work); |
1165 | } | 1165 | } |
1166 | 1166 | ||
@@ -1383,7 +1383,6 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, | |||
1383 | static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, | 1383 | static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, |
1384 | u8 *data) | 1384 | u8 *data) |
1385 | { | 1385 | { |
1386 | ulong flags; | ||
1387 | int i; | 1386 | int i; |
1388 | 1387 | ||
1389 | if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) { | 1388 | if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) { |
@@ -1392,19 +1391,18 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, | |||
1392 | } | 1391 | } |
1393 | 1392 | ||
1394 | brcmf_dbg(DATA, "enter: data %pM\n", data); | 1393 | brcmf_dbg(DATA, "enter: data %pM\n", data); |
1395 | brcmf_fws_lock(fws->drvr, flags); | 1394 | brcmf_fws_lock(fws); |
1396 | for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++) | 1395 | for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++) |
1397 | brcmf_fws_return_credits(fws, i, data[i]); | 1396 | brcmf_fws_return_credits(fws, i, data[i]); |
1398 | 1397 | ||
1399 | brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map, | 1398 | brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map, |
1400 | fws->fifo_delay_map); | 1399 | fws->fifo_delay_map); |
1401 | brcmf_fws_unlock(fws->drvr, flags); | 1400 | brcmf_fws_unlock(fws); |
1402 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1401 | return BRCMF_FWS_RET_OK_SCHEDULE; |
1403 | } | 1402 | } |
1404 | 1403 | ||
1405 | static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | 1404 | static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) |
1406 | { | 1405 | { |
1407 | ulong lflags; | ||
1408 | __le32 status_le; | 1406 | __le32 status_le; |
1409 | u32 status; | 1407 | u32 status; |
1410 | u32 hslot; | 1408 | u32 hslot; |
@@ -1418,9 +1416,9 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | |||
1418 | hslot = brcmf_txstatus_get_field(status, HSLOT); | 1416 | hslot = brcmf_txstatus_get_field(status, HSLOT); |
1419 | genbit = brcmf_txstatus_get_field(status, GENERATION); | 1417 | genbit = brcmf_txstatus_get_field(status, GENERATION); |
1420 | 1418 | ||
1421 | brcmf_fws_lock(fws->drvr, lflags); | 1419 | brcmf_fws_lock(fws); |
1422 | brcmf_fws_txs_process(fws, flags, hslot, genbit); | 1420 | brcmf_fws_txs_process(fws, flags, hslot, genbit); |
1423 | brcmf_fws_unlock(fws->drvr, lflags); | 1421 | brcmf_fws_unlock(fws); |
1424 | return BRCMF_FWS_RET_OK_NOSCHEDULE; | 1422 | return BRCMF_FWS_RET_OK_NOSCHEDULE; |
1425 | } | 1423 | } |
1426 | 1424 | ||
@@ -1440,7 +1438,6 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, | |||
1440 | { | 1438 | { |
1441 | struct brcmf_fws_info *fws = ifp->drvr->fws; | 1439 | struct brcmf_fws_info *fws = ifp->drvr->fws; |
1442 | int i; | 1440 | int i; |
1443 | ulong flags; | ||
1444 | u8 *credits = data; | 1441 | u8 *credits = data; |
1445 | 1442 | ||
1446 | if (e->datalen < BRCMF_FWS_FIFO_COUNT) { | 1443 | if (e->datalen < BRCMF_FWS_FIFO_COUNT) { |
@@ -1453,7 +1450,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, | |||
1453 | fws->creditmap_received = true; | 1450 | fws->creditmap_received = true; |
1454 | 1451 | ||
1455 | brcmf_dbg(TRACE, "enter: credits %pM\n", credits); | 1452 | brcmf_dbg(TRACE, "enter: credits %pM\n", credits); |
1456 | brcmf_fws_lock(ifp->drvr, flags); | 1453 | brcmf_fws_lock(fws); |
1457 | for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) { | 1454 | for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) { |
1458 | if (*credits) | 1455 | if (*credits) |
1459 | fws->fifo_credit_map |= 1 << i; | 1456 | fws->fifo_credit_map |= 1 << i; |
@@ -1462,7 +1459,7 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, | |||
1462 | fws->fifo_credit[i] = *credits++; | 1459 | fws->fifo_credit[i] = *credits++; |
1463 | } | 1460 | } |
1464 | brcmf_fws_schedule_deq(fws); | 1461 | brcmf_fws_schedule_deq(fws); |
1465 | brcmf_fws_unlock(ifp->drvr, flags); | 1462 | brcmf_fws_unlock(fws); |
1466 | return 0; | 1463 | return 0; |
1467 | } | 1464 | } |
1468 | 1465 | ||
@@ -1471,18 +1468,18 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp, | |||
1471 | void *data) | 1468 | void *data) |
1472 | { | 1469 | { |
1473 | struct brcmf_fws_info *fws = ifp->drvr->fws; | 1470 | struct brcmf_fws_info *fws = ifp->drvr->fws; |
1474 | ulong flags; | ||
1475 | 1471 | ||
1476 | brcmf_fws_lock(ifp->drvr, flags); | 1472 | brcmf_fws_lock(fws); |
1477 | if (fws) | 1473 | if (fws) |
1478 | fws->bcmc_credit_check = true; | 1474 | fws->bcmc_credit_check = true; |
1479 | brcmf_fws_unlock(ifp->drvr, flags); | 1475 | brcmf_fws_unlock(fws); |
1480 | return 0; | 1476 | return 0; |
1481 | } | 1477 | } |
1482 | 1478 | ||
1483 | int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | 1479 | int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, |
1484 | struct sk_buff *skb) | 1480 | struct sk_buff *skb) |
1485 | { | 1481 | { |
1482 | struct brcmf_skb_reorder_data *rd; | ||
1486 | struct brcmf_fws_info *fws = drvr->fws; | 1483 | struct brcmf_fws_info *fws = drvr->fws; |
1487 | u8 *signal_data; | 1484 | u8 *signal_data; |
1488 | s16 data_len; | 1485 | s16 data_len; |
@@ -1497,8 +1494,10 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
1497 | 1494 | ||
1498 | WARN_ON(signal_len > skb->len); | 1495 | WARN_ON(signal_len > skb->len); |
1499 | 1496 | ||
1497 | if (!signal_len) | ||
1498 | return 0; | ||
1500 | /* if flow control disabled, skip to packet data and leave */ | 1499 | /* if flow control disabled, skip to packet data and leave */ |
1501 | if (!signal_len || !drvr->fw_signals) { | 1500 | if (!fws->fw_signals) { |
1502 | skb_pull(skb, signal_len); | 1501 | skb_pull(skb, signal_len); |
1503 | return 0; | 1502 | return 0; |
1504 | } | 1503 | } |
@@ -1536,9 +1535,12 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
1536 | 1535 | ||
1537 | err = BRCMF_FWS_RET_OK_NOSCHEDULE; | 1536 | err = BRCMF_FWS_RET_OK_NOSCHEDULE; |
1538 | switch (type) { | 1537 | switch (type) { |
1539 | case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: | ||
1540 | case BRCMF_FWS_TYPE_COMP_TXSTATUS: | 1538 | case BRCMF_FWS_TYPE_COMP_TXSTATUS: |
1541 | break; | 1539 | break; |
1540 | case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: | ||
1541 | rd = (struct brcmf_skb_reorder_data *)skb->cb; | ||
1542 | rd->reorder = data; | ||
1543 | break; | ||
1542 | case BRCMF_FWS_TYPE_MACDESC_ADD: | 1544 | case BRCMF_FWS_TYPE_MACDESC_ADD: |
1543 | case BRCMF_FWS_TYPE_MACDESC_DEL: | 1545 | case BRCMF_FWS_TYPE_MACDESC_DEL: |
1544 | brcmf_fws_macdesc_indicate(fws, type, data); | 1546 | brcmf_fws_macdesc_indicate(fws, type, data); |
@@ -1694,17 +1696,22 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo, | |||
1694 | return PTR_ERR(entry); | 1696 | return PTR_ERR(entry); |
1695 | 1697 | ||
1696 | brcmf_fws_precommit_skb(fws, fifo, skb); | 1698 | brcmf_fws_precommit_skb(fws, fifo, skb); |
1699 | entry->transit_count++; | ||
1700 | if (entry->suppressed) | ||
1701 | entry->suppr_transit_count++; | ||
1702 | brcmf_fws_unlock(fws); | ||
1697 | rc = brcmf_bus_txdata(bus, skb); | 1703 | rc = brcmf_bus_txdata(bus, skb); |
1704 | brcmf_fws_lock(fws); | ||
1698 | brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name, | 1705 | brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name, |
1699 | skcb->if_flags, skcb->htod, rc); | 1706 | skcb->if_flags, skcb->htod, rc); |
1700 | if (rc < 0) { | 1707 | if (rc < 0) { |
1708 | entry->transit_count--; | ||
1709 | if (entry->suppressed) | ||
1710 | entry->suppr_transit_count--; | ||
1701 | brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); | 1711 | brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb); |
1702 | goto rollback; | 1712 | goto rollback; |
1703 | } | 1713 | } |
1704 | 1714 | ||
1705 | entry->transit_count++; | ||
1706 | if (entry->suppressed) | ||
1707 | entry->suppr_transit_count++; | ||
1708 | fws->stats.pkt2bus++; | 1715 | fws->stats.pkt2bus++; |
1709 | fws->stats.send_pkts[fifo]++; | 1716 | fws->stats.send_pkts[fifo]++; |
1710 | if (brcmf_skb_if_flags_get_field(skb, REQUESTED)) | 1717 | if (brcmf_skb_if_flags_get_field(skb, REQUESTED)) |
@@ -1741,11 +1748,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1741 | struct brcmf_fws_info *fws = drvr->fws; | 1748 | struct brcmf_fws_info *fws = drvr->fws; |
1742 | struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); | 1749 | struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb); |
1743 | struct ethhdr *eh = (struct ethhdr *)(skb->data); | 1750 | struct ethhdr *eh = (struct ethhdr *)(skb->data); |
1744 | ulong flags; | ||
1745 | int fifo = BRCMF_FWS_FIFO_BCMC; | 1751 | int fifo = BRCMF_FWS_FIFO_BCMC; |
1746 | bool multicast = is_multicast_ether_addr(eh->h_dest); | 1752 | bool multicast = is_multicast_ether_addr(eh->h_dest); |
1747 | bool pae = eh->h_proto == htons(ETH_P_PAE); | 1753 | bool pae = eh->h_proto == htons(ETH_P_PAE); |
1748 | 1754 | ||
1755 | brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); | ||
1749 | /* determine the priority */ | 1756 | /* determine the priority */ |
1750 | if (!skb->priority) | 1757 | if (!skb->priority) |
1751 | skb->priority = cfg80211_classify8021d(skb); | 1758 | skb->priority = cfg80211_classify8021d(skb); |
@@ -1754,14 +1761,6 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1754 | if (pae) | 1761 | if (pae) |
1755 | atomic_inc(&ifp->pend_8021x_cnt); | 1762 | atomic_inc(&ifp->pend_8021x_cnt); |
1756 | 1763 | ||
1757 | if (!brcmf_fws_fc_active(fws)) { | ||
1758 | /* If the protocol uses a data header, apply it */ | ||
1759 | brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb); | ||
1760 | |||
1761 | /* Use bus module to send data frame */ | ||
1762 | return brcmf_bus_txdata(drvr->bus_if, skb); | ||
1763 | } | ||
1764 | |||
1765 | /* set control buffer information */ | 1764 | /* set control buffer information */ |
1766 | skcb->if_flags = 0; | 1765 | skcb->if_flags = 0; |
1767 | skcb->state = BRCMF_FWS_SKBSTATE_NEW; | 1766 | skcb->state = BRCMF_FWS_SKBSTATE_NEW; |
@@ -1769,7 +1768,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1769 | if (!multicast) | 1768 | if (!multicast) |
1770 | fifo = brcmf_fws_prio2fifo[skb->priority]; | 1769 | fifo = brcmf_fws_prio2fifo[skb->priority]; |
1771 | 1770 | ||
1772 | brcmf_fws_lock(drvr, flags); | 1771 | brcmf_fws_lock(fws); |
1773 | if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) | 1772 | if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC) |
1774 | fws->borrow_defer_timestamp = jiffies + | 1773 | fws->borrow_defer_timestamp = jiffies + |
1775 | BRCMF_FWS_BORROW_DEFER_PERIOD; | 1774 | BRCMF_FWS_BORROW_DEFER_PERIOD; |
@@ -1789,7 +1788,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) | |||
1789 | } | 1788 | } |
1790 | brcmu_pkt_buf_free_skb(skb); | 1789 | brcmu_pkt_buf_free_skb(skb); |
1791 | } | 1790 | } |
1792 | brcmf_fws_unlock(drvr, flags); | 1791 | brcmf_fws_unlock(fws); |
1793 | return 0; | 1792 | return 0; |
1794 | } | 1793 | } |
1795 | 1794 | ||
@@ -1809,7 +1808,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) | |||
1809 | struct brcmf_fws_info *fws = ifp->drvr->fws; | 1808 | struct brcmf_fws_info *fws = ifp->drvr->fws; |
1810 | struct brcmf_fws_mac_descriptor *entry; | 1809 | struct brcmf_fws_mac_descriptor *entry; |
1811 | 1810 | ||
1812 | if (!ifp->ndev || !ifp->drvr->fw_signals) | 1811 | if (!ifp->ndev) |
1813 | return; | 1812 | return; |
1814 | 1813 | ||
1815 | entry = &fws->desc.iface[ifp->ifidx]; | 1814 | entry = &fws->desc.iface[ifp->ifidx]; |
@@ -1824,31 +1823,54 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) | |||
1824 | void brcmf_fws_del_interface(struct brcmf_if *ifp) | 1823 | void brcmf_fws_del_interface(struct brcmf_if *ifp) |
1825 | { | 1824 | { |
1826 | struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; | 1825 | struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc; |
1827 | ulong flags; | ||
1828 | 1826 | ||
1829 | if (!entry) | 1827 | if (!entry) |
1830 | return; | 1828 | return; |
1831 | 1829 | ||
1832 | brcmf_fws_lock(ifp->drvr, flags); | 1830 | brcmf_fws_lock(ifp->drvr->fws); |
1833 | ifp->fws_desc = NULL; | 1831 | ifp->fws_desc = NULL; |
1834 | brcmf_dbg(TRACE, "deleting %s\n", entry->name); | 1832 | brcmf_dbg(TRACE, "deleting %s\n", entry->name); |
1835 | brcmf_fws_macdesc_deinit(entry); | 1833 | brcmf_fws_macdesc_deinit(entry); |
1836 | brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); | 1834 | brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); |
1837 | brcmf_fws_unlock(ifp->drvr, flags); | 1835 | brcmf_fws_unlock(ifp->drvr->fws); |
1838 | } | 1836 | } |
1839 | 1837 | ||
1840 | static void brcmf_fws_dequeue_worker(struct work_struct *worker) | 1838 | static void brcmf_fws_dequeue_worker(struct work_struct *worker) |
1841 | { | 1839 | { |
1842 | struct brcmf_fws_info *fws; | 1840 | struct brcmf_fws_info *fws; |
1841 | struct brcmf_pub *drvr; | ||
1843 | struct sk_buff *skb; | 1842 | struct sk_buff *skb; |
1844 | ulong flags; | ||
1845 | int fifo; | 1843 | int fifo; |
1844 | u32 hslot; | ||
1845 | u32 ifidx; | ||
1846 | int ret; | ||
1846 | 1847 | ||
1847 | fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work); | 1848 | fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work); |
1849 | drvr = fws->drvr; | ||
1848 | 1850 | ||
1849 | brcmf_fws_lock(fws->drvr, flags); | 1851 | brcmf_fws_lock(fws); |
1850 | for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked; | 1852 | for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked; |
1851 | fifo--) { | 1853 | fifo--) { |
1854 | if (!brcmf_fws_fc_active(fws)) { | ||
1855 | while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) { | ||
1856 | hslot = brcmf_skb_htod_tag_get_field(skb, | ||
1857 | HSLOT); | ||
1858 | brcmf_fws_hanger_poppkt(&fws->hanger, hslot, | ||
1859 | &skb, true); | ||
1860 | ifidx = brcmf_skb_if_flags_get_field(skb, | ||
1861 | INDEX); | ||
1862 | brcmf_proto_hdrpush(drvr, ifidx, 0, skb); | ||
1863 | /* Use bus module to send data frame */ | ||
1864 | brcmf_fws_unlock(fws); | ||
1865 | ret = brcmf_bus_txdata(drvr->bus_if, skb); | ||
1866 | brcmf_fws_lock(fws); | ||
1867 | if (ret < 0) | ||
1868 | brcmf_txfinalize(drvr, skb, false); | ||
1869 | if (fws->bus_flow_blocked) | ||
1870 | break; | ||
1871 | } | ||
1872 | continue; | ||
1873 | } | ||
1852 | while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) && | 1874 | while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) && |
1853 | (fifo == BRCMF_FWS_FIFO_BCMC))) { | 1875 | (fifo == BRCMF_FWS_FIFO_BCMC))) { |
1854 | skb = brcmf_fws_deq(fws, fifo); | 1876 | skb = brcmf_fws_deq(fws, fifo); |
@@ -1876,42 +1898,43 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) | |||
1876 | } | 1898 | } |
1877 | } | 1899 | } |
1878 | } | 1900 | } |
1879 | brcmf_fws_unlock(fws->drvr, flags); | 1901 | brcmf_fws_unlock(fws); |
1880 | } | 1902 | } |
1881 | 1903 | ||
1882 | int brcmf_fws_init(struct brcmf_pub *drvr) | 1904 | int brcmf_fws_init(struct brcmf_pub *drvr) |
1883 | { | 1905 | { |
1906 | struct brcmf_fws_info *fws; | ||
1884 | u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; | 1907 | u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS; |
1885 | int rc; | 1908 | int rc; |
1886 | 1909 | ||
1887 | if (!drvr->fw_signals) | ||
1888 | return 0; | ||
1889 | |||
1890 | spin_lock_init(&drvr->fws_spinlock); | ||
1891 | |||
1892 | drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); | 1910 | drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL); |
1893 | if (!drvr->fws) { | 1911 | if (!drvr->fws) { |
1894 | rc = -ENOMEM; | 1912 | rc = -ENOMEM; |
1895 | goto fail; | 1913 | goto fail; |
1896 | } | 1914 | } |
1897 | 1915 | ||
1916 | fws = drvr->fws; | ||
1917 | |||
1918 | spin_lock_init(&fws->spinlock); | ||
1919 | |||
1898 | /* set linkage back */ | 1920 | /* set linkage back */ |
1899 | drvr->fws->drvr = drvr; | 1921 | fws->drvr = drvr; |
1900 | drvr->fws->fcmode = fcmode; | 1922 | fws->fcmode = fcmode; |
1901 | 1923 | ||
1902 | drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); | 1924 | fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq"); |
1903 | if (drvr->fws->fws_wq == NULL) { | 1925 | if (fws->fws_wq == NULL) { |
1904 | brcmf_err("workqueue creation failed\n"); | 1926 | brcmf_err("workqueue creation failed\n"); |
1905 | rc = -EBADF; | 1927 | rc = -EBADF; |
1906 | goto fail; | 1928 | goto fail; |
1907 | } | 1929 | } |
1908 | INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker); | 1930 | INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker); |
1909 | 1931 | ||
1910 | /* enable firmware signalling if fcmode active */ | 1932 | /* enable firmware signalling if fcmode active */ |
1911 | if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE) | 1933 | if (fws->fcmode != BRCMF_FWS_FCMODE_NONE) |
1912 | tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS | | 1934 | tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS | |
1913 | BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS | | 1935 | BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS | |
1914 | BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE; | 1936 | BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE | |
1937 | BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE; | ||
1915 | 1938 | ||
1916 | rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP, | 1939 | rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP, |
1917 | brcmf_fws_notify_credit_map); | 1940 | brcmf_fws_notify_credit_map); |
@@ -1927,31 +1950,33 @@ int brcmf_fws_init(struct brcmf_pub *drvr) | |||
1927 | goto fail; | 1950 | goto fail; |
1928 | } | 1951 | } |
1929 | 1952 | ||
1930 | /* setting the iovar may fail if feature is unsupported | 1953 | /* Setting the iovar may fail if feature is unsupported |
1931 | * so leave the rc as is so driver initialization can | 1954 | * so leave the rc as is so driver initialization can |
1932 | * continue. | 1955 | * continue. Set mode back to none indicating not enabled. |
1933 | */ | 1956 | */ |
1957 | fws->fw_signals = true; | ||
1934 | if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) { | 1958 | if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) { |
1935 | brcmf_err("failed to set bdcv2 tlv signaling\n"); | 1959 | brcmf_err("failed to set bdcv2 tlv signaling\n"); |
1936 | goto fail_event; | 1960 | fws->fcmode = BRCMF_FWS_FCMODE_NONE; |
1961 | fws->fw_signals = false; | ||
1937 | } | 1962 | } |
1938 | 1963 | ||
1939 | brcmf_fws_hanger_init(&drvr->fws->hanger); | 1964 | if (brcmf_fil_iovar_int_set(drvr->iflist[0], "ampdu_hostreorder", 1)) |
1940 | brcmf_fws_macdesc_init(&drvr->fws->desc.other, NULL, 0); | 1965 | brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n"); |
1941 | brcmf_fws_macdesc_set_name(drvr->fws, &drvr->fws->desc.other); | 1966 | |
1942 | brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, | 1967 | brcmf_fws_hanger_init(&fws->hanger); |
1968 | brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0); | ||
1969 | brcmf_fws_macdesc_set_name(fws, &fws->desc.other); | ||
1970 | brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, | ||
1943 | BRCMF_FWS_PSQ_LEN); | 1971 | BRCMF_FWS_PSQ_LEN); |
1944 | 1972 | ||
1945 | /* create debugfs file for statistics */ | 1973 | /* create debugfs file for statistics */ |
1946 | brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats); | 1974 | brcmf_debugfs_create_fws_stats(drvr, &fws->stats); |
1947 | 1975 | ||
1948 | brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", | 1976 | brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", |
1949 | drvr->fw_signals ? "enabled" : "disabled", tlv); | 1977 | fws->fw_signals ? "enabled" : "disabled", tlv); |
1950 | return 0; | 1978 | return 0; |
1951 | 1979 | ||
1952 | fail_event: | ||
1953 | brcmf_fweh_unregister(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT); | ||
1954 | brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP); | ||
1955 | fail: | 1980 | fail: |
1956 | brcmf_fws_deinit(drvr); | 1981 | brcmf_fws_deinit(drvr); |
1957 | return rc; | 1982 | return rc; |
@@ -1960,24 +1985,18 @@ fail: | |||
1960 | void brcmf_fws_deinit(struct brcmf_pub *drvr) | 1985 | void brcmf_fws_deinit(struct brcmf_pub *drvr) |
1961 | { | 1986 | { |
1962 | struct brcmf_fws_info *fws = drvr->fws; | 1987 | struct brcmf_fws_info *fws = drvr->fws; |
1963 | ulong flags; | ||
1964 | 1988 | ||
1965 | if (!fws) | 1989 | if (!fws) |
1966 | return; | 1990 | return; |
1967 | 1991 | ||
1968 | /* disable firmware signalling entirely | ||
1969 | * to avoid using the workqueue. | ||
1970 | */ | ||
1971 | drvr->fw_signals = false; | ||
1972 | |||
1973 | if (drvr->fws->fws_wq) | 1992 | if (drvr->fws->fws_wq) |
1974 | destroy_workqueue(drvr->fws->fws_wq); | 1993 | destroy_workqueue(drvr->fws->fws_wq); |
1975 | 1994 | ||
1976 | /* cleanup */ | 1995 | /* cleanup */ |
1977 | brcmf_fws_lock(drvr, flags); | 1996 | brcmf_fws_lock(fws); |
1978 | brcmf_fws_cleanup(fws, -1); | 1997 | brcmf_fws_cleanup(fws, -1); |
1979 | drvr->fws = NULL; | 1998 | drvr->fws = NULL; |
1980 | brcmf_fws_unlock(drvr, flags); | 1999 | brcmf_fws_unlock(fws); |
1981 | 2000 | ||
1982 | /* free top structure */ | 2001 | /* free top structure */ |
1983 | kfree(fws); | 2002 | kfree(fws); |
@@ -1985,7 +2004,7 @@ void brcmf_fws_deinit(struct brcmf_pub *drvr) | |||
1985 | 2004 | ||
1986 | bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) | 2005 | bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) |
1987 | { | 2006 | { |
1988 | if (!fws) | 2007 | if (!fws->creditmap_received) |
1989 | return false; | 2008 | return false; |
1990 | 2009 | ||
1991 | return fws->fcmode != BRCMF_FWS_FCMODE_NONE; | 2010 | return fws->fcmode != BRCMF_FWS_FCMODE_NONE; |
@@ -1993,17 +2012,16 @@ bool brcmf_fws_fc_active(struct brcmf_fws_info *fws) | |||
1993 | 2012 | ||
1994 | void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) | 2013 | void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb) |
1995 | { | 2014 | { |
1996 | ulong flags; | ||
1997 | u32 hslot; | 2015 | u32 hslot; |
1998 | 2016 | ||
1999 | if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) { | 2017 | if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) { |
2000 | brcmu_pkt_buf_free_skb(skb); | 2018 | brcmu_pkt_buf_free_skb(skb); |
2001 | return; | 2019 | return; |
2002 | } | 2020 | } |
2003 | brcmf_fws_lock(fws->drvr, flags); | 2021 | brcmf_fws_lock(fws); |
2004 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); | 2022 | hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); |
2005 | brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0); | 2023 | brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0); |
2006 | brcmf_fws_unlock(fws->drvr, flags); | 2024 | brcmf_fws_unlock(fws); |
2007 | } | 2025 | } |
2008 | 2026 | ||
2009 | void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) | 2027 | void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) |