X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Focteontx2%2Fotx2_ptp.c;h=ae5a2b7cd12660ebf26347f8c5317b1d9c954358;hb=55f003d8884c3a05937ef7ef113f698870d71a83;hp=105067949a32e1b1d0ee5f53f5c843021044dfe5;hpb=b5dc3140448ee25425385e3a7aa911b858c43a88;p=dpdk.git diff --git a/drivers/net/octeontx2/otx2_ptp.c b/drivers/net/octeontx2/otx2_ptp.c index 105067949a..ae5a2b7cd1 100644 --- a/drivers/net/octeontx2/otx2_ptp.c +++ b/drivers/net/octeontx2/otx2_ptp.c @@ -8,6 +8,113 @@ #define PTP_FREQ_ADJUST (1 << 9) +/* Function to enable ptp config for VFs */ +void +otx2_nix_ptp_enable_vf(struct rte_eth_dev *eth_dev) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + + if (otx2_nix_recalc_mtu(eth_dev)) + otx2_err("Failed to set MTU size for ptp"); + + dev->scalar_ena = true; + dev->rx_offload_flags |= NIX_RX_OFFLOAD_TSTAMP_F; + + /* Setting up the function pointers as per new offload flags */ + otx2_eth_set_rx_function(eth_dev); + otx2_eth_set_tx_function(eth_dev); +} + +static uint16_t +nix_eth_ptp_vf_burst(void *queue, struct rte_mbuf **mbufs, uint16_t pkts) +{ + struct otx2_eth_rxq *rxq = queue; + struct rte_eth_dev *eth_dev; + + RTE_SET_USED(mbufs); + RTE_SET_USED(pkts); + + eth_dev = rxq->eth_dev; + otx2_nix_ptp_enable_vf(eth_dev); + + return 0; +} + +static int +nix_read_raw_clock(struct otx2_eth_dev *dev, uint64_t *clock, uint64_t *tsc, + uint8_t is_pmu) +{ + struct otx2_mbox *mbox = dev->mbox; + struct ptp_req *req; + struct ptp_rsp *rsp; + int rc; + + req = otx2_mbox_alloc_msg_ptp_op(mbox); + req->op = PTP_OP_GET_CLOCK; + req->is_pmu = is_pmu; + rc = otx2_mbox_process_msg(mbox, (void *)&rsp); + if (rc) + goto fail; + + if (clock) + *clock = rsp->clk; + if (tsc) + *tsc = rsp->tsc; + +fail: + return rc; +} + +/* This function calculates two parameters "clk_freq_mult" and + * "clk_delta" which is useful in deriving PTP HI clock from + * timestamp counter (tsc) value. + */ +int +otx2_nix_raw_clock_tsc_conv(struct otx2_eth_dev *dev) +{ + uint64_t ticks_base = 0, ticks = 0, tsc = 0, t_freq; + int rc, val; + + /* Calculating the frequency at which PTP HI clock is running */ + rc = nix_read_raw_clock(dev, &ticks_base, &tsc, false); + if (rc) { + otx2_err("Failed to read the raw clock value: %d", rc); + goto fail; + } + + rte_delay_ms(100); + + rc = nix_read_raw_clock(dev, &ticks, &tsc, false); + if (rc) { + otx2_err("Failed to read the raw clock value: %d", rc); + goto fail; + } + + t_freq = (ticks - ticks_base) * 10; + + /* Calculating the freq multiplier viz the ratio between the + * frequency at which PTP HI clock works and tsc clock runs + */ + dev->clk_freq_mult = + (double)pow(10, floor(log10(t_freq))) / rte_get_timer_hz(); + + val = false; +#ifdef RTE_ARM_EAL_RDTSC_USE_PMU + val = true; +#endif + rc = nix_read_raw_clock(dev, &ticks, &tsc, val); + if (rc) { + otx2_err("Failed to read the raw clock value: %d", rc); + goto fail; + } + + /* Calculating delta between PTP HI clock and tsc */ + dev->clk_delta = ((uint64_t)(ticks / dev->clk_freq_mult) - tsc); + +fail: + return rc; +} + static void nix_start_timecounters(struct rte_eth_dev *eth_dev) { @@ -27,9 +134,9 @@ nix_ptp_config(struct rte_eth_dev *eth_dev, int en) { struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); struct otx2_mbox *mbox = dev->mbox; - uint8_t rc = 0; + uint8_t rc = -EINVAL; - if (otx2_dev_is_vf(dev)) + if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev)) return rc; if (en) { @@ -57,33 +164,77 @@ nix_ptp_config(struct rte_eth_dev *eth_dev, int en) return otx2_mbox_process(mbox); } +int +otx2_eth_dev_ptp_info_update(struct otx2_dev *dev, bool ptp_en) +{ + struct otx2_eth_dev *otx2_dev = (struct otx2_eth_dev *)dev; + struct rte_eth_dev *eth_dev; + int i; + + if (!dev) + return -EINVAL; + + eth_dev = otx2_dev->eth_dev; + if (!eth_dev) + return -EINVAL; + + otx2_dev->ptp_en = ptp_en; + for (i = 0; i < eth_dev->data->nb_rx_queues; i++) { + struct otx2_eth_rxq *rxq = eth_dev->data->rx_queues[i]; + rxq->mbuf_initializer = + otx2_nix_rxq_mbuf_setup(otx2_dev, + eth_dev->data->port_id); + } + if (otx2_dev_is_vf(otx2_dev) && !(otx2_dev_is_sdp(otx2_dev)) && + !(otx2_dev_is_lbk(otx2_dev))) { + /* In case of VF, setting of MTU cant be done directly in this + * function as this is running as part of MBOX request(PF->VF) + * and MTU setting also requires MBOX message to be + * sent(VF->PF) + */ + eth_dev->rx_pkt_burst = nix_eth_ptp_vf_burst; + rte_mb(); + } + + return 0; +} + int otx2_nix_timesync_enable(struct rte_eth_dev *eth_dev) { struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); int i, rc = 0; - if (otx2_ethdev_is_ptp_en(dev)) { - otx2_info("PTP mode is already enabled "); + /* If we are VF/SDP/LBK, ptp cannot not be enabled */ + if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev)) { + otx2_info("PTP cannot be enabled in case of VF/SDP/LBK"); return -EINVAL; } - /* If we are VF, no further action can be taken */ - if (otx2_dev_is_vf(dev)) + if (otx2_ethdev_is_ptp_en(dev)) { + otx2_info("PTP mode is already enabled"); return -EINVAL; + } if (!(dev->rx_offload_flags & NIX_RX_OFFLOAD_PTYPE_F)) { otx2_err("Ptype offload is disabled, it should be enabled"); return -EINVAL; } + if (dev->npc_flow.switch_header_type == OTX2_PRIV_FLAGS_HIGIG) { + otx2_err("Both PTP and switch header enabled"); + return -EINVAL; + } + /* Allocating a iova address for tx tstamp */ const struct rte_memzone *ts; ts = rte_eth_dma_zone_reserve(eth_dev, "otx2_ts", 0, OTX2_ALIGN, OTX2_ALIGN, dev->node); - if (ts == NULL) + if (ts == NULL) { otx2_err("Failed to allocate mem for tx tstamp addr"); + return -ENOMEM; + } dev->tstamp.tx_tstamp_iova = ts->iova; dev->tstamp.tx_tstamp = ts->addr; @@ -101,7 +252,16 @@ otx2_nix_timesync_enable(struct rte_eth_dev *eth_dev) struct otx2_eth_txq *txq = eth_dev->data->tx_queues[i]; otx2_nix_form_default_desc(txq); } + + /* Setting up the function pointers as per new offload flags */ + otx2_eth_set_rx_function(eth_dev); + otx2_eth_set_tx_function(eth_dev); } + + rc = otx2_nix_recalc_mtu(eth_dev); + if (rc) + otx2_err("Failed to set MTU size for ptp"); + return rc; } @@ -116,8 +276,7 @@ otx2_nix_timesync_disable(struct rte_eth_dev *eth_dev) return -EINVAL; } - /* If we are VF, nothing else can be done */ - if (otx2_dev_is_vf(dev)) + if (otx2_dev_is_vf_or_sdp(dev) || otx2_dev_is_lbk(dev)) return -EINVAL; dev->rx_offloads &= ~DEV_RX_OFFLOAD_TIMESTAMP; @@ -130,6 +289,154 @@ otx2_nix_timesync_disable(struct rte_eth_dev *eth_dev) struct otx2_eth_txq *txq = eth_dev->data->tx_queues[i]; otx2_nix_form_default_desc(txq); } + + /* Setting up the function pointers as per new offload flags */ + otx2_eth_set_rx_function(eth_dev); + otx2_eth_set_tx_function(eth_dev); } + + rc = otx2_nix_recalc_mtu(eth_dev); + if (rc) + otx2_err("Failed to set MTU size for ptp"); + return rc; } + +int +otx2_nix_timesync_read_rx_timestamp(struct rte_eth_dev *eth_dev, + struct timespec *timestamp, + uint32_t __rte_unused flags) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_timesync_info *tstamp = &dev->tstamp; + uint64_t ns; + + if (!tstamp->rx_ready) + return -EINVAL; + + ns = rte_timecounter_update(&dev->rx_tstamp_tc, tstamp->rx_tstamp); + *timestamp = rte_ns_to_timespec(ns); + tstamp->rx_ready = 0; + + otx2_nix_dbg("rx timestamp: %"PRIu64" sec: %"PRIu64" nsec %"PRIu64"", + (uint64_t)tstamp->rx_tstamp, (uint64_t)timestamp->tv_sec, + (uint64_t)timestamp->tv_nsec); + + return 0; +} + +int +otx2_nix_timesync_read_tx_timestamp(struct rte_eth_dev *eth_dev, + struct timespec *timestamp) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_timesync_info *tstamp = &dev->tstamp; + uint64_t ns; + + if (*tstamp->tx_tstamp == 0) + return -EINVAL; + + ns = rte_timecounter_update(&dev->tx_tstamp_tc, *tstamp->tx_tstamp); + *timestamp = rte_ns_to_timespec(ns); + + otx2_nix_dbg("tx timestamp: %"PRIu64" sec: %"PRIu64" nsec %"PRIu64"", + *tstamp->tx_tstamp, (uint64_t)timestamp->tv_sec, + (uint64_t)timestamp->tv_nsec); + + *tstamp->tx_tstamp = 0; + rte_wmb(); + + return 0; +} + +int +otx2_nix_timesync_adjust_time(struct rte_eth_dev *eth_dev, int64_t delta) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_mbox *mbox = dev->mbox; + struct ptp_req *req; + struct ptp_rsp *rsp; + int rc; + + /* Adjust the frequent to make tics increments in 10^9 tics per sec */ + if (delta < PTP_FREQ_ADJUST && delta > -PTP_FREQ_ADJUST) { + req = otx2_mbox_alloc_msg_ptp_op(mbox); + req->op = PTP_OP_ADJFINE; + req->scaled_ppm = delta; + + rc = otx2_mbox_process_msg(mbox, (void *)&rsp); + if (rc) + return rc; + /* Since the frequency of PTP comp register is tuned, delta and + * freq mult calculation for deriving PTP_HI from timestamp + * counter should be done again. + */ + rc = otx2_nix_raw_clock_tsc_conv(dev); + if (rc) + otx2_err("Failed to calculate delta and freq mult"); + } + dev->systime_tc.nsec += delta; + dev->rx_tstamp_tc.nsec += delta; + dev->tx_tstamp_tc.nsec += delta; + + return 0; +} + +int +otx2_nix_timesync_write_time(struct rte_eth_dev *eth_dev, + const struct timespec *ts) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + uint64_t ns; + + ns = rte_timespec_to_ns(ts); + /* Set the time counters to a new value. */ + dev->systime_tc.nsec = ns; + dev->rx_tstamp_tc.nsec = ns; + dev->tx_tstamp_tc.nsec = ns; + + return 0; +} + +int +otx2_nix_timesync_read_time(struct rte_eth_dev *eth_dev, struct timespec *ts) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + struct otx2_mbox *mbox = dev->mbox; + struct ptp_req *req; + struct ptp_rsp *rsp; + uint64_t ns; + int rc; + + req = otx2_mbox_alloc_msg_ptp_op(mbox); + req->op = PTP_OP_GET_CLOCK; + rc = otx2_mbox_process_msg(mbox, (void *)&rsp); + if (rc) + return rc; + + ns = rte_timecounter_update(&dev->systime_tc, rsp->clk); + *ts = rte_ns_to_timespec(ns); + + otx2_nix_dbg("PTP time read: %"PRIu64" .%09"PRIu64"", + (uint64_t)ts->tv_sec, (uint64_t)ts->tv_nsec); + + return 0; +} + + +int +otx2_nix_read_clock(struct rte_eth_dev *eth_dev, uint64_t *clock) +{ + struct otx2_eth_dev *dev = otx2_eth_pmd_priv(eth_dev); + + /* This API returns the raw PTP HI clock value. Since LFs doesn't + * have direct access to PTP registers and it requires mbox msg + * to AF for this value. In fastpath reading this value for every + * packet (which involes mbox call) becomes very expensive, hence + * we should be able to derive PTP HI clock value from tsc by + * using freq_mult and clk_delta calculated during configure stage. + */ + *clock = (rte_get_tsc_cycles() + dev->clk_delta) * dev->clk_freq_mult; + + return 0; +}