#include "base/ice_flow.h"
#include "base/ice_dcb.h"
#include "base/ice_common.h"
+#include "base/ice_ptp_hw.h"
#include "rte_pmd_ice.h"
#include "ice_ethdev.h"
#define ICE_PROTO_XTR_ARG "proto_xtr"
#define ICE_HW_DEBUG_MASK_ARG "hw_debug_mask"
#define ICE_ONE_PPS_OUT_ARG "pps_out"
+#define ICE_RX_LOW_LATENCY_ARG "rx_low_latency"
+
+#define ICE_CYCLECOUNTER_MASK 0xffffffffffffffffULL
+
+uint64_t ice_timestamp_dynflag;
+int ice_timestamp_dynfield_offset = -1;
static const char * const ice_valid_args[] = {
ICE_SAFE_MODE_SUPPORT_ARG,
ICE_PROTO_XTR_ARG,
ICE_HW_DEBUG_MASK_ARG,
ICE_ONE_PPS_OUT_ARG,
+ ICE_RX_LOW_LATENCY_ARG,
NULL
};
-#define NSEC_PER_SEC 1000000000
#define PPS_OUT_DELAY_NS 1
static const struct rte_mbuf_dynfield ice_proto_xtr_metadata_param = {
struct rte_eth_udp_tunnel *udp_tunnel);
static int ice_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *udp_tunnel);
+static int ice_timesync_enable(struct rte_eth_dev *dev);
+static int ice_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp,
+ uint32_t flags);
+static int ice_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp);
+static int ice_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta);
+static int ice_timesync_read_time(struct rte_eth_dev *dev,
+ struct timespec *timestamp);
+static int ice_timesync_write_time(struct rte_eth_dev *dev,
+ const struct timespec *timestamp);
+static int ice_timesync_disable(struct rte_eth_dev *dev);
static const struct rte_pci_id pci_id_ice_map[] = {
{ RTE_PCI_DEVICE(ICE_INTEL_VENDOR_ID, ICE_DEV_ID_E823L_BACKPLANE) },
.tx_queue_start = ice_tx_queue_start,
.tx_queue_stop = ice_tx_queue_stop,
.rx_queue_setup = ice_rx_queue_setup,
- .rx_queue_release = ice_rx_queue_release,
+ .rx_queue_release = ice_dev_rx_queue_release,
.tx_queue_setup = ice_tx_queue_setup,
- .tx_queue_release = ice_tx_queue_release,
+ .tx_queue_release = ice_dev_tx_queue_release,
.dev_infos_get = ice_dev_info_get,
.dev_supported_ptypes_get = ice_dev_supported_ptypes_get,
.link_update = ice_link_update,
.udp_tunnel_port_del = ice_dev_udp_tunnel_port_del,
.tx_done_cleanup = ice_tx_done_cleanup,
.get_monitor_addr = ice_get_monitor_addr,
+ .timesync_enable = ice_timesync_enable,
+ .timesync_read_rx_timestamp = ice_timesync_read_rx_timestamp,
+ .timesync_read_tx_timestamp = ice_timesync_read_tx_timestamp,
+ .timesync_adjust_time = ice_timesync_adjust_time,
+ .timesync_read_time = ice_timesync_read_time,
+ .timesync_write_time = ice_timesync_write_time,
+ .timesync_disable = ice_timesync_disable,
};
/* store statistics names and its offset in stats structure */
if (ret)
goto bail;
+ ret = rte_kvargs_process(kvlist, ICE_RX_LOW_LATENCY_ARG,
+ &parse_bool, &ad->devargs.rx_low_latency);
+
bail:
rte_kvargs_free(kvlist);
return ret;
{
struct ice_hw *hw = ICE_VSI_TO_HW(vsi);
uint32_t val, val_tx;
- int i;
+ int rx_low_latency, i;
+ rx_low_latency = vsi->adapter->devargs.rx_low_latency;
for (i = 0; i < nb_queue; i++) {
/*do actual bind*/
val = (msix_vect & QINT_RQCTL_MSIX_INDX_M) |
PMD_DRV_LOG(INFO, "queue %d is binding to vect %d",
base_queue + i, msix_vect);
+
/* set ITR0 value */
- ICE_WRITE_REG(hw, GLINT_ITR(0, msix_vect), 0x2);
+ if (rx_low_latency) {
+ /**
+ * Empirical configuration for optimal real time
+ * latency reduced interrupt throttling to 2us
+ */
+ ICE_WRITE_REG(hw, GLINT_ITR(0, msix_vect), 0x1);
+ ICE_WRITE_REG(hw, QRX_ITR(base_queue + i),
+ QRX_ITR_NO_EXPR_M);
+ } else {
+ ICE_WRITE_REG(hw, GLINT_ITR(0, msix_vect), 0x2);
+ ICE_WRITE_REG(hw, QRX_ITR(base_queue + i), 0);
+ }
+
ICE_WRITE_REG(hw, QINT_RQCTL(base_queue + i), val);
ICE_WRITE_REG(hw, QINT_TQCTL(base_queue + i), val_tx);
}
DEV_RX_OFFLOAD_QINQ_STRIP |
DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
DEV_RX_OFFLOAD_VLAN_EXTEND |
- DEV_RX_OFFLOAD_RSS_HASH;
+ DEV_RX_OFFLOAD_RSS_HASH |
+ DEV_RX_OFFLOAD_TIMESTAMP;
dev_info->tx_offload_capa |=
DEV_TX_OFFLOAD_QINQ_INSERT |
DEV_TX_OFFLOAD_IPV4_CKSUM |
return ret;
}
+static int
+ice_timesync_enable(struct rte_eth_dev *dev)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ int ret;
+
+ if (dev->data->dev_started && !(dev->data->dev_conf.rxmode.offloads &
+ DEV_RX_OFFLOAD_TIMESTAMP)) {
+ PMD_DRV_LOG(ERR, "Rx timestamp offload not configured");
+ return -1;
+ }
+
+ if (hw->func_caps.ts_func_info.src_tmr_owned) {
+ ret = ice_ptp_init_phc(hw);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to initialize PHC");
+ return -1;
+ }
+
+ ret = ice_ptp_write_incval(hw, ICE_PTP_NOMINAL_INCVAL_E810);
+ if (ret) {
+ PMD_DRV_LOG(ERR,
+ "Failed to write PHC increment time value");
+ return -1;
+ }
+ }
+
+ /* Initialize cycle counters for system time/RX/TX timestamp */
+ memset(&ad->systime_tc, 0, sizeof(struct rte_timecounter));
+ memset(&ad->rx_tstamp_tc, 0, sizeof(struct rte_timecounter));
+ memset(&ad->tx_tstamp_tc, 0, sizeof(struct rte_timecounter));
+
+ ad->systime_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->systime_tc.cc_shift = 0;
+ ad->systime_tc.nsec_mask = 0;
+
+ ad->rx_tstamp_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->rx_tstamp_tc.cc_shift = 0;
+ ad->rx_tstamp_tc.nsec_mask = 0;
+
+ ad->tx_tstamp_tc.cc_mask = ICE_CYCLECOUNTER_MASK;
+ ad->tx_tstamp_tc.cc_shift = 0;
+ ad->tx_tstamp_tc.nsec_mask = 0;
+
+ ad->ptp_ena = 1;
+
+ return 0;
+}
+
+static int
+ice_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp, uint32_t flags)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ struct ice_rx_queue *rxq;
+ uint32_t ts_high;
+ uint64_t ts_ns, ns;
+
+ rxq = dev->data->rx_queues[flags];
+
+ ts_high = rxq->time_high;
+ ts_ns = ice_tstamp_convert_32b_64b(hw, ts_high);
+ ns = rte_timecounter_update(&ad->rx_tstamp_tc, ts_ns);
+ *timestamp = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
+ struct timespec *timestamp)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint8_t lport;
+ uint64_t ts_ns, ns, tstamp;
+ const uint64_t mask = 0xFFFFFFFF;
+ int ret;
+
+ lport = hw->port_info->lport;
+
+ ret = ice_read_phy_tstamp(hw, lport, 0, &tstamp);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to read phy timestamp");
+ return -1;
+ }
+
+ ts_ns = ice_tstamp_convert_32b_64b(hw, (tstamp >> 8) & mask);
+ ns = rte_timecounter_update(&ad->tx_tstamp_tc, ts_ns);
+ *timestamp = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta)
+{
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+
+ ad->systime_tc.nsec += delta;
+ ad->rx_tstamp_tc.nsec += delta;
+ ad->tx_tstamp_tc.nsec += delta;
+
+ return 0;
+}
+
+static int
+ice_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *ts)
+{
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint64_t ns;
+
+ ns = rte_timespec_to_ns(ts);
+
+ ad->systime_tc.nsec = ns;
+ ad->rx_tstamp_tc.nsec = ns;
+ ad->tx_tstamp_tc.nsec = ns;
+
+ return 0;
+}
+
+static int
+ice_timesync_read_time(struct rte_eth_dev *dev, struct timespec *ts)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint32_t hi, lo, lo2;
+ uint64_t time, ns;
+
+ lo = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+ hi = ICE_READ_REG(hw, GLTSYN_TIME_H(0));
+ lo2 = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+
+ if (lo2 < lo) {
+ lo = ICE_READ_REG(hw, GLTSYN_TIME_L(0));
+ hi = ICE_READ_REG(hw, GLTSYN_TIME_H(0));
+ }
+
+ time = ((uint64_t)hi << 32) | lo;
+ ns = rte_timecounter_update(&ad->systime_tc, time);
+ *ts = rte_ns_to_timespec(ns);
+
+ return 0;
+}
+
+static int
+ice_timesync_disable(struct rte_eth_dev *dev)
+{
+ struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ struct ice_adapter *ad =
+ ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ uint64_t val;
+ uint8_t lport;
+
+ lport = hw->port_info->lport;
+
+ ice_clear_phy_tstamp(hw, lport, 0);
+
+ val = ICE_READ_REG(hw, GLTSYN_ENA(0));
+ val &= ~GLTSYN_ENA_TSYN_ENA_M;
+ ICE_WRITE_REG(hw, GLTSYN_ENA(0), val);
+
+ ICE_WRITE_REG(hw, GLTSYN_INCVAL_L(0), 0);
+ ICE_WRITE_REG(hw, GLTSYN_INCVAL_H(0), 0);
+
+ ad->ptp_ena = 0;
+
+ return 0;
+}
+
static int
ice_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
struct rte_pci_device *pci_dev)
ICE_HW_DEBUG_MASK_ARG "=0xXXX"
ICE_PROTO_XTR_ARG "=[queue:]<vlan|ipv4|ipv6|ipv6_flow|tcp|ip_offset>"
ICE_SAFE_MODE_SUPPORT_ARG "=<0|1>"
- ICE_PIPELINE_MODE_SUPPORT_ARG "=<0|1>");
+ ICE_PIPELINE_MODE_SUPPORT_ARG "=<0|1>"
+ ICE_RX_LOW_LATENCY_ARG "=<0|1>");
RTE_LOG_REGISTER_SUFFIX(ice_logtype_init, init, NOTICE);
RTE_LOG_REGISTER_SUFFIX(ice_logtype_driver, driver, NOTICE);