diff options
author | Florian Fainelli <f.fainelli@gmail.com> | 2014-09-08 14:37:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-08 19:02:49 -0400 |
commit | b629be5c8399d7c423b92135eb43a86c924d1cbc (patch) | |
tree | 28483cec84c56b551a51d19a25d5479ea948aae5 /drivers/net/ethernet/broadcom/genet/bcmgenet.c | |
parent | fe24ba082b8483c81f546d24e40a55624295b85d (diff) |
net: bcmgenet: check harder for out of memory conditions
There is a potential case where we might be failing to refill a
control block, leaving it with both a NULL skb pointer *and* a NULL
dma_unmap_addr.
The way we process incoming packets, by first calling
dma_unmap_single(), and then only checking for a potential NULL skb can
lead to situations where do pass a NULL dma_unmap_addr() to
dma_unmap_single(), resulting in an oops.
Fix this my moving the NULL skb check earlier, since no backing skb
also means no corresponding DMA mapping for this packet.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/genet/bcmgenet.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmgenet.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3f9d4de8173c..cdef86a03862 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c | |||
@@ -1274,12 +1274,29 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, | |||
1274 | 1274 | ||
1275 | while ((rxpktprocessed < rxpkttoprocess) && | 1275 | while ((rxpktprocessed < rxpkttoprocess) && |
1276 | (rxpktprocessed < budget)) { | 1276 | (rxpktprocessed < budget)) { |
1277 | cb = &priv->rx_cbs[priv->rx_read_ptr]; | ||
1278 | skb = cb->skb; | ||
1279 | |||
1280 | rxpktprocessed++; | ||
1281 | |||
1282 | priv->rx_read_ptr++; | ||
1283 | priv->rx_read_ptr &= (priv->num_rx_bds - 1); | ||
1284 | |||
1285 | /* We do not have a backing SKB, so we do not have a | ||
1286 | * corresponding DMA mapping for this incoming packet since | ||
1287 | * bcmgenet_rx_refill always either has both skb and mapping or | ||
1288 | * none. | ||
1289 | */ | ||
1290 | if (unlikely(!skb)) { | ||
1291 | dev->stats.rx_dropped++; | ||
1292 | dev->stats.rx_errors++; | ||
1293 | goto refill; | ||
1294 | } | ||
1295 | |||
1277 | /* Unmap the packet contents such that we can use the | 1296 | /* Unmap the packet contents such that we can use the |
1278 | * RSV from the 64 bytes descriptor when enabled and save | 1297 | * RSV from the 64 bytes descriptor when enabled and save |
1279 | * a 32-bits register read | 1298 | * a 32-bits register read |
1280 | */ | 1299 | */ |
1281 | cb = &priv->rx_cbs[priv->rx_read_ptr]; | ||
1282 | skb = cb->skb; | ||
1283 | dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr), | 1300 | dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr), |
1284 | priv->rx_buf_len, DMA_FROM_DEVICE); | 1301 | priv->rx_buf_len, DMA_FROM_DEVICE); |
1285 | 1302 | ||
@@ -1307,18 +1324,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, | |||
1307 | __func__, p_index, priv->rx_c_index, | 1324 | __func__, p_index, priv->rx_c_index, |
1308 | priv->rx_read_ptr, dma_length_status); | 1325 | priv->rx_read_ptr, dma_length_status); |
1309 | 1326 | ||
1310 | rxpktprocessed++; | ||
1311 | |||
1312 | priv->rx_read_ptr++; | ||
1313 | priv->rx_read_ptr &= (priv->num_rx_bds - 1); | ||
1314 | |||
1315 | /* out of memory, just drop packets at the hardware level */ | ||
1316 | if (unlikely(!skb)) { | ||
1317 | dev->stats.rx_dropped++; | ||
1318 | dev->stats.rx_errors++; | ||
1319 | goto refill; | ||
1320 | } | ||
1321 | |||
1322 | if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { | 1327 | if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { |
1323 | netif_err(priv, rx_status, dev, | 1328 | netif_err(priv, rx_status, dev, |
1324 | "dropping fragmented packet!\n"); | 1329 | "dropping fragmented packet!\n"); |