diff options
author | Nick Nunley <nicholasx.d.nunley@intel.com> | 2010-03-26 11:36:47 (GMT) |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-31 06:42:27 (GMT) |
commit | 757b77e2b208490868cf21fd22d796eb9bd199c5 (patch) | |
tree | 628dccdbed780dc38d9843bb30d5c5920b830258 /drivers/net | |
parent | 3365a2934cce29fa9196bc4fd7086f62e799ee84 (diff) | |
download | linux-fsl-qoriq-757b77e2b208490868cf21fd22d796eb9bd199c5.tar.xz |
igb: add per-packet timestamping
This patch adds support for per-packet timestamping for the
82580 adapter. The rx timestamp code is also pulled out of the
inlined rx hotpath and instead moved to a seperate function.
This version adds a comment explaining the per-packet timestamping
code added to igb_hwtstamp_ioctl().
Signed-off-by: Nicholas Nunley <nicholasx.d.nunley@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/igb/e1000_82575.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 45 |
3 files changed, 41 insertions, 8 deletions
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index c1cad8a..cbd1e12 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h @@ -53,6 +53,7 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw); #define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 #define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 #define E1000_SRRCTL_DROP_EN 0x80000000 +#define E1000_SRRCTL_TIMESTAMP 0x40000000 #define E1000_MRQC_ENABLE_RSS_4Q 0x00000002 #define E1000_MRQC_ENABLE_VMDQ 0x00000003 @@ -109,6 +110,7 @@ union e1000_adv_rx_desc { #define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0 #define E1000_RXDADV_HDRBUFLEN_SHIFT 5 #define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */ +#define E1000_RXDADV_STAT_TSIP 0x08000 /* timestamp in packet */ /* Transmit Descriptor - Advanced */ union e1000_adv_tx_desc { diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index a177570..4f69b6d 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -107,6 +107,7 @@ struct vf_data_storage { #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 /* Supported Rx Buffer Sizes */ +#define IGB_RXBUFFER_64 64 /* Used for packet split */ #define IGB_RXBUFFER_128 128 /* Used for packet split */ #define IGB_RXBUFFER_1024 1024 #define IGB_RXBUFFER_2048 2048 @@ -324,6 +325,7 @@ struct igb_adapter { #define IGB_82576_TSYNC_SHIFT 19 #define IGB_82580_TSYNC_SHIFT 24 +#define IGB_TS_HDR_LEN 16 enum e1000_state_t { __IGB_TESTING, __IGB_RESETTING, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 7d755dd..ea87570 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2576,6 +2576,8 @@ void igb_configure_rx_ring(struct igb_adapter *adapter, E1000_SRRCTL_BSIZEPKT_SHIFT; srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF; } + if (hw->mac.type == e1000_82580) + srrctl |= E1000_SRRCTL_TIMESTAMP; /* Only set Drop Enable if we are supporting multiple queues */ if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1) srrctl |= E1000_SRRCTL_DROP_EN; @@ -3910,6 +3912,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) * i.e. RXBUFFER_2048 --> size-4096 slab */ + if (adapter->hw.mac.type == e1000_82580) + max_frame += IGB_TS_HDR_LEN; + if (max_frame <= IGB_RXBUFFER_1024) rx_buffer_len = IGB_RXBUFFER_1024; else if (max_frame <= MAXIMUM_ETHERNET_VLAN_SIZE) @@ -3917,6 +3922,14 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) else rx_buffer_len = IGB_RXBUFFER_128; + if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN + IGB_TS_HDR_LEN) || + (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN)) + rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN; + + if ((adapter->hw.mac.type == e1000_82580) && + (rx_buffer_len == IGB_RXBUFFER_128)) + rx_buffer_len += IGB_RXBUFFER_64; + if (netif_running(netdev)) igb_down(adapter); @@ -5133,7 +5146,7 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring, dev_dbg(&ring->pdev->dev, "cksum success: bits %08X\n", status_err); } -static inline void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr, +static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr, struct sk_buff *skb) { struct igb_adapter *adapter = q_vector->adapter; @@ -5151,13 +5164,18 @@ static inline void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr, * If nothing went wrong, then it should have a skb_shared_tx that we * can turn into a skb_shared_hwtstamps. */ - if (likely(!(staterr & E1000_RXDADV_STAT_TS))) - return; - if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) - return; + if (staterr & E1000_RXDADV_STAT_TSIP) { + u32 *stamp = (u32 *)skb->data; + regval = le32_to_cpu(*(stamp + 2)); + regval |= (u64)le32_to_cpu(*(stamp + 3)) << 32; + skb_pull(skb, IGB_TS_HDR_LEN); + } else { + if(!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) + return; - regval = rd32(E1000_RXSTMPL); - regval |= (u64)rd32(E1000_RXSTMPH) << 32; + regval = rd32(E1000_RXSTMPL); + regval |= (u64)rd32(E1000_RXSTMPH) << 32; + } igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); } @@ -5265,7 +5283,8 @@ send_up: goto next_desc; } - igb_rx_hwtstamp(q_vector, staterr, skb); + if (staterr & (E1000_RXDADV_STAT_TSIP | E1000_RXDADV_STAT_TS)) + igb_rx_hwtstamp(q_vector, staterr, skb); total_bytes += skb->len; total_packets++; @@ -5545,6 +5564,16 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev, return 0; } + /* + * Per-packet timestamping only works if all packets are + * timestamped, so enable timestamping in all packets as + * long as one rx filter was configured. + */ + if ((hw->mac.type == e1000_82580) && tsync_rx_ctl) { + tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; + tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; + } + /* enable/disable TX */ regval = rd32(E1000_TSYNCTXCTL); regval &= ~E1000_TSYNCTXCTL_ENABLED; |