diff options
| -rw-r--r-- | drivers/net/ethernet/broadcom/bgmac.c | 46 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/bgmac.h | 6 |
2 files changed, 23 insertions, 29 deletions
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index fa8f9e147c34..b9e02e484d72 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c | |||
| @@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, | |||
| 142 | { | 142 | { |
| 143 | struct device *dma_dev = bgmac->core->dma_dev; | 143 | struct device *dma_dev = bgmac->core->dma_dev; |
| 144 | struct net_device *net_dev = bgmac->net_dev; | 144 | struct net_device *net_dev = bgmac->net_dev; |
| 145 | struct bgmac_slot_info *slot = &ring->slots[ring->end]; | 145 | int index = ring->end % BGMAC_TX_RING_SLOTS; |
| 146 | int free_slots; | 146 | struct bgmac_slot_info *slot = &ring->slots[index]; |
| 147 | int nr_frags; | 147 | int nr_frags; |
| 148 | u32 flags; | 148 | u32 flags; |
| 149 | int index = ring->end; | ||
| 150 | int i; | 149 | int i; |
| 151 | 150 | ||
| 152 | if (skb->len > BGMAC_DESC_CTL1_LEN) { | 151 | if (skb->len > BGMAC_DESC_CTL1_LEN) { |
| @@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, | |||
| 159 | 158 | ||
| 160 | nr_frags = skb_shinfo(skb)->nr_frags; | 159 | nr_frags = skb_shinfo(skb)->nr_frags; |
| 161 | 160 | ||
| 162 | if (ring->start <= ring->end) | 161 | /* ring->end - ring->start will return the number of valid slots, |
| 163 | free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS; | 162 | * even when ring->end overflows |
| 164 | else | 163 | */ |
| 165 | free_slots = ring->start - ring->end; | 164 | if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) { |
| 166 | |||
| 167 | if (free_slots <= nr_frags + 1) { | ||
| 168 | bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); | 165 | bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n"); |
| 169 | netif_stop_queue(net_dev); | 166 | netif_stop_queue(net_dev); |
| 170 | return NETDEV_TX_BUSY; | 167 | return NETDEV_TX_BUSY; |
| @@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, | |||
| 200 | } | 197 | } |
| 201 | 198 | ||
| 202 | slot->skb = skb; | 199 | slot->skb = skb; |
| 203 | 200 | ring->end += nr_frags + 1; | |
| 204 | netdev_sent_queue(net_dev, skb->len); | 201 | netdev_sent_queue(net_dev, skb->len); |
| 205 | 202 | ||
| 206 | wmb(); | 203 | wmb(); |
| @@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac, | |||
| 208 | /* Increase ring->end to point empty slot. We tell hardware the first | 205 | /* Increase ring->end to point empty slot. We tell hardware the first |
| 209 | * slot it should *not* read. | 206 | * slot it should *not* read. |
| 210 | */ | 207 | */ |
| 211 | ring->end = (index + 1) % BGMAC_TX_RING_SLOTS; | ||
| 212 | bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, | 208 | bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX, |
| 213 | ring->index_base + | 209 | ring->index_base + |
| 214 | ring->end * sizeof(struct bgmac_dma_desc)); | 210 | (ring->end % BGMAC_TX_RING_SLOTS) * |
| 211 | sizeof(struct bgmac_dma_desc)); | ||
| 215 | 212 | ||
| 216 | free_slots -= nr_frags + 1; | 213 | if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8) |
| 217 | if (free_slots < 8) | ||
| 218 | netif_stop_queue(net_dev); | 214 | netif_stop_queue(net_dev); |
| 219 | 215 | ||
| 220 | return NETDEV_TX_OK; | 216 | return NETDEV_TX_OK; |
| @@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring) | |||
| 256 | empty_slot &= BGMAC_DMA_TX_STATDPTR; | 252 | empty_slot &= BGMAC_DMA_TX_STATDPTR; |
| 257 | empty_slot /= sizeof(struct bgmac_dma_desc); | 253 | empty_slot /= sizeof(struct bgmac_dma_desc); |
| 258 | 254 | ||
| 259 | while (ring->start != empty_slot) { | 255 | while (ring->start != ring->end) { |
| 260 | struct bgmac_slot_info *slot = &ring->slots[ring->start]; | 256 | int slot_idx = ring->start % BGMAC_TX_RING_SLOTS; |
| 261 | u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1); | 257 | struct bgmac_slot_info *slot = &ring->slots[slot_idx]; |
| 262 | int len = ctl1 & BGMAC_DESC_CTL1_LEN; | 258 | u32 ctl1; |
| 259 | int len; | ||
| 263 | 260 | ||
| 264 | if (!slot->dma_addr) { | 261 | if (slot_idx == empty_slot) |
| 265 | bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n", | 262 | break; |
| 266 | ring->start, ring->end); | ||
| 267 | goto next; | ||
| 268 | } | ||
| 269 | 263 | ||
| 264 | ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1); | ||
| 265 | len = ctl1 & BGMAC_DESC_CTL1_LEN; | ||
| 270 | if (ctl1 & BGMAC_DESC_CTL0_SOF) | 266 | if (ctl1 & BGMAC_DESC_CTL0_SOF) |
| 271 | /* Unmap no longer used buffer */ | 267 | /* Unmap no longer used buffer */ |
| 272 | dma_unmap_single(dma_dev, slot->dma_addr, len, | 268 | dma_unmap_single(dma_dev, slot->dma_addr, len, |
| @@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring) | |||
| 284 | slot->skb = NULL; | 280 | slot->skb = NULL; |
| 285 | } | 281 | } |
| 286 | 282 | ||
| 287 | next: | ||
| 288 | slot->dma_addr = 0; | 283 | slot->dma_addr = 0; |
| 289 | if (++ring->start >= BGMAC_TX_RING_SLOTS) | 284 | ring->start++; |
| 290 | ring->start = 0; | ||
| 291 | freed = true; | 285 | freed = true; |
| 292 | } | 286 | } |
| 293 | 287 | ||
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h index 3ad965fe7fcc..5a198d56f3e7 100644 --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h | |||
| @@ -414,10 +414,10 @@ enum bgmac_dma_ring_type { | |||
| 414 | * empty. | 414 | * empty. |
| 415 | */ | 415 | */ |
| 416 | struct bgmac_dma_ring { | 416 | struct bgmac_dma_ring { |
| 417 | u16 num_slots; | 417 | u32 start; |
| 418 | u16 start; | 418 | u32 end; |
| 419 | u16 end; | ||
| 420 | 419 | ||
| 420 | u16 num_slots; | ||
| 421 | u16 mmio_base; | 421 | u16 mmio_base; |
| 422 | struct bgmac_dma_desc *cpu_base; | 422 | struct bgmac_dma_desc *cpu_base; |
| 423 | dma_addr_t dma_base; | 423 | dma_addr_t dma_base; |
