aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorManfred Rudigier <Manfred.Rudigier@omicron.at>2012-01-09 18:26:51 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-12 18:26:01 -0500
commit9c4886e5e63bbecea0b560829a96f37e8d9ddd7c (patch)
tree1cc0c8626a929ecf04f8f84f9b289a20e95f32b5 /drivers
parentdb83d136d7f7534857cd9c6e588adc08a428b190 (diff)
gianfar: Fix invalid TX frames returned on error queue when time stamping
When TX time stamping for PTP messages is enabled on a socket, a time stamp is returned on the socket error queue to the user space application after the frame was transmitted. The transmitted frame is also returned on the error queue so that an application knows to which frame the time stamp belongs. In the current implementation the TxFCB is immediately followed by the frame. Since the eTSEC inserts the TX time stamp 8 bytes after the TxFCB, parts of the frame have been overwritten and an invalid frame was returned on the socket error queue. This patch fixes the described problem by adding additional 16 padding bytes between the TxFCB and the frame for all messages sent from a time stamping enabled socket (other sockets are not affected). Signed-off-by: Manfred Rudigier <manfred.rudigier@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c30
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h3
2 files changed, 23 insertions, 10 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2b3c1299212..39d160d353a 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1984,7 +1984,8 @@ static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
1984 return fcb; 1984 return fcb;
1985} 1985}
1986 1986
1987static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb) 1987static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
1988 int fcb_length)
1988{ 1989{
1989 u8 flags = 0; 1990 u8 flags = 0;
1990 1991
@@ -2006,7 +2007,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
2006 * frame (skb->data) and the start of the IP hdr. 2007 * frame (skb->data) and the start of the IP hdr.
2007 * l4os is the distance between the start of the 2008 * l4os is the distance between the start of the
2008 * l3 hdr and the l4 hdr */ 2009 * l3 hdr and the l4 hdr */
2009 fcb->l3os = (u16)(skb_network_offset(skb) - GMAC_FCB_LEN); 2010 fcb->l3os = (u16)(skb_network_offset(skb) - fcb_length);
2010 fcb->l4os = skb_network_header_len(skb); 2011 fcb->l4os = skb_network_header_len(skb);
2011 2012
2012 fcb->flags = flags; 2013 fcb->flags = flags;
@@ -2046,7 +2047,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2046 int i, rq = 0, do_tstamp = 0; 2047 int i, rq = 0, do_tstamp = 0;
2047 u32 bufaddr; 2048 u32 bufaddr;
2048 unsigned long flags; 2049 unsigned long flags;
2049 unsigned int nr_frags, nr_txbds, length; 2050 unsigned int nr_frags, nr_txbds, length, fcb_length = GMAC_FCB_LEN;
2050 2051
2051 /* 2052 /*
2052 * TOE=1 frames larger than 2500 bytes may see excess delays 2053 * TOE=1 frames larger than 2500 bytes may see excess delays
@@ -2070,17 +2071,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2070 2071
2071 /* check if time stamp should be generated */ 2072 /* check if time stamp should be generated */
2072 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && 2073 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
2073 priv->hwts_tx_en)) 2074 priv->hwts_tx_en)) {
2074 do_tstamp = 1; 2075 do_tstamp = 1;
2076 fcb_length = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
2077 }
2075 2078
2076 /* make space for additional header when fcb is needed */ 2079 /* make space for additional header when fcb is needed */
2077 if (((skb->ip_summed == CHECKSUM_PARTIAL) || 2080 if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
2078 vlan_tx_tag_present(skb) || 2081 vlan_tx_tag_present(skb) ||
2079 unlikely(do_tstamp)) && 2082 unlikely(do_tstamp)) &&
2080 (skb_headroom(skb) < GMAC_FCB_LEN)) { 2083 (skb_headroom(skb) < fcb_length)) {
2081 struct sk_buff *skb_new; 2084 struct sk_buff *skb_new;
2082 2085
2083 skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN); 2086 skb_new = skb_realloc_headroom(skb, fcb_length);
2084 if (!skb_new) { 2087 if (!skb_new) {
2085 dev->stats.tx_errors++; 2088 dev->stats.tx_errors++;
2086 kfree_skb(skb); 2089 kfree_skb(skb);
@@ -2158,6 +2161,12 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2158 lstatus = txbdp_start->lstatus; 2161 lstatus = txbdp_start->lstatus;
2159 } 2162 }
2160 2163
2164 /* Add TxPAL between FCB and frame if required */
2165 if (unlikely(do_tstamp)) {
2166 skb_push(skb, GMAC_TXPAL_LEN);
2167 memset(skb->data, 0, GMAC_TXPAL_LEN);
2168 }
2169
2161 /* Set up checksumming */ 2170 /* Set up checksumming */
2162 if (CHECKSUM_PARTIAL == skb->ip_summed) { 2171 if (CHECKSUM_PARTIAL == skb->ip_summed) {
2163 fcb = gfar_add_fcb(skb); 2172 fcb = gfar_add_fcb(skb);
@@ -2168,7 +2177,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2168 skb_checksum_help(skb); 2177 skb_checksum_help(skb);
2169 } else { 2178 } else {
2170 lstatus |= BD_LFLAG(TXBD_TOE); 2179 lstatus |= BD_LFLAG(TXBD_TOE);
2171 gfar_tx_checksum(skb, fcb); 2180 gfar_tx_checksum(skb, fcb, fcb_length);
2172 } 2181 }
2173 } 2182 }
2174 2183
@@ -2200,9 +2209,9 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
2200 * the full frame length. 2209 * the full frame length.
2201 */ 2210 */
2202 if (unlikely(do_tstamp)) { 2211 if (unlikely(do_tstamp)) {
2203 txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN; 2212 txbdp_tstamp->bufPtr = txbdp_start->bufPtr + fcb_length;
2204 txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) | 2213 txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) |
2205 (skb_headlen(skb) - GMAC_FCB_LEN); 2214 (skb_headlen(skb) - fcb_length);
2206 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN; 2215 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
2207 } else { 2216 } else {
2208 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); 2217 lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
@@ -2494,7 +2503,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
2494 2503
2495 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { 2504 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
2496 next = next_txbd(bdp, base, tx_ring_size); 2505 next = next_txbd(bdp, base, tx_ring_size);
2497 buflen = next->length + GMAC_FCB_LEN; 2506 buflen = next->length + GMAC_FCB_LEN + GMAC_TXPAL_LEN;
2498 } else 2507 } else
2499 buflen = bdp->length; 2508 buflen = bdp->length;
2500 2509
@@ -2506,6 +2515,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
2506 u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7); 2515 u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
2507 memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 2516 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
2508 shhwtstamps.hwtstamp = ns_to_ktime(*ns); 2517 shhwtstamps.hwtstamp = ns_to_ktime(*ns);
2518 skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
2509 skb_tstamp_tx(skb, &shhwtstamps); 2519 skb_tstamp_tx(skb, &shhwtstamps);
2510 bdp->lstatus &= BD_LFLAG(TXBD_WRAP); 2520 bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
2511 bdp = next; 2521 bdp = next;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index fe7ac3a8319..40c33a7554c 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -63,6 +63,9 @@ struct ethtool_rx_list {
63/* Length for FCB */ 63/* Length for FCB */
64#define GMAC_FCB_LEN 8 64#define GMAC_FCB_LEN 8
65 65
66/* Length for TxPAL */
67#define GMAC_TXPAL_LEN 16
68
66/* Default padding amount */ 69/* Default padding amount */
67#define DEFAULT_PADDING 2 70#define DEFAULT_PADDING 2
68 71