diff options
Diffstat (limited to 'drivers/net/sky2.c')
-rw-r--r-- | drivers/net/sky2.c | 95 |
1 files changed, 47 insertions, 48 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index b908596bd89a..64af764d0087 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -769,9 +769,16 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod; sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE); + le->ctrl = 0; return le; } +static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2, + struct sky2_tx_le *le) +{ + return sky2->tx_ring + (le - sky2->tx_le); +} + /* Update chip's next pointer */ static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) { @@ -786,6 +793,7 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2) { struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put; sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE); + le->ctrl = 0; return le; } @@ -805,7 +813,6 @@ static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map) if (sky2->rx_addr64 != hi) { le = sky2_next_rx(sky2); le->addr = cpu_to_le32(hi); - le->ctrl = 0; le->opcode = OP_ADDR64 | HW_OWNER; sky2->rx_addr64 = high32(map + len); } @@ -813,7 +820,6 @@ static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map) le = sky2_next_rx(sky2); le->addr = cpu_to_le32((u32) map); le->length = cpu_to_le16(len); - le->ctrl = 0; le->opcode = OP_PACKET | HW_OWNER; } @@ -877,7 +883,7 @@ static void sky2_rx_clean(struct sky2_port *sky2) memset(sky2->rx_le, 0, RX_LE_BYTES); for (i = 0; i < sky2->rx_pending; i++) { - struct ring_info *re = sky2->rx_ring + i; + struct rx_ring_info *re = sky2->rx_ring + i; if (re->skb) { pci_unmap_single(sky2->hw->pdev, @@ -1008,7 +1014,7 @@ static int sky2_rx_start(struct sky2_port *sky2) rx_set_checksum(sky2); for (i = 0; i < sky2->rx_pending; i++) { - struct ring_info *re = sky2->rx_ring + i; + struct rx_ring_info *re = sky2->rx_ring + i; re->skb = sky2_alloc_skb(sky2->netdev, sky2->rx_bufsize, GFP_KERNEL); @@ -1094,7 +1100,7 @@ static int sky2_up(struct net_device *dev) goto err_out; memset(sky2->rx_le, 0, RX_LE_BYTES); - sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct ring_info), + sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info), GFP_KERNEL); if (!sky2->rx_ring) goto err_out; @@ -1241,13 +1247,10 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) mapping = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE); addr64 = high32(mapping); - re = sky2->tx_ring + sky2->tx_prod; - /* Send high bits if changed or crosses boundary */ if (addr64 != sky2->tx_addr64 || high32(mapping + len) != sky2->tx_addr64) { le = get_tx_le(sky2); le->addr = cpu_to_le32(addr64); - le->ctrl = 0; le->opcode = OP_ADDR64 | HW_OWNER; sky2->tx_addr64 = high32(mapping + len); } @@ -1263,7 +1266,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le = get_tx_le(sky2); le->addr = cpu_to_le32(mss); le->opcode = OP_LRGLEN | HW_OWNER; - le->ctrl = 0; sky2->tx_last_mss = mss; } } @@ -1276,7 +1278,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le = get_tx_le(sky2); le->addr = 0; le->opcode = OP_VLAN|HW_OWNER; - le->ctrl = 0; } else le->opcode |= OP_VLAN; le->length = cpu_to_be16(vlan_tx_tag_get(skb)); @@ -1313,13 +1314,13 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->ctrl = ctrl; le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER); - /* Record the transmit mapping info */ + re = tx_le_re(sky2, le); re->skb = skb; pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, len); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - struct tx_ring_info *fre; + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); @@ -1338,12 +1339,12 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) le->ctrl = ctrl; le->opcode = OP_BUFFER | HW_OWNER; - fre = sky2->tx_ring - + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE); - pci_unmap_addr_set(fre, mapaddr, mapping); + re = tx_le_re(sky2, le); + re->skb = skb; + pci_unmap_addr_set(re, mapaddr, mapping); + pci_unmap_len_set(re, maplen, frag->size); } - re->idx = sky2->tx_prod; le->ctrl |= EOP; if (tx_avail(sky2) <= MAX_SKB_TX_LE) @@ -1361,49 +1362,47 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) * Free ring elements from starting at tx_cons until "done" * * NB: the hardware will tell us about partial completion of multi-part - * buffers; these are deferred until completion. + * buffers so make sure not to free skb to early. */ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) { struct net_device *dev = sky2->netdev; struct pci_dev *pdev = sky2->hw->pdev; - u16 nxt, put; - unsigned i; + unsigned idx; BUG_ON(done >= TX_RING_SIZE); - if (unlikely(netif_msg_tx_done(sky2))) - printk(KERN_DEBUG "%s: tx done, up to %u\n", - dev->name, done); - - for (put = sky2->tx_cons; put != done; put = nxt) { - struct tx_ring_info *re = sky2->tx_ring + put; - struct sk_buff *skb = re->skb; - - nxt = re->idx; - BUG_ON(nxt >= TX_RING_SIZE); - prefetch(sky2->tx_ring + nxt); - - /* Check for partial status */ - if (tx_dist(put, done) < tx_dist(put, nxt)) + for (idx = sky2->tx_cons; idx != done; + idx = RING_NEXT(idx, TX_RING_SIZE)) { + struct sky2_tx_le *le = sky2->tx_le + idx; + struct tx_ring_info *re = sky2->tx_ring + idx; + + switch(le->opcode & ~HW_OWNER) { + case OP_LARGESEND: + case OP_PACKET: + pci_unmap_single(pdev, + pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), + PCI_DMA_TODEVICE); break; - - skb = re->skb; - pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr), - skb_headlen(skb), PCI_DMA_TODEVICE); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - struct tx_ring_info *fre; - fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE); - pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr), - skb_shinfo(skb)->frags[i].size, + case OP_BUFFER: + pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr), + pci_unmap_len(re, maplen), PCI_DMA_TODEVICE); + break; + } + + if (le->ctrl & EOP) { + if (unlikely(netif_msg_tx_done(sky2))) + printk(KERN_DEBUG "%s: tx done %u\n", + dev->name, idx); + dev_kfree_skb(re->skb); } - dev_kfree_skb(skb); + le->opcode = 0; /* paranoia */ } - sky2->tx_cons = put; + sky2->tx_cons = idx; if (tx_avail(sky2) > MAX_SKB_TX_LE + 4) netif_wake_queue(dev); } @@ -1843,7 +1842,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, u16 length, u32 status) { struct sky2_port *sky2 = netdev_priv(dev); - struct ring_info *re = sky2->rx_ring + sky2->rx_next; + struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; if (unlikely(netif_msg_rx_status(sky2))) @@ -1889,7 +1888,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, prefetch(skb->data); re->mapaddr = pci_map_single(sky2->hw->pdev, nskb->data, - sky2->rx_bufsize, PCI_DMA_FROMDEVICE); + sky2->rx_bufsize, PCI_DMA_FROMDEVICE); } skb_put(skb, length); |