From patchwork Thu Sep 2 07:39:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simei Su X-Patchwork-Id: 97762 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E11E0A0C47; Thu, 2 Sep 2021 09:45:38 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id C5D294013F; Thu, 2 Sep 2021 09:45:38 +0200 (CEST) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by mails.dpdk.org (Postfix) with ESMTP id 29D414003C for ; Thu, 2 Sep 2021 09:45:37 +0200 (CEST) X-IronPort-AV: E=McAfee;i="6200,9189,10094"; a="282727373" X-IronPort-AV: E=Sophos;i="5.84,371,1620716400"; d="scan'208";a="282727373" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Sep 2021 00:45:36 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,371,1620716400"; d="scan'208";a="499613156" Received: from unknown (HELO npg-dpdk-cvl-simeisu-118d193.sh.intel.com) ([10.67.119.195]) by fmsmga008.fm.intel.com with ESMTP; 02 Sep 2021 00:45:33 -0700 From: Simei Su To: qi.z.zhang@intel.com Cc: dev@dpdk.org, haiyue.wang@intel.com, Simei Su Date: Thu, 2 Sep 2021 15:39:27 +0800 Message-Id: <20210902073927.88804-1-simei.su@intel.com> X-Mailer: git-send-email 2.9.5 Subject: [dpdk-dev] [PATCH] net/ice: add 1PPS support for E810 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The E810 supports four single-ended GPIO signals (SDP[20:23]). The 1PPS signal outputs via SDP[20:23], which is measured by an oscilloscope. This feature can be turned by a devargs which can select GPIO pin index flexibly. Pin index 0 means SDP20, pin index 1 means SDP21 and so on. The example for test command is as below: ./build/app/dpdk-testpmd -w af:00.0,pps_out='[pin:2]' -c f -n 4 -- -i Signed-off-by: Simei Su --- drivers/net/ice/ice_ethdev.c | 196 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/ice/ice_ethdev.h | 15 ++++ 2 files changed, 211 insertions(+) diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index 3dc7d40..4af3210 100644 --- a/drivers/net/ice/ice_ethdev.c +++ b/drivers/net/ice/ice_ethdev.c @@ -30,14 +30,18 @@ #define ICE_PIPELINE_MODE_SUPPORT_ARG "pipeline-mode-support" #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_CYCLECOUNTER_MASK 0xffffffffffffffffULL +#define PPS_OUT_DELAY_NS 1 + static const char * const ice_valid_args[] = { ICE_SAFE_MODE_SUPPORT_ARG, ICE_PIPELINE_MODE_SUPPORT_ARG, ICE_PROTO_XTR_ARG, ICE_HW_DEBUG_MASK_ARG, + ICE_ONE_PPS_OUT_ARG, NULL }; @@ -1808,6 +1812,125 @@ parse_u64(const char *key, const char *value, void *args) return 0; } +static int +lookup_pps_type(const char *pps_name) +{ + static struct { + const char *name; + enum pps_type type; + } pps_type_map[] = { + { "pin", PPS_PIN }, + }; + + uint32_t i; + + for (i = 0; i < RTE_DIM(pps_type_map); i++) { + if (strcmp(pps_name, pps_type_map[i].name) == 0) + return pps_type_map[i].type; + } + + return -1; +} + +static int +parse_gpio_set(const char *input, int pps_type, struct ice_devargs *devargs) +{ + const char *str = input; + char *end = NULL; + uint32_t idx; + + while (isblank(*str)) + str++; + + if (!isdigit(*str)) + return -1; + + if (pps_type == PPS_PIN) { + idx = strtoul(str, &end, 10); + if (end == NULL || idx >= ICE_MAX_GPIO_NUM) + return -1; + + devargs->pin_idx = idx; + devargs->pps_out_ena = 1; + } + + while (isblank(*end)) + end++; + + if (*end != ']') + return -1; + + return 0; +} + +static int +parse_pps_out_parameter(const char *pins, struct ice_devargs *devargs) +{ + const char *pin_start; + uint32_t idx; + int pps_type; + char pps_name[32]; + + while (isblank(*pins)) + pins++; + + pins++; + while (isblank(*pins)) + pins++; + if (*pins == '\0') + return -1; + + for (idx = 0; ; idx++) { + if (isblank(pins[idx]) || + pins[idx] == ':' || + pins[idx] == '\0') + break; + + pps_name[idx] = pins[idx]; + } + pps_name[idx] = '\0'; + pps_type = lookup_pps_type(pps_name); + if (pps_type < 0) + return -1; + + pins += idx; + + pins += strcspn(pins, ":"); + if (*pins++ != ':') + return -1; + while (isblank(*pins)) + pins++; + + pin_start = pins; + + while (isblank(*pins)) + pins++; + + if (parse_gpio_set(pin_start, pps_type, devargs) < 0) + return -1; + + return 0; +} + +static int +handle_pps_out_arg(__rte_unused const char *key, const char *value, + void *extra_args) +{ + struct ice_devargs *devargs = extra_args; + + if (value == NULL || extra_args == NULL) + return -EINVAL; + + if (parse_pps_out_parameter(value, devargs) < 0) { + PMD_DRV_LOG(ERR, + "The GPIO pin parameter is wrong : '%s'", + value); + return -1; + } + + return 0; +} + static int ice_parse_devargs(struct rte_eth_dev *dev) { struct ice_adapter *ad = @@ -1849,6 +1972,11 @@ static int ice_parse_devargs(struct rte_eth_dev *dev) if (ret) goto bail; + ret = rte_kvargs_process(kvlist, ICE_ONE_PPS_OUT_ARG, + &handle_pps_out_arg, &ad->devargs); + if (ret) + goto bail; + bail: rte_kvargs_free(kvlist); return ret; @@ -2308,6 +2436,9 @@ ice_dev_close(struct rte_eth_dev *dev) struct ice_adapter *ad = ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); int ret; + uint32_t val; + uint8_t timer = hw->func_caps.ts_func_info.tmr_index_owned; + uint32_t pin_idx = ad->devargs.pin_idx; if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; @@ -2344,6 +2475,16 @@ ice_dev_close(struct rte_eth_dev *dev) rte_intr_callback_unregister(intr_handle, ice_interrupt_handler, dev); + if (ad->devargs.pps_out_ena) { + ICE_WRITE_REG(hw, GLTSYN_AUX_OUT(pin_idx, timer), 0); + ICE_WRITE_REG(hw, GLTSYN_CLKO(pin_idx, timer), 0); + ICE_WRITE_REG(hw, GLTSYN_TGT_L(pin_idx, timer), 0); + ICE_WRITE_REG(hw, GLTSYN_TGT_H(pin_idx, timer), 0); + + val = GLGEN_GPIO_CTL_PIN_DIR_M; + ICE_WRITE_REG(hw, GLGEN_GPIO_CTL(pin_idx), val); + } + return ret; } @@ -3340,16 +3481,63 @@ ice_get_init_link_status(struct rte_eth_dev *dev) } static int +ice_pps_out_cfg(struct ice_hw *hw, int idx, int timer) +{ + uint64_t current_time, start_time; + uint32_t hi, lo, lo2, func, val; + + lo = ICE_READ_REG(hw, GLTSYN_TIME_L(timer)); + hi = ICE_READ_REG(hw, GLTSYN_TIME_H(timer)); + lo2 = ICE_READ_REG(hw, GLTSYN_TIME_L(timer)); + + if (lo2 < lo) { + lo = ICE_READ_REG(hw, GLTSYN_TIME_L(timer)); + hi = ICE_READ_REG(hw, GLTSYN_TIME_H(timer)); + } + + current_time = ((uint64_t)hi << 32) | lo; + + start_time = (current_time + NSEC_PER_SEC) / + NSEC_PER_SEC * NSEC_PER_SEC; + start_time = start_time - PPS_OUT_DELAY_NS; + + func = 8 + idx + timer * 4; + val = GLGEN_GPIO_CTL_PIN_DIR_M | + ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) & + GLGEN_GPIO_CTL_PIN_FUNC_M); + + /* Write clkout with half of period value */ + ICE_WRITE_REG(hw, GLTSYN_CLKO(idx, timer), NSEC_PER_SEC / 2); + + /* Write TARGET time register */ + ICE_WRITE_REG(hw, GLTSYN_TGT_L(idx, timer), start_time & 0xffffffff); + ICE_WRITE_REG(hw, GLTSYN_TGT_H(idx, timer), start_time >> 32); + + /* Write AUX_OUT register */ + ICE_WRITE_REG(hw, GLTSYN_AUX_OUT(idx, timer), + GLTSYN_AUX_OUT_0_OUT_ENA_M | GLTSYN_AUX_OUT_0_OUTMOD_M); + + /* Write GPIO CTL register */ + ICE_WRITE_REG(hw, GLGEN_GPIO_CTL(idx), val); + + return 0; +} + +static int ice_dev_start(struct rte_eth_dev *dev) { struct rte_eth_dev_data *data = dev->data; struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct ice_vsi *vsi = pf->main_vsi; + struct ice_adapter *ad = + ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); uint16_t nb_rxq = 0; uint16_t nb_txq, i; uint16_t max_frame_size; int mask, ret; + uint8_t timer = hw->func_caps.ts_func_info.tmr_index_owned; + uint32_t pin_idx = ad->devargs.pin_idx; /* program Tx queues' context in hardware */ for (nb_txq = 0; nb_txq < data->nb_tx_queues; nb_txq++) { @@ -3420,6 +3608,14 @@ ice_dev_start(struct rte_eth_dev *dev) /* Set the max frame size to HW*/ ice_aq_set_mac_cfg(hw, max_frame_size, NULL); + if (ad->devargs.pps_out_ena) { + ret = ice_pps_out_cfg(hw, pin_idx, timer); + if (ret) { + PMD_DRV_LOG(ERR, "fail to start Rx queue %u", nb_rxq); + goto rx_err; + } + } + return 0; /* stop the started queues if failed to start all queues */ diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index 1c7c8ea..1ded0eb 100644 --- a/drivers/net/ice/ice_ethdev.h +++ b/drivers/net/ice/ice_ethdev.h @@ -144,6 +144,12 @@ /* Max number of flexible descriptor rxdid */ #define ICE_FLEX_DESC_RXDID_MAX_NUM 64 +/* Per-channel register definitions */ +#define GLTSYN_AUX_OUT(_chan, _idx) (GLTSYN_AUX_OUT_0(_idx) + ((_chan) * 8)) +#define GLTSYN_CLKO(_chan, _idx) (GLTSYN_CLKO_0(_idx) + ((_chan) * 8)) +#define GLTSYN_TGT_L(_chan, _idx) (GLTSYN_TGT_L_0(_idx) + ((_chan) * 16)) +#define GLTSYN_TGT_H(_chan, _idx) (GLTSYN_TGT_H_0(_idx) + ((_chan) * 16)) + /* DDP package type */ enum ice_pkg_type { ICE_PKG_TYPE_UNKNOWN, @@ -151,6 +157,12 @@ enum ice_pkg_type { ICE_PKG_TYPE_COMMS, }; +enum pps_type { + PPS_NONE, + PPS_PIN, + PPS_MAX, +}; + struct ice_adapter; /** @@ -459,6 +471,7 @@ struct ice_pf { }; #define ICE_MAX_QUEUE_NUM 2048 +#define ICE_MAX_GPIO_NUM 4 /** * Cache devargs parse result. @@ -468,6 +481,8 @@ struct ice_devargs { uint8_t proto_xtr_dflt; int pipe_mode_support; uint8_t proto_xtr[ICE_MAX_QUEUE_NUM]; + uint8_t pin_idx; + uint8_t pps_out_ena; }; /**