Skip to content

Commit

Permalink
brcmfmac: rework headroom check in .start_xmit()
Browse files Browse the repository at this point in the history
Since commit 9cc4b7c ("brcmfmac: Make skb header writable
before use") the headroom usage has been fixed. However, the
driver was keeping statistics that got lost. So reworking the
code so we get those driver statistics back for debugging.

Cc: James Hughes <james.hughes@raspberrypi.org>
Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
  • Loading branch information
Arend Van Spriel authored and Kalle Valo committed Jun 28, 2017
1 parent a833f3d commit 270a6c1
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
15 changes: 13 additions & 2 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ struct brcmf_bus_msgbuf {
};


/**
* struct brcmf_bus_stats - bus statistic counters.
*
* @pktcowed: packets cowed for extra headroom/unorphan.
* @pktcow_failed: packets dropped due to failed cow-ing.
*/
struct brcmf_bus_stats {
atomic_t pktcowed;
atomic_t pktcow_failed;
};

/**
* struct brcmf_bus - interface structure between common and bus layer
*
Expand All @@ -120,8 +131,8 @@ struct brcmf_bus_msgbuf {
* @dev: device pointer of bus device.
* @drvr: public driver information.
* @state: operational state of the bus interface.
* @stats: statistics shared between common and bus layer.
* @maxctl: maximum size for rxctl request message.
* @tx_realloc: number of tx packets realloced for headroom.
* @chip: device identifier of the dongle chip.
* @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver.
Expand All @@ -137,8 +148,8 @@ struct brcmf_bus {
struct device *dev;
struct brcmf_pub *drvr;
enum brcmf_bus_state state;
struct brcmf_bus_stats stats;
uint maxctl;
atomic_t tx_realloc;
u32 chip;
u32 chiprev;
bool always_use_fws_queue;
Expand Down
23 changes: 16 additions & 7 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
struct ethhdr *eh;
int head_delta;

brcmf_dbg(DATA, "Enter, bsscfgidx=%d\n", ifp->bsscfgidx);

Expand All @@ -211,13 +212,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}

/* Make sure there's enough writable headroom*/
ret = skb_cow_head(skb, drvr->hdrlen);
if (ret < 0) {
brcmf_err("%s: skb_cow_head failed\n",
brcmf_ifname(ifp));
dev_kfree_skb(skb);
goto done;
/* Make sure there's enough writeable headroom */
if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
head_delta = drvr->hdrlen - skb_headroom(skb);

brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
brcmf_ifname(ifp), head_delta);
atomic_inc(&drvr->bus_if->stats.pktcowed);
ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
GFP_ATOMIC);
if (ret < 0) {
brcmf_err("%s: failed to expand headroom\n",
brcmf_ifname(ifp));
atomic_inc(&drvr->bus_if->stats.pktcow_failed);
goto done;
}
}

/* validate length for ether packet */
Expand Down
13 changes: 8 additions & 5 deletions drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,7 @@ brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)

static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
{
struct brcmf_bus_stats *stats;
u16 head_pad;
u8 *dat_buf;

Expand All @@ -2046,16 +2047,18 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
head_pad = ((unsigned long)dat_buf % bus->head_align);
if (head_pad) {
if (skb_headroom(pkt) < head_pad) {
atomic_inc(&bus->sdiodev->bus_if->tx_realloc);
head_pad = 0;
if (skb_cow(pkt, head_pad))
stats = &bus->sdiodev->bus_if->stats;
atomic_inc(&stats->pktcowed);
if (skb_cow_head(pkt, head_pad)) {
atomic_inc(&stats->pktcow_failed);
return -ENOMEM;
}
}
skb_push(pkt, head_pad);
dat_buf = (u8 *)(pkt->data);
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
}
return head_pad;
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
return 0;
}

/**
Expand Down

0 comments on commit 270a6c1

Please sign in to comment.