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>
This commit is contained in:
parent
80898a1178
commit
c6a681ab2c
|
@ -905,10 +905,26 @@ static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* using macro so sparse checking does not complain
|
||||||
|
* about locking imbalance.
|
||||||
|
*/
|
||||||
|
#define brcmf_fws_lock(drvr, flags) \
|
||||||
|
do { \
|
||||||
|
flags = 0; \
|
||||||
|
spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* using macro so sparse checking does not complain
|
||||||
|
* about locking imbalance.
|
||||||
|
*/
|
||||||
|
#define brcmf_fws_unlock(drvr, flags) \
|
||||||
|
spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
|
||||||
|
|
||||||
static
|
static
|
||||||
int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
|
int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
|
||||||
{
|
{
|
||||||
struct brcmf_fws_mac_descriptor *entry, *existing;
|
struct brcmf_fws_mac_descriptor *entry, *existing;
|
||||||
|
ulong flags;
|
||||||
u8 mac_handle;
|
u8 mac_handle;
|
||||||
u8 ifidx;
|
u8 ifidx;
|
||||||
u8 *addr;
|
u8 *addr;
|
||||||
|
@ -922,8 +938,10 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
|
||||||
if (entry->occupied) {
|
if (entry->occupied) {
|
||||||
brcmf_dbg(TRACE, "deleting %s mac %pM\n",
|
brcmf_dbg(TRACE, "deleting %s mac %pM\n",
|
||||||
entry->name, addr);
|
entry->name, addr);
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
brcmf_fws_macdesc_cleanup(fws, entry, -1);
|
brcmf_fws_macdesc_cleanup(fws, entry, -1);
|
||||||
brcmf_fws_macdesc_deinit(entry);
|
brcmf_fws_macdesc_deinit(entry);
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
} else
|
} else
|
||||||
fws->stats.mac_update_failed++;
|
fws->stats.mac_update_failed++;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -932,11 +950,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
|
||||||
existing = brcmf_fws_macdesc_lookup(fws, addr);
|
existing = brcmf_fws_macdesc_lookup(fws, addr);
|
||||||
if (IS_ERR(existing)) {
|
if (IS_ERR(existing)) {
|
||||||
if (!entry->occupied) {
|
if (!entry->occupied) {
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
entry->mac_handle = mac_handle;
|
entry->mac_handle = mac_handle;
|
||||||
brcmf_fws_macdesc_init(entry, addr, ifidx);
|
brcmf_fws_macdesc_init(entry, addr, ifidx);
|
||||||
brcmf_fws_macdesc_set_name(fws, entry);
|
brcmf_fws_macdesc_set_name(fws, entry);
|
||||||
brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
|
brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
|
||||||
BRCMF_FWS_PSQ_LEN);
|
BRCMF_FWS_PSQ_LEN);
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
|
brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
|
||||||
} else {
|
} else {
|
||||||
fws->stats.mac_update_failed++;
|
fws->stats.mac_update_failed++;
|
||||||
|
@ -944,11 +964,13 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
|
||||||
} else {
|
} else {
|
||||||
if (entry != existing) {
|
if (entry != existing) {
|
||||||
brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
|
brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
memcpy(entry, existing,
|
memcpy(entry, existing,
|
||||||
offsetof(struct brcmf_fws_mac_descriptor, psq));
|
offsetof(struct brcmf_fws_mac_descriptor, psq));
|
||||||
entry->mac_handle = mac_handle;
|
entry->mac_handle = mac_handle;
|
||||||
brcmf_fws_macdesc_deinit(existing);
|
brcmf_fws_macdesc_deinit(existing);
|
||||||
brcmf_fws_macdesc_set_name(fws, entry);
|
brcmf_fws_macdesc_set_name(fws, entry);
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
|
brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
|
||||||
addr);
|
addr);
|
||||||
} else {
|
} else {
|
||||||
|
@ -964,7 +986,9 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
|
||||||
u8 type, u8 *data)
|
u8 type, u8 *data)
|
||||||
{
|
{
|
||||||
struct brcmf_fws_mac_descriptor *entry;
|
struct brcmf_fws_mac_descriptor *entry;
|
||||||
|
ulong flags;
|
||||||
u8 mac_handle;
|
u8 mac_handle;
|
||||||
|
int ret;
|
||||||
|
|
||||||
mac_handle = data[0];
|
mac_handle = data[0];
|
||||||
entry = &fws->desc.nodes[mac_handle & 0x1F];
|
entry = &fws->desc.nodes[mac_handle & 0x1F];
|
||||||
|
@ -972,26 +996,30 @@ static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
|
||||||
fws->stats.mac_ps_update_failed++;
|
fws->stats.mac_ps_update_failed++;
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
}
|
}
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
/* a state update should wipe old credits */
|
/* a state update should wipe old credits */
|
||||||
entry->requested_credit = 0;
|
entry->requested_credit = 0;
|
||||||
entry->requested_packet = 0;
|
entry->requested_packet = 0;
|
||||||
if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
|
if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
|
||||||
entry->state = BRCMF_FWS_STATE_OPEN;
|
entry->state = BRCMF_FWS_STATE_OPEN;
|
||||||
return BRCMF_FWS_RET_OK_SCHEDULE;
|
ret = BRCMF_FWS_RET_OK_SCHEDULE;
|
||||||
} else {
|
} else {
|
||||||
entry->state = BRCMF_FWS_STATE_CLOSE;
|
entry->state = BRCMF_FWS_STATE_CLOSE;
|
||||||
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
|
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
|
||||||
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
|
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
|
||||||
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
|
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
|
||||||
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
|
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
|
||||||
|
ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
|
||||||
}
|
}
|
||||||
return BRCMF_FWS_RET_OK_NOSCHEDULE;
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
|
static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
|
||||||
u8 type, u8 *data)
|
u8 type, u8 *data)
|
||||||
{
|
{
|
||||||
struct brcmf_fws_mac_descriptor *entry;
|
struct brcmf_fws_mac_descriptor *entry;
|
||||||
|
ulong flags;
|
||||||
u8 ifidx;
|
u8 ifidx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1010,17 +1038,24 @@ static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
|
||||||
|
|
||||||
brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
|
brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
|
||||||
entry->name);
|
entry->name);
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BRCMF_FWS_TYPE_INTERFACE_OPEN:
|
case BRCMF_FWS_TYPE_INTERFACE_OPEN:
|
||||||
entry->state = BRCMF_FWS_STATE_OPEN;
|
entry->state = BRCMF_FWS_STATE_OPEN;
|
||||||
return BRCMF_FWS_RET_OK_SCHEDULE;
|
ret = BRCMF_FWS_RET_OK_SCHEDULE;
|
||||||
|
break;
|
||||||
case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
|
case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
|
||||||
entry->state = BRCMF_FWS_STATE_CLOSE;
|
entry->state = BRCMF_FWS_STATE_CLOSE;
|
||||||
return BRCMF_FWS_RET_OK_NOSCHEDULE;
|
ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
|
return ret;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
fws->stats.if_update_failed++;
|
fws->stats.if_update_failed++;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1030,6 +1065,7 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
|
||||||
u8 *data)
|
u8 *data)
|
||||||
{
|
{
|
||||||
struct brcmf_fws_mac_descriptor *entry;
|
struct brcmf_fws_mac_descriptor *entry;
|
||||||
|
ulong flags;
|
||||||
|
|
||||||
entry = &fws->desc.nodes[data[1] & 0x1F];
|
entry = &fws->desc.nodes[data[1] & 0x1F];
|
||||||
if (!entry->occupied) {
|
if (!entry->occupied) {
|
||||||
|
@ -1043,12 +1079,14 @@ static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
|
||||||
brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
|
brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
|
||||||
brcmf_fws_get_tlv_name(type), type, entry->name,
|
brcmf_fws_get_tlv_name(type), type, entry->name,
|
||||||
data[0], data[2]);
|
data[0], data[2]);
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
|
if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
|
||||||
entry->requested_credit = data[0];
|
entry->requested_credit = data[0];
|
||||||
else
|
else
|
||||||
entry->requested_packet = data[0];
|
entry->requested_packet = data[0];
|
||||||
|
|
||||||
entry->ac_bitmap = data[2];
|
entry->ac_bitmap = data[2];
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
return BRCMF_FWS_RET_OK_SCHEDULE;
|
return BRCMF_FWS_RET_OK_SCHEDULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1345,6 +1383,7 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
|
||||||
static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
|
static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
|
||||||
u8 *data)
|
u8 *data)
|
||||||
{
|
{
|
||||||
|
ulong flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
|
if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
|
||||||
|
@ -1353,16 +1392,19 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
|
||||||
}
|
}
|
||||||
|
|
||||||
brcmf_dbg(DATA, "enter: data %pM\n", data);
|
brcmf_dbg(DATA, "enter: data %pM\n", data);
|
||||||
|
brcmf_fws_lock(fws->drvr, flags);
|
||||||
for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
|
for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
|
||||||
brcmf_fws_return_credits(fws, i, data[i]);
|
brcmf_fws_return_credits(fws, i, data[i]);
|
||||||
|
|
||||||
brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
|
brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
|
||||||
fws->fifo_delay_map);
|
fws->fifo_delay_map);
|
||||||
|
brcmf_fws_unlock(fws->drvr, flags);
|
||||||
return BRCMF_FWS_RET_OK_SCHEDULE;
|
return BRCMF_FWS_RET_OK_SCHEDULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
|
static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
|
||||||
{
|
{
|
||||||
|
ulong lflags;
|
||||||
__le32 status_le;
|
__le32 status_le;
|
||||||
u32 status;
|
u32 status;
|
||||||
u32 hslot;
|
u32 hslot;
|
||||||
|
@ -1376,7 +1418,10 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
|
||||||
hslot = brcmf_txstatus_get_field(status, HSLOT);
|
hslot = brcmf_txstatus_get_field(status, HSLOT);
|
||||||
genbit = brcmf_txstatus_get_field(status, GENERATION);
|
genbit = brcmf_txstatus_get_field(status, GENERATION);
|
||||||
|
|
||||||
return brcmf_fws_txs_process(fws, flags, hslot, genbit);
|
brcmf_fws_lock(fws->drvr, lflags);
|
||||||
|
brcmf_fws_txs_process(fws, flags, hslot, genbit);
|
||||||
|
brcmf_fws_unlock(fws->drvr, lflags);
|
||||||
|
return BRCMF_FWS_RET_OK_NOSCHEDULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
|
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)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* using macro so sparse checking does not complain
|
|
||||||
* about locking imbalance.
|
|
||||||
*/
|
|
||||||
#define brcmf_fws_lock(drvr, flags) \
|
|
||||||
do { \
|
|
||||||
flags = 0; \
|
|
||||||
spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* using macro so sparse checking does not complain
|
|
||||||
* about locking imbalance.
|
|
||||||
*/
|
|
||||||
#define brcmf_fws_unlock(drvr, flags) \
|
|
||||||
spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
|
|
||||||
|
|
||||||
static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
|
static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
|
||||||
const struct brcmf_event_msg *e,
|
const struct brcmf_event_msg *e,
|
||||||
void *data)
|
void *data)
|
||||||
|
@ -1454,7 +1484,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct brcmf_fws_info *fws = drvr->fws;
|
struct brcmf_fws_info *fws = drvr->fws;
|
||||||
ulong flags;
|
|
||||||
u8 *signal_data;
|
u8 *signal_data;
|
||||||
s16 data_len;
|
s16 data_len;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
@ -1474,9 +1503,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lock during tlv parsing */
|
|
||||||
brcmf_fws_lock(drvr, flags);
|
|
||||||
|
|
||||||
fws->stats.header_pulls++;
|
fws->stats.header_pulls++;
|
||||||
data_len = signal_len;
|
data_len = signal_len;
|
||||||
signal_data = skb->data;
|
signal_data = skb->data;
|
||||||
|
@ -1570,7 +1596,6 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
|
||||||
if (skb->len == 0)
|
if (skb->len == 0)
|
||||||
fws->stats.header_only_pkt++;
|
fws->stats.header_only_pkt++;
|
||||||
|
|
||||||
brcmf_fws_unlock(drvr, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue