Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=173261ed37e7a98cedfcc808eb07eeceee66e078
Commit:     173261ed37e7a98cedfcc808eb07eeceee66e078
Parent:     829185e97fba67ededd3eb025147bafcc0ca7557
Author:     Masakazu Mokuno <[EMAIL PROTECTED]>
AuthorDate: Fri Aug 31 22:22:32 2007 +0900
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Wed Oct 10 16:51:00 2007 -0700

    PS3: changed the way to handle tx skbs
    
    The PS3 virtual network device requires a vlan tag in the sending packet
    to select the destination device, ethernet port or wireless.
    As the vlan tag field is in the middle of the passed data,
    we should insert it into the packet data.
    To avoid copying much of the packet data, the driver used two tx descriptors
    for one tx skb; one descriptor was for sending a small static
    buffer which contained vlan tag and copied header (two mac addresses),
    one was for the residual data after the vlan field.
    
    This patch changes the way to insert the vlan tag.  By changing
    netdev->hard_header_len, we can make the headroom for moving mac address
    fields in the skb buffer. Then we can send one tx skb with
    one tx descriptor.  This also gives us a tx throughut gain of approx.
    20% according to netperf results.
    
    Signed-off-by: Masakazu Mokuno <[EMAIL PROTECTED]>
    CC: Geoff Levand <[EMAIL PROTECTED]>
    Signed-off-by: Jeff Garzik <[EMAIL PROTECTED]>
---
 drivers/net/ps3_gelic_net.c |  140 +++++++++++++++++++-----------------------
 1 files changed, 63 insertions(+), 77 deletions(-)

diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 92561c0..31c3092 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -351,19 +351,13 @@ static int gelic_net_alloc_rx_skbs(struct gelic_net_card 
*card)
 static void gelic_net_release_tx_descr(struct gelic_net_card *card,
                            struct gelic_net_descr *descr)
 {
-       struct sk_buff *skb;
+       struct sk_buff *skb = descr->skb;
 
+       BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)));
 
-       if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) {
-               /* 2nd descriptor */
-               skb = descr->skb;
-               dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
-                                DMA_TO_DEVICE);
-               dev_kfree_skb_any(skb);
-       } else {
-               dma_unmap_single(ctodev(card), descr->buf_addr,
-                                descr->buf_size, DMA_TO_DEVICE);
-       }
+       dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
+                        DMA_TO_DEVICE);
+       dev_kfree_skb_any(skb);
 
        descr->buf_addr = 0;
        descr->buf_size = 0;
@@ -426,7 +420,7 @@ static void gelic_net_release_tx_chain(struct 
gelic_net_card *card, int stop)
                release ++;
        }
 out:
-       if (!stop && (2 < release))
+       if (!stop && release)
                netif_wake_queue(card->netdev);
 }
 
@@ -593,13 +587,10 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
 {
        if (!card->tx_chain.head)
                return NULL;
-       /*  see if we can two consecutive free descrs */
+       /*  see if the next descriptor is free */
        if (card->tx_chain.tail != card->tx_chain.head->next &&
            gelic_net_get_descr_status(card->tx_chain.head) ==
-           GELIC_NET_DESCR_NOT_IN_USE &&
-           card->tx_chain.tail != card->tx_chain.head->next->next &&
-           gelic_net_get_descr_status(card->tx_chain.head->next) ==
-            GELIC_NET_DESCR_NOT_IN_USE )
+           GELIC_NET_DESCR_NOT_IN_USE)
                return card->tx_chain.head;
        else
                return NULL;
@@ -610,44 +601,66 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
  * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
  * @descr: descriptor structure to fill out
  * @skb: packet to consider
- * @middle: middle of frame
  *
  * fills out the command and status field of the descriptor structure,
  * depending on hardware checksum settings. This function assumes a wmb()
  * has executed before.
  */
 static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
-                                         struct sk_buff *skb, int middle)
+                                         struct sk_buff *skb)
 {
-       u32 eofr;
-
-       if (middle)
-               eofr = 0;
-       else
-               eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME;
-
        if (skb->ip_summed != CHECKSUM_PARTIAL)
-               descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+               descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS |
+                       GELIC_NET_DMAC_CMDSTAT_END_FRAME;
        else {
                /* is packet ip?
                 * if yes: tcp? udp? */
                if (skb->protocol == htons(ETH_P_IP)) {
                        if (ip_hdr(skb)->protocol == IPPROTO_TCP)
                                descr->dmac_cmd_status =
-                                       GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr;
+                                       GELIC_NET_DMAC_CMDSTAT_TCPCS |
+                                       GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+
                        else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
                                descr->dmac_cmd_status =
-                                       GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr;
+                                       GELIC_NET_DMAC_CMDSTAT_UDPCS |
+                                       GELIC_NET_DMAC_CMDSTAT_END_FRAME;
                        else    /*
                                 * the stack should checksum non-tcp and non-udp
                                 * packets on his own: NETIF_F_IP_CSUM
                                 */
                                descr->dmac_cmd_status =
-                                       GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+                                       GELIC_NET_DMAC_CMDSTAT_NOCS |
+                                       GELIC_NET_DMAC_CMDSTAT_END_FRAME;
                }
        }
 }
 
+static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+                                                unsigned short tag)
+{
+       struct vlan_ethhdr *veth;
+       static unsigned int c;
+
+       if (skb_headroom(skb) < VLAN_HLEN) {
+               struct sk_buff *sk_tmp = skb;
+               pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
+               skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
+               if (!skb)
+                       return NULL;
+               dev_kfree_skb_any(sk_tmp);
+       }
+       veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
+
+       /* Move the mac addresses to the top of buffer */
+       memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+       veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
+       veth->h_vlan_TCI = htons(tag);
+
+       return skb;
+}
+
 /**
  * gelic_net_prepare_tx_descr_v - get dma address of skb_data
  * @card: card structure
@@ -661,65 +674,35 @@ static int gelic_net_prepare_tx_descr_v(struct 
gelic_net_card *card,
                                        struct gelic_net_descr *descr,
                                        struct sk_buff *skb)
 {
-       dma_addr_t buf[2];
-       unsigned int vlan_len;
-       struct gelic_net_descr *sec_descr = descr->next;
-
-       if (skb->len < GELIC_NET_VLAN_POS)
-               return -EINVAL;
+       dma_addr_t buf;
 
-       vlan_len = GELIC_NET_VLAN_POS;
-       memcpy(&descr->vlan, skb->data, vlan_len);
        if (card->vlan_index != -1) {
-               /* internal vlan tag used */
-               descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
-               descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
-               vlan_len += VLAN_HLEN; /* added for above two lines */
-       }
-
-       /* map data area */
-       buf[0] = dma_map_single(ctodev(card), &descr->vlan,
-                            vlan_len, DMA_TO_DEVICE);
-
-       if (!buf[0]) {
-               dev_err(ctodev(card),
-                       "dma map 1 failed (%p, %i). Dropping packet\n",
-                       skb->data, vlan_len);
-               return -ENOMEM;
+               struct sk_buff *skb_tmp;
+               skb_tmp = gelic_put_vlan_tag(skb,
+                                            card->vlan_id[card->vlan_index]);
+               if (!skb_tmp)
+                       return -ENOMEM;
+               skb = skb_tmp;
        }
 
-       buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
-                            skb->len - GELIC_NET_VLAN_POS,
-                            DMA_TO_DEVICE);
+       buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
 
-       if (!buf[1]) {
+       if (!buf) {
                dev_err(ctodev(card),
                        "dma map 2 failed (%p, %i). Dropping packet\n",
-                       skb->data + GELIC_NET_VLAN_POS,
-                       skb->len - GELIC_NET_VLAN_POS);
-               dma_unmap_single(ctodev(card), buf[0], vlan_len,
-                                DMA_TO_DEVICE);
+                       skb->data, skb->len);
                return -ENOMEM;
        }
 
-       /* first descr */
-       descr->buf_addr = buf[0];
-       descr->buf_size = vlan_len;
-       descr->skb = NULL; /* not used */
+       descr->buf_addr = buf;
+       descr->buf_size = skb->len;
+       descr->skb = skb;
        descr->data_status = 0;
-       descr->next_descr_addr = descr->next->bus_addr;
-       gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
-
-       /* second descr */
-       sec_descr->buf_addr = buf[1];
-       sec_descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
-       sec_descr->skb = skb;
-       sec_descr->data_status = 0;
-       sec_descr->next_descr_addr = 0; /* terminate hw descr */
-       gelic_net_set_txdescr_cmdstat(sec_descr, skb, 0);
+       descr->next_descr_addr = 0; /* terminate hw descr */
+       gelic_net_set_txdescr_cmdstat(descr, skb);
 
        /* bump free descriptor pointer */
-       card->tx_chain.head = sec_descr->next;
+       card->tx_chain.head = descr->next;
        return 0;
 }
 
@@ -1425,8 +1408,11 @@ static int gelic_net_setup_netdev(struct gelic_net_card 
*card)
                        dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1);
                }
        }
-       if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1])
+
+       if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) {
                card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
+               netdev->hard_header_len += VLAN_HLEN;
+       }
 
        status = register_netdev(netdev);
        if (status) {
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to