Skip to content

Commit 270a6c1

Browse files
Arend Van SprielKalle Valo
authored andcommitted
brcmfmac: rework headroom check in .start_xmit()
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>
1 parent a833f3d commit 270a6c1

File tree

3 files changed

+37
-14
lines changed

3 files changed

+37
-14
lines changed

drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ struct brcmf_bus_msgbuf {
112112
};
113113

114114

115+
/**
116+
* struct brcmf_bus_stats - bus statistic counters.
117+
*
118+
* @pktcowed: packets cowed for extra headroom/unorphan.
119+
* @pktcow_failed: packets dropped due to failed cow-ing.
120+
*/
121+
struct brcmf_bus_stats {
122+
atomic_t pktcowed;
123+
atomic_t pktcow_failed;
124+
};
125+
115126
/**
116127
* struct brcmf_bus - interface structure between common and bus layer
117128
*
@@ -120,8 +131,8 @@ struct brcmf_bus_msgbuf {
120131
* @dev: device pointer of bus device.
121132
* @drvr: public driver information.
122133
* @state: operational state of the bus interface.
134+
* @stats: statistics shared between common and bus layer.
123135
* @maxctl: maximum size for rxctl request message.
124-
* @tx_realloc: number of tx packets realloced for headroom.
125136
* @chip: device identifier of the dongle chip.
126137
* @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
127138
* @wowl_supported: is wowl supported by bus driver.
@@ -137,8 +148,8 @@ struct brcmf_bus {
137148
struct device *dev;
138149
struct brcmf_pub *drvr;
139150
enum brcmf_bus_state state;
151+
struct brcmf_bus_stats stats;
140152
uint maxctl;
141-
atomic_t tx_realloc;
142153
u32 chip;
143154
u32 chiprev;
144155
bool always_use_fws_queue;

drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
199199
struct brcmf_if *ifp = netdev_priv(ndev);
200200
struct brcmf_pub *drvr = ifp->drvr;
201201
struct ethhdr *eh;
202+
int head_delta;
202203

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

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

214-
/* Make sure there's enough writable headroom*/
215-
ret = skb_cow_head(skb, drvr->hdrlen);
216-
if (ret < 0) {
217-
brcmf_err("%s: skb_cow_head failed\n",
218-
brcmf_ifname(ifp));
219-
dev_kfree_skb(skb);
220-
goto done;
215+
/* Make sure there's enough writeable headroom */
216+
if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
217+
head_delta = drvr->hdrlen - skb_headroom(skb);
218+
219+
brcmf_dbg(INFO, "%s: insufficient headroom (%d)\n",
220+
brcmf_ifname(ifp), head_delta);
221+
atomic_inc(&drvr->bus_if->stats.pktcowed);
222+
ret = pskb_expand_head(skb, ALIGN(head_delta, NET_SKB_PAD), 0,
223+
GFP_ATOMIC);
224+
if (ret < 0) {
225+
brcmf_err("%s: failed to expand headroom\n",
226+
brcmf_ifname(ifp));
227+
atomic_inc(&drvr->bus_if->stats.pktcow_failed);
228+
goto done;
229+
}
221230
}
222231

223232
/* validate length for ether packet */

drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,6 +2037,7 @@ brcmf_sdio_wait_event_wakeup(struct brcmf_sdio *bus)
20372037

20382038
static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
20392039
{
2040+
struct brcmf_bus_stats *stats;
20402041
u16 head_pad;
20412042
u8 *dat_buf;
20422043

@@ -2046,16 +2047,18 @@ static int brcmf_sdio_txpkt_hdalign(struct brcmf_sdio *bus, struct sk_buff *pkt)
20462047
head_pad = ((unsigned long)dat_buf % bus->head_align);
20472048
if (head_pad) {
20482049
if (skb_headroom(pkt) < head_pad) {
2049-
atomic_inc(&bus->sdiodev->bus_if->tx_realloc);
2050-
head_pad = 0;
2051-
if (skb_cow(pkt, head_pad))
2050+
stats = &bus->sdiodev->bus_if->stats;
2051+
atomic_inc(&stats->pktcowed);
2052+
if (skb_cow_head(pkt, head_pad)) {
2053+
atomic_inc(&stats->pktcow_failed);
20522054
return -ENOMEM;
2055+
}
20532056
}
20542057
skb_push(pkt, head_pad);
20552058
dat_buf = (u8 *)(pkt->data);
2056-
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
20572059
}
2058-
return head_pad;
2060+
memset(dat_buf, 0, head_pad + bus->tx_hdrlen);
2061+
return 0;
20592062
}
20602063

20612064
/**

0 commit comments

Comments
 (0)