diff options
author | Arend van Spriel <arend@broadcom.com> | 2013-06-26 08:20:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-06-27 13:42:19 -0400 |
commit | c6a681ab2c73c1296b4214307216dffeb52558df (patch) | |
tree | dd332a6536e23bd59b12ca0533a6cff172cad5b6 | |
parent | 80898a117895235587b7dde63e3240e4f4d440c1 (diff) |
brcmfmac: reduce firmware-signalling locking scope in rx path
In the receive path a spinlock is taken upon parsing the TLV signal
header. This moves to locking to the TLV handling functions where
it protects the data structures.
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index e92a3ce58c02..f0d9f7f6c83d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | |||
@@ -905,10 +905,26 @@ static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) | |||
905 | return 0; | 905 | return 0; |
906 | } | 906 | } |
907 | 907 | ||
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 | |||
908 | static | 923 | static |
909 | int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | 924 | int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) |
910 | { | 925 | { |
911 | struct brcmf_fws_mac_descriptor *entry, *existing; | 926 | struct brcmf_fws_mac_descriptor *entry, *existing; |
927 | ulong flags; | ||
912 | u8 mac_handle; | 928 | u8 mac_handle; |
913 | u8 ifidx; | 929 | u8 ifidx; |
914 | u8 *addr; | 930 | u8 *addr; |
@@ -922,8 +938,10 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
922 | if (entry->occupied) { | 938 | if (entry->occupied) { |
923 | brcmf_dbg(TRACE, "deleting %s mac %pM\n", | 939 | brcmf_dbg(TRACE, "deleting %s mac %pM\n", |
924 | entry->name, addr); | 940 | entry->name, addr); |
941 | brcmf_fws_lock(fws->drvr, flags); | ||
925 | brcmf_fws_macdesc_cleanup(fws, entry, -1); | 942 | brcmf_fws_macdesc_cleanup(fws, entry, -1); |
926 | brcmf_fws_macdesc_deinit(entry); | 943 | brcmf_fws_macdesc_deinit(entry); |
944 | brcmf_fws_unlock(fws->drvr, flags); | ||
927 | } else | 945 | } else |
928 | fws->stats.mac_update_failed++; | 946 | fws->stats.mac_update_failed++; |
929 | return 0; | 947 | return 0; |
@@ -932,11 +950,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
932 | existing = brcmf_fws_macdesc_lookup(fws, addr); | 950 | existing = brcmf_fws_macdesc_lookup(fws, addr); |
933 | if (IS_ERR(existing)) { | 951 | if (IS_ERR(existing)) { |
934 | if (!entry->occupied) { | 952 | if (!entry->occupied) { |
953 | brcmf_fws_lock(fws->drvr, flags); | ||
935 | entry->mac_handle = mac_handle; | 954 | entry->mac_handle = mac_handle; |
936 | brcmf_fws_macdesc_init(entry, addr, ifidx); | 955 | brcmf_fws_macdesc_init(entry, addr, ifidx); |
937 | brcmf_fws_macdesc_set_name(fws, entry); | 956 | brcmf_fws_macdesc_set_name(fws, entry); |
938 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, | 957 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, |
939 | BRCMF_FWS_PSQ_LEN); | 958 | BRCMF_FWS_PSQ_LEN); |
959 | brcmf_fws_unlock(fws->drvr, flags); | ||
940 | brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr); | 960 | brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr); |
941 | } else { | 961 | } else { |
942 | fws->stats.mac_update_failed++; | 962 | fws->stats.mac_update_failed++; |
@@ -944,11 +964,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | |||
944 | } else { | 964 | } else { |
945 | if (entry != existing) { | 965 | if (entry != existing) { |
946 | brcmf_dbg(TRACE, "copy mac %s\n", existing->name); | 966 | brcmf_dbg(TRACE, "copy mac %s\n", existing->name); |
967 | brcmf_fws_lock(fws->drvr, flags); | ||
947 | memcpy(entry, existing, | 968 | memcpy(entry, existing, |
948 | offsetof(struct brcmf_fws_mac_descriptor, psq)); | 969 | offsetof(struct brcmf_fws_mac_descriptor, psq)); |
949 | entry->mac_handle = mac_handle; | 970 | entry->mac_handle = mac_handle; |
950 | brcmf_fws_macdesc_deinit(existing); | 971 | brcmf_fws_macdesc_deinit(existing); |
951 | brcmf_fws_macdesc_set_name(fws, entry); | 972 | brcmf_fws_macdesc_set_name(fws, entry); |
973 | brcmf_fws_unlock(fws->drvr, flags); | ||
952 | brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name, | 974 | brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name, |
953 | addr); | 975 | addr); |
954 | } else { | 976 | } else { |
@@ -964,7 +986,9 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, | |||
964 | u8 type, u8 *data) | 986 | u8 type, u8 *data) |
965 | { | 987 | { |
966 | struct brcmf_fws_mac_descriptor *entry; | 988 | struct brcmf_fws_mac_descriptor *entry; |
989 | ulong flags; | ||
967 | u8 mac_handle; | 990 | u8 mac_handle; |
991 | int ret; | ||
968 | 992 | ||
969 | mac_handle = data[0]; | 993 | mac_handle = data[0]; |
970 | entry = &fws->desc.nodes[mac_handle & 0x1F]; | 994 | entry = &fws->desc.nodes[mac_handle & 0x1F]; |
@@ -972,26 +996,30 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws, | |||
972 | fws->stats.mac_ps_update_failed++; | 996 | fws->stats.mac_ps_update_failed++; |
973 | return -ESRCH; | 997 | return -ESRCH; |
974 | } | 998 | } |
999 | brcmf_fws_lock(fws->drvr, flags); | ||
975 | /* a state update should wipe old credits */ | 1000 | /* a state update should wipe old credits */ |
976 | entry->requested_credit = 0; | 1001 | entry->requested_credit = 0; |
977 | entry->requested_packet = 0; | 1002 | entry->requested_packet = 0; |
978 | if (type == BRCMF_FWS_TYPE_MAC_OPEN) { | 1003 | if (type == BRCMF_FWS_TYPE_MAC_OPEN) { |
979 | entry->state = BRCMF_FWS_STATE_OPEN; | 1004 | entry->state = BRCMF_FWS_STATE_OPEN; |
980 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1005 | ret = BRCMF_FWS_RET_OK_SCHEDULE; |
981 | } else { | 1006 | } else { |
982 | entry->state = BRCMF_FWS_STATE_CLOSE; | 1007 | entry->state = BRCMF_FWS_STATE_CLOSE; |
983 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false); | 1008 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false); |
984 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false); | 1009 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false); |
985 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false); | 1010 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false); |
986 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true); | 1011 | brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true); |
1012 | ret = BRCMF_FWS_RET_OK_NOSCHEDULE; | ||
987 | } | 1013 | } |
988 | return BRCMF_FWS_RET_OK_NOSCHEDULE; | 1014 | brcmf_fws_unlock(fws->drvr, flags); |
1015 | return ret; | ||
989 | } | 1016 | } |
990 | 1017 | ||
991 | static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, | 1018 | static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, |
992 | u8 type, u8 *data) | 1019 | u8 type, u8 *data) |
993 | { | 1020 | { |
994 | struct brcmf_fws_mac_descriptor *entry; | 1021 | struct brcmf_fws_mac_descriptor *entry; |
1022 | ulong flags; | ||
995 | u8 ifidx; | 1023 | u8 ifidx; |
996 | int ret; | 1024 | int ret; |
997 | 1025 | ||
@@ -1010,17 +1038,24 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws, | |||
1010 | 1038 | ||
1011 | 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, |
1012 | entry->name); | 1040 | entry->name); |
1041 | brcmf_fws_lock(fws->drvr, flags); | ||
1013 | switch (type) { | 1042 | switch (type) { |
1014 | case BRCMF_FWS_TYPE_INTERFACE_OPEN: | 1043 | case BRCMF_FWS_TYPE_INTERFACE_OPEN: |
1015 | entry->state = BRCMF_FWS_STATE_OPEN; | 1044 | entry->state = BRCMF_FWS_STATE_OPEN; |
1016 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1045 | ret = BRCMF_FWS_RET_OK_SCHEDULE; |
1046 | break; | ||
1017 | case BRCMF_FWS_TYPE_INTERFACE_CLOSE: | 1047 | case BRCMF_FWS_TYPE_INTERFACE_CLOSE: |
1018 | entry->state = BRCMF_FWS_STATE_CLOSE; | 1048 | entry->state = BRCMF_FWS_STATE_CLOSE; |
1019 | return BRCMF_FWS_RET_OK_NOSCHEDULE; | 1049 | ret = BRCMF_FWS_RET_OK_NOSCHEDULE; |
1050 | break; | ||
1020 | default: | 1051 | default: |
1021 | ret = -EINVAL; | 1052 | ret = -EINVAL; |
1022 | break; | 1053 | brcmf_fws_unlock(fws->drvr, flags); |
1054 | goto fail; | ||
1023 | } | 1055 | } |
1056 | brcmf_fws_unlock(fws->drvr, flags); | ||
1057 | return ret; | ||
1058 | |||
1024 | fail: | 1059 | fail: |
1025 | fws->stats.if_update_failed++; | 1060 | fws->stats.if_update_failed++; |
1026 | return ret; | 1061 | return ret; |
@@ -1030,6 +1065,7 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, | |||
1030 | u8 *data) | 1065 | u8 *data) |
1031 | { | 1066 | { |
1032 | struct brcmf_fws_mac_descriptor *entry; | 1067 | struct brcmf_fws_mac_descriptor *entry; |
1068 | ulong flags; | ||
1033 | 1069 | ||
1034 | entry = &fws->desc.nodes[data[1] & 0x1F]; | 1070 | entry = &fws->desc.nodes[data[1] & 0x1F]; |
1035 | if (!entry->occupied) { | 1071 | if (!entry->occupied) { |
@@ -1043,12 +1079,14 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type, | |||
1043 | brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n", | 1079 | brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n", |
1044 | brcmf_fws_get_tlv_name(type), type, entry->name, | 1080 | brcmf_fws_get_tlv_name(type), type, entry->name, |
1045 | data[0], data[2]); | 1081 | data[0], data[2]); |
1082 | brcmf_fws_lock(fws->drvr, flags); | ||
1046 | if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT) | 1083 | if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT) |
1047 | entry->requested_credit = data[0]; | 1084 | entry->requested_credit = data[0]; |
1048 | else | 1085 | else |
1049 | entry->requested_packet = data[0]; | 1086 | entry->requested_packet = data[0]; |
1050 | 1087 | ||
1051 | entry->ac_bitmap = data[2]; | 1088 | entry->ac_bitmap = data[2]; |
1089 | brcmf_fws_unlock(fws->drvr, flags); | ||
1052 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1090 | return BRCMF_FWS_RET_OK_SCHEDULE; |
1053 | } | 1091 | } |
1054 | 1092 | ||
@@ -1345,6 +1383,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, | |||
1345 | static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, | 1383 | static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, |
1346 | u8 *data) | 1384 | u8 *data) |
1347 | { | 1385 | { |
1386 | ulong flags; | ||
1348 | int i; | 1387 | int i; |
1349 | 1388 | ||
1350 | if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) { | 1389 | if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) { |
@@ -1353,16 +1392,19 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws, | |||
1353 | } | 1392 | } |
1354 | 1393 | ||
1355 | brcmf_dbg(DATA, "enter: data %pM\n", data); | 1394 | brcmf_dbg(DATA, "enter: data %pM\n", data); |
1395 | brcmf_fws_lock(fws->drvr, flags); | ||
1356 | for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++) | 1396 | for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++) |
1357 | brcmf_fws_return_credits(fws, i, data[i]); | 1397 | brcmf_fws_return_credits(fws, i, data[i]); |
1358 | 1398 | ||
1359 | brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map, | 1399 | brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map, |
1360 | fws->fifo_delay_map); | 1400 | fws->fifo_delay_map); |
1401 | brcmf_fws_unlock(fws->drvr, flags); | ||
1361 | return BRCMF_FWS_RET_OK_SCHEDULE; | 1402 | return BRCMF_FWS_RET_OK_SCHEDULE; |
1362 | } | 1403 | } |
1363 | 1404 | ||
1364 | static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | 1405 | static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) |
1365 | { | 1406 | { |
1407 | ulong lflags; | ||
1366 | __le32 status_le; | 1408 | __le32 status_le; |
1367 | u32 status; | 1409 | u32 status; |
1368 | u32 hslot; | 1410 | u32 hslot; |
@@ -1376,7 +1418,10 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) | |||
1376 | hslot = brcmf_txstatus_get_field(status, HSLOT); | 1418 | hslot = brcmf_txstatus_get_field(status, HSLOT); |
1377 | genbit = brcmf_txstatus_get_field(status, GENERATION); | 1419 | genbit = brcmf_txstatus_get_field(status, GENERATION); |
1378 | 1420 | ||
1379 | return brcmf_fws_txs_process(fws, flags, hslot, genbit); | 1421 | brcmf_fws_lock(fws->drvr, lflags); |
1422 | brcmf_fws_txs_process(fws, flags, hslot, genbit); | ||
1423 | brcmf_fws_unlock(fws->drvr, lflags); | ||
1424 | return BRCMF_FWS_RET_OK_NOSCHEDULE; | ||
1380 | } | 1425 | } |
1381 | 1426 | ||
1382 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) | 1427 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) |
@@ -1389,21 +1434,6 @@ static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) | |||
1389 | return 0; | 1434 | return 0; |
1390 | } | 1435 | } |
1391 | 1436 | ||
1392 | /* using macro so sparse checking does not complain | ||
1393 | * about locking imbalance. | ||
1394 | */ | ||
1395 | #define brcmf_fws_lock(drvr, flags) \ | ||
1396 | do { \ | ||
1397 | flags = 0; \ | ||
1398 | spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \ | ||
1399 | } while (0) | ||
1400 | |||
1401 | /* using macro so sparse checking does not complain | ||
1402 | * about locking imbalance. | ||
1403 | */ | ||
1404 | #define brcmf_fws_unlock(drvr, flags) \ | ||
1405 | spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags)) | ||
1406 | |||
1407 | static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, | 1437 | static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp, |
1408 | const struct brcmf_event_msg *e, | 1438 | const struct brcmf_event_msg *e, |
1409 | void *data) | 1439 | void *data) |
@@ -1454,7 +1484,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
1454 | struct sk_buff *skb) | 1484 | struct sk_buff *skb) |
1455 | { | 1485 | { |
1456 | struct brcmf_fws_info *fws = drvr->fws; | 1486 | struct brcmf_fws_info *fws = drvr->fws; |
1457 | ulong flags; | ||
1458 | u8 *signal_data; | 1487 | u8 *signal_data; |
1459 | s16 data_len; | 1488 | s16 data_len; |
1460 | u8 type; | 1489 | u8 type; |
@@ -1474,9 +1503,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
1474 | return 0; | 1503 | return 0; |
1475 | } | 1504 | } |
1476 | 1505 | ||
1477 | /* lock during tlv parsing */ | ||
1478 | brcmf_fws_lock(drvr, flags); | ||
1479 | |||
1480 | fws->stats.header_pulls++; | 1506 | fws->stats.header_pulls++; |
1481 | data_len = signal_len; | 1507 | data_len = signal_len; |
1482 | signal_data = skb->data; | 1508 | signal_data = skb->data; |
@@ -1570,7 +1596,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
1570 | if (skb->len == 0) | 1596 | if (skb->len == 0) |
1571 | fws->stats.header_only_pkt++; | 1597 | fws->stats.header_only_pkt++; |
1572 | 1598 | ||
1573 | brcmf_fws_unlock(drvr, flags); | ||
1574 | return 0; | 1599 | return 0; |
1575 | } | 1600 | } |
1576 | 1601 | ||