From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by dpdk.org (Postfix) with ESMTP id 70F913784 for ; Thu, 2 Jul 2015 17:17:09 +0200 (CEST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 02 Jul 2015 08:16:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,393,1432623600"; d="scan'208";a="757292957" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga002.jf.intel.com with ESMTP; 02 Jul 2015 08:16:52 -0700 Received: from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com [10.237.217.46]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id t62FGpJn018930; Thu, 2 Jul 2015 16:16:51 +0100 Received: from sivswdev02.ir.intel.com (localhost [127.0.0.1]) by sivswdev02.ir.intel.com with ESMTP id t62FGpnI007095; Thu, 2 Jul 2015 16:16:51 +0100 Received: (from jmcnam2x@localhost) by sivswdev02.ir.intel.com with id t62FGpw8007091; Thu, 2 Jul 2015 16:16:51 +0100 From: John McNamara To: dev@dpdk.org Date: Thu, 2 Jul 2015 16:16:31 +0100 Message-Id: <1435850194-7024-5-git-send-email-john.mcnamara@intel.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1435850194-7024-1-git-send-email-john.mcnamara@intel.com> References: <1435585344-26652-1-git-send-email-john.mcnamara@intel.com> <1435850194-7024-1-git-send-email-john.mcnamara@intel.com> Subject: [dpdk-dev] [PATCH v3 4/7] i40e: add support for ieee1588 timestamping X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 02 Jul 2015 15:17:10 -0000 Add ixgbe support for new ethdev APIs to enable and read IEEE1588/ 802.1AS PTP timestamps. Signed-off-by: John McNamara --- drivers/net/i40e/i40e_ethdev.c | 143 +++++++++++++++++++++++++++++++++++++++++ drivers/net/i40e/i40e_rxtx.c | 39 ++++++++++- 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c index 2ada502..a6875d0 100644 --- a/drivers/net/i40e/i40e_ethdev.c +++ b/drivers/net/i40e/i40e_ethdev.c @@ -55,6 +55,7 @@ #include "base/i40e_prototype.h" #include "base/i40e_adminq_cmd.h" #include "base/i40e_type.h" +#include "base/i40e_register.h" #include "i40e_ethdev.h" #include "i40e_rxtx.h" #include "i40e_pf.h" @@ -106,6 +107,12 @@ (1UL << RTE_ETH_FLOW_NONFRAG_IPV6_OTHER) | \ (1UL << RTE_ETH_FLOW_L2_PAYLOAD)) +#define I40E_PTP_40GB_INCVAL 0x0199999999ULL +#define I40E_PTP_10GB_INCVAL 0x0333333333ULL +#define I40E_PTP_1GB_INCVAL 0x2000000000ULL +#define I40E_PRTTSYN_TSYNENA 0x80000000 +#define I40E_PRTTSYN_TSYNTYPE 0x0e000000 + static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev); static int i40e_dev_configure(struct rte_eth_dev *dev); static int i40e_dev_start(struct rte_eth_dev *dev); @@ -212,6 +219,14 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev, static void i40e_configure_registers(struct i40e_hw *hw); static void i40e_hw_init(struct i40e_hw *hw); +static int i40e_timesync_enable(struct rte_eth_dev *dev); +static int i40e_timesync_disable(struct rte_eth_dev *dev); +static int i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp, + uint32_t flags); +static int i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp); + static const struct rte_pci_id pci_id_i40e_map[] = { #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)}, #include "rte_pci_dev_ids.h" @@ -262,6 +277,10 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { .udp_tunnel_add = i40e_dev_udp_tunnel_add, .udp_tunnel_del = i40e_dev_udp_tunnel_del, .filter_ctrl = i40e_dev_filter_ctrl, + .timesync_enable = i40e_timesync_enable, + .timesync_disable = i40e_timesync_disable, + .timesync_read_rx_timestamp = i40e_timesync_read_rx_timestamp, + .timesync_read_tx_timestamp = i40e_timesync_read_tx_timestamp, }; static struct eth_driver rte_i40e_pmd = { @@ -5697,3 +5716,127 @@ i40e_configure_registers(struct i40e_hw *hw) "0x%"PRIx32, reg_table[i].val, reg_table[i].addr); } } + +static int +i40e_timesync_enable(struct rte_eth_dev *dev) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_eth_link *link = &dev->data->dev_link; + uint32_t tsync_ctl_l; + uint32_t tsync_ctl_h; + uint32_t tsync_inc_l; + uint32_t tsync_inc_h; + + switch (link->link_speed) { + case ETH_LINK_SPEED_40G: + tsync_inc_l = I40E_PTP_40GB_INCVAL & 0xFFFFFFFF; + tsync_inc_h = I40E_PTP_40GB_INCVAL >> 32; + break; + case ETH_LINK_SPEED_10G: + tsync_inc_l = I40E_PTP_10GB_INCVAL & 0xFFFFFFFF; + tsync_inc_h = I40E_PTP_10GB_INCVAL >> 32; + break; + case ETH_LINK_SPEED_1000: + tsync_inc_l = I40E_PTP_1GB_INCVAL & 0xFFFFFFFF; + tsync_inc_h = I40E_PTP_1GB_INCVAL >> 32; + break; + default: + tsync_inc_l = 0x0; + tsync_inc_h = 0x0; + } + + /* Clear timesync registers. */ + I40E_READ_REG(hw, I40E_PRTTSYN_STAT_0); + I40E_READ_REG(hw, I40E_PRTTSYN_TXTIME_H); + I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_L(0)); + I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_L(1)); + I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_L(2)); + I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_L(3)); + I40E_READ_REG(hw, I40E_PRTTSYN_TXTIME_H); + + /* Set the timesync increment value. */ + I40E_WRITE_REG(hw, I40E_PRTTSYN_INC_L, tsync_inc_l); + I40E_WRITE_REG(hw, I40E_PRTTSYN_INC_H, tsync_inc_h); + + /* Enable timestamping of PTP packets. */ + tsync_ctl_l = I40E_READ_REG(hw, I40E_PRTTSYN_CTL0); + tsync_ctl_l |= I40E_PRTTSYN_TSYNENA; + + tsync_ctl_h = I40E_READ_REG(hw, I40E_PRTTSYN_CTL1); + tsync_ctl_h |= I40E_PRTTSYN_TSYNENA; + tsync_ctl_h |= I40E_PRTTSYN_TSYNTYPE; + + I40E_WRITE_REG(hw, I40E_PRTTSYN_CTL0, tsync_ctl_l); + I40E_WRITE_REG(hw, I40E_PRTTSYN_CTL1, tsync_ctl_h); + + return 0; +} + +static int +i40e_timesync_disable(struct rte_eth_dev *dev) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t tsync_ctl_l; + uint32_t tsync_ctl_h; + + /* Disable timestamping of transmitted PTP packets. */ + tsync_ctl_l = I40E_READ_REG(hw, I40E_PRTTSYN_CTL0); + tsync_ctl_l &= ~I40E_PRTTSYN_TSYNENA; + + tsync_ctl_h = I40E_READ_REG(hw, I40E_PRTTSYN_CTL1); + tsync_ctl_h &= ~I40E_PRTTSYN_TSYNENA; + + I40E_WRITE_REG(hw, I40E_PRTTSYN_CTL0, tsync_ctl_l); + I40E_WRITE_REG(hw, I40E_PRTTSYN_CTL1, tsync_ctl_h); + + /* Set the timesync increment value. */ + I40E_WRITE_REG(hw, I40E_PRTTSYN_INC_L, 0x0); + I40E_WRITE_REG(hw, I40E_PRTTSYN_INC_H, 0x0); + + return 0; +} + +static int +i40e_timesync_read_rx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp, uint32_t flags) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t sync_status; + uint32_t rx_stmpl; + uint32_t rx_stmph; + uint32_t index = flags & 0x03; + + sync_status = I40E_READ_REG(hw, I40E_PRTTSYN_STAT_1); + if ((sync_status & (1 << index)) == 0) + return -EINVAL; + + rx_stmpl = I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_L(index)); + rx_stmph = I40E_READ_REG(hw, I40E_PRTTSYN_RXTIME_H(index)); + + timestamp->tv_sec = (uint64_t)(((uint64_t)rx_stmph << 32) | rx_stmpl); + timestamp->tv_nsec = 0; + + return 0; +} + +static int +i40e_timesync_read_tx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp) +{ + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t sync_status; + uint32_t tx_stmpl; + uint32_t tx_stmph; + + sync_status = I40E_READ_REG(hw, I40E_PRTTSYN_STAT_0); + if ((sync_status & I40E_PRTTSYN_STAT_0_TXTIME_MASK) == 0) + return -EINVAL; + + tx_stmpl = I40E_READ_REG(hw, I40E_PRTTSYN_TXTIME_L); + tx_stmph = I40E_READ_REG(hw, I40E_PRTTSYN_TXTIME_H); + + timestamp->tv_sec = (uint64_t)(((uint64_t)tx_stmph << 32) | tx_stmpl); + timestamp->tv_nsec = 0; + + return 0; +} diff --git a/drivers/net/i40e/i40e_rxtx.c b/drivers/net/i40e/i40e_rxtx.c index 2de0ac4..3e9aace 100644 --- a/drivers/net/i40e/i40e_rxtx.c +++ b/drivers/net/i40e/i40e_rxtx.c @@ -159,7 +159,7 @@ i40e_rxd_ptype_to_pkt_flags(uint64_t qword) static const uint64_t ip_ptype_map[I40E_MAX_PKT_TYPE] = { 0, /* PTYPE 0 */ 0, /* PTYPE 1 */ - 0, /* PTYPE 2 */ + PKT_RX_IEEE1588_PTP, /* PTYPE 2 */ 0, /* PTYPE 3 */ 0, /* PTYPE 4 */ 0, /* PTYPE 5 */ @@ -719,6 +719,17 @@ i40e_rx_scan_hw_ring(struct i40e_rx_queue *rxq) if (pkt_flags & PKT_RX_FDIR) pkt_flags |= i40e_rxd_build_fdir(&rxdp[j], mb); +#ifdef RTE_LIBRTE_IEEE1588 + uint16_t tsyn = (qword1 + & (I40E_RXD_QW1_STATUS_TSYNVALID_MASK + | I40E_RXD_QW1_STATUS_TSYNINDX_MASK)) + >> I40E_RX_DESC_STATUS_TSYNINDX_SHIFT; + + if (tsyn & 0x04) + pkt_flags |= PKT_RX_IEEE1588_TMST; + + mb->udata64 = tsyn & 0x03; +#endif mb->ol_flags = pkt_flags; } @@ -901,6 +912,7 @@ i40e_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len); rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; + /* Check the DD bit first */ if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) break; @@ -960,6 +972,16 @@ i40e_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) if (pkt_flags & PKT_RX_FDIR) pkt_flags |= i40e_rxd_build_fdir(&rxd, rxm); +#ifdef RTE_LIBRTE_IEEE1588 + uint16_t tsyn = (qword1 & (I40E_RXD_QW1_STATUS_TSYNVALID_MASK + | I40E_RXD_QW1_STATUS_TSYNINDX_MASK)) + >> I40E_RX_DESC_STATUS_TSYNINDX_SHIFT; + + if (tsyn & 0x04) + pkt_flags |= PKT_RX_IEEE1588_TMST; + + rxm->udata64 = tsyn & 0x03; +#endif rxm->ol_flags = pkt_flags; rx_pkts[nb_rx++] = rxm; @@ -1010,6 +1032,7 @@ i40e_recv_scattered_pkts(void *rx_queue, qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len); rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; + /* Check the DD bit */ if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) break; @@ -1120,6 +1143,16 @@ i40e_recv_scattered_pkts(void *rx_queue, if (pkt_flags & PKT_RX_FDIR) pkt_flags |= i40e_rxd_build_fdir(&rxd, rxm); +#ifdef RTE_LIBRTE_IEEE1588 + uint16_t tsyn = (qword1 & (I40E_RXD_QW1_STATUS_TSYNVALID_MASK + | I40E_RXD_QW1_STATUS_TSYNINDX_MASK)) + >> I40E_RX_DESC_STATUS_TSYNINDX_SHIFT; + + if (tsyn & 0x04) + pkt_flags |= PKT_RX_IEEE1588_TMST; + + first_seg->udata64 = tsyn & 0x03; +#endif first_seg->ol_flags = pkt_flags; /* Prefetch data of first segment, if configured to do so. */ @@ -2366,6 +2399,10 @@ i40e_tx_queue_init(struct i40e_tx_queue *txq) tx_ctx.new_context = 1; tx_ctx.base = txq->tx_ring_phys_addr / I40E_QUEUE_BASE_ADDR_UNIT; tx_ctx.qlen = txq->nb_tx_desc; + +#ifdef RTE_LIBRTE_IEEE1588 + tx_ctx.timesync_ena = 1; +#endif tx_ctx.rdylist = rte_le_to_cpu_16(vsi->info.qs_handle[0]); if (vsi->type == I40E_VSI_FDIR) tx_ctx.fd_ena = TRUE; -- 1.8.1.4