diff --git a/include/osi_common.h b/include/osi_common.h index 9061f20..42934b1 100644 --- a/include/osi_common.h +++ b/include/osi_common.h @@ -130,6 +130,8 @@ #define OSI_PTP_REQ_CLK_FREQ 250000000U #define OSI_FLOW_CTRL_DISABLE 0U +#define OSI_POLL_COUNT 1000U + #define OSI_ADDRESS_32BIT 0 #define OSI_ADDRESS_40BIT 1 #define OSI_ADDRESS_48BIT 2 @@ -143,7 +145,6 @@ #endif /** @} */ - /** * @addtogroup Helper Helper MACROS * @@ -154,11 +155,15 @@ /* Logging defines */ /* log levels */ + +#define OSI_LOG_INFO 1U +#define OSI_LOG_WARN 2U #define OSI_LOG_ERR 3U /* Error types */ +#define OSI_LOG_ARG_OUTOFBOUND 1U #define OSI_LOG_ARG_INVALID 2U +#define OSI_LOG_ARG_HW_FAIL 4U #ifndef OSI_STRIPPED_LIB -#define OSI_LOG_WARN 2U #define OSI_LOG_ARG_OPNOTSUPP 3U #endif /* !OSI_STRIPPED_LIB */ /* Default maximum Giant Packet Size Limit is 16K */ diff --git a/include/osi_core.h b/include/osi_core.h index 773dc50..f586f7e 100644 --- a/include/osi_core.h +++ b/include/osi_core.h @@ -76,6 +76,7 @@ typedef my_lint_64 nvel64_t; #define OSI_MAC_TCR_TSMASTERENA OSI_BIT(15) #define OSI_MAC_TCR_SNAPTYPSEL_1 OSI_BIT(16) #define OSI_MAC_TCR_SNAPTYPSEL_2 OSI_BIT(17) +#define OSI_MAC_TCR_CSC OSI_BIT(19) #define OSI_MAC_TCR_AV8021ASMEN OSI_BIT(28) #ifndef OSI_STRIPPED_LIB #define OSI_MAC_TCR_SNAPTYPSEL_3 (OSI_BIT(16) | OSI_BIT(17)) @@ -115,11 +116,6 @@ typedef my_lint_64 nvel64_t; #define OSI_IPV6_MATCH 1U #define OSI_IPV4_MATCH 0U - -#define OSI_LOG_INFO 1U -#define OSI_LOG_ARG_HW_FAIL 4U -#define OSI_LOG_ARG_OUTOFBOUND 1U - /* L2 filter operations supported by OSI layer. These operation modes shall be * set by OSD driver as input to update registers accordingly. */ @@ -180,6 +176,8 @@ typedef my_lint_64 nvel64_t; #define VLAN_NUM_VID 4096U #define OSI_VLAN_ACTION_ADD OSI_BIT(31) #define OSI_VLAN_ACTION_DEL 0x0U +#define OSI_RXQ_ROUTE_PTP 0U +#define OSI_DELAY_1000US 1000U /** * @addtogroup RSS related information diff --git a/include/osi_dma.h b/include/osi_dma.h index 8c2f947..d5af817 100644 --- a/include/osi_dma.h +++ b/include/osi_dma.h @@ -26,6 +26,19 @@ #include #include "osi_dma_txrx.h" +/* + * @addtogroup Helper Helper MACROS + * + * @brief These flags are used for PTP time synchronization + * @{ + */ +#define OSI_PTP_SYNC_MASTER OSI_BIT(0) +#define OSI_PTP_SYNC_SLAVE OSI_BIT(1) +#define OSI_PTP_SYNC_ONESTEP OSI_BIT(2) +#define OSI_PTP_SYNC_TWOSTEP OSI_BIT(3) +#define OSI_DELAY_1US 1U +/** @} */ + /** * @addtogroup Helper Helper MACROS * @@ -82,8 +95,8 @@ * whether checksum offload is to be enabled for the packet upon transmit, * whether IP checksum offload is to be enabled for the packet upon transmit, * whether TCP segmentation offload is to be enabled for the packet, - * whether the HW should timestamp transmit/arrival of a packet respectively, - * whether tx payload length to be updated + * whether the HW should timestamp transmit/arrival of a packet respectively + * whether a paged buffer. * @{ */ /** VLAN packet */ @@ -94,8 +107,10 @@ #define OSI_PKT_CX_TSO OSI_BIT(2) /** PTP packet */ #define OSI_PKT_CX_PTP OSI_BIT(3) +/** Paged buffer */ +#define OSI_PKT_CX_PAGED_BUF OSI_BIT(4) /** Rx packet has RSS hash */ -#define OSI_PKT_CX_RSS OSI_BIT(4) +#define OSI_PKT_CX_RSS OSI_BIT(5) /** Valid packet */ #define OSI_PKT_CX_VALID OSI_BIT(10) /** Update Packet Length in Tx Desc3 */ @@ -324,6 +339,11 @@ struct osi_tx_swcx { /** Flag to keep track of whether buffer pointed by buf_phy_addr * is a paged buffer/linear buffer */ nveu32_t is_paged_buf; + /** Flag to keep track of SWCX + * Bit 0 is_paged_buf - whether buffer pointed by buf_phy_addr + * is a paged buffer/linear buffer + * Bit 1 PTP hwtime form timestamp registers */ + unsigned int flags; }; /** @@ -519,6 +539,10 @@ struct osi_dma_priv_data { nveu64_t resv_buf_phy_addr; /** Tegra Pre-si platform info */ nveu32_t pre_si; + /** PTP flags + * bit 0 PTP mode master(1) slave(0) + * bit 1 PTP sync method twostep(1) onestep(0) */ + unsigned int ptp_flag; }; diff --git a/osi/common/mgbe_common.c b/osi/common/mgbe_common.c new file mode 100644 index 0000000..315fdbf --- /dev/null +++ b/osi/common/mgbe_common.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "../osi/common/common.h" +#include "mgbe_common.h" + +/** + * @brief mgbe_get_systime_from_mac - Get system time from MAC + * + * Algorithm: Get current system time + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +nveul64_t mgbe_get_systime_from_mac(void *addr) +{ + nveul64_t ns1, ns2, ns = 0; + nveu32_t varmac_stnsr, temp1; + nveu32_t varmac_stsr; + + varmac_stnsr = osi_readl((nveu8_t *)addr + MGBE_MAC_STNSR); + temp1 = (varmac_stnsr & MGBE_MAC_STNSR_TSSS_MASK); + ns1 = (nveul64_t)temp1; + + varmac_stsr = osi_readl((nveu8_t *)addr + MGBE_MAC_STSR); + + varmac_stnsr = osi_readl((nveu8_t *)addr + MGBE_MAC_STNSR); + temp1 = (varmac_stnsr & MGBE_MAC_STNSR_TSSS_MASK); + ns2 = (nveul64_t)temp1; + + /* if ns1 is greater than ns2, it means nsec counter rollover + * happened. In that case read the updated sec counter again + */ + if (ns1 >= ns2) { + varmac_stsr = osi_readl((nveu8_t *)addr + MGBE_MAC_STSR); + /* convert sec/high time value to nanosecond */ + if (varmac_stsr < UINT_MAX) { + ns = ns2 + (varmac_stsr * OSI_NSEC_PER_SEC); + } + } else { + /* convert sec/high time value to nanosecond */ + if (varmac_stsr < UINT_MAX) { + ns = ns1 + (varmac_stsr * OSI_NSEC_PER_SEC); + } + } + + return ns; +} diff --git a/osi/common/mgbe_common.h b/osi/common/mgbe_common.h new file mode 100644 index 0000000..1baff90 --- /dev/null +++ b/osi/common/mgbe_common.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef INCLUDED_MGBE_COMMON_H +#define INCLUDED_MGBE_COMMON_H + +/** + * @addtogroup MGBE-MAC MGBE MAC PTP HW feature registers + * + * @{ + */ +#define MGBE_MAC_STSR 0x0D08 +#define MGBE_MAC_STNSR 0x0D0C +#define MGBE_MAC_STNSR_TSSS_MASK 0x7FFFFFFFU +/** @} */ + +nveul64_t mgbe_get_systime_from_mac(void *addr); + +#endif /* INCLUDED_MGBE_COMMON_H */ diff --git a/osi/common/osi_common.c b/osi/common/osi_common.c index d06dc7b..9e2b26e 100644 --- a/osi/common/osi_common.c +++ b/osi/common/osi_common.c @@ -32,6 +32,8 @@ void common_get_systime_from_mac(void *addr, nveu32_t mac, nveu32_t *sec, if (mac == OSI_MAC_HW_EQOS) { ns = eqos_get_systime_from_mac(addr); + } else if (mac == OSI_MAC_HW_MGBE) { + ns = eqos_get_systime_from_mac(addr); } else { /* Non EQOS HW is supported yet */ return; diff --git a/osi/core/core_local.h b/osi/core/core_local.h index 4bd50c7..d763adb 100644 --- a/osi/core/core_local.h +++ b/osi/core/core_local.h @@ -120,7 +120,8 @@ struct core_ops { void (*config_tscr)(struct osi_core_priv_data *const osi_core, const nveu32_t ptp_filter); /** Called to configure the sub second increment register */ - void (*config_ssir)(struct osi_core_priv_data *const osi_core); + void (*config_ssir)(struct osi_core_priv_data *const osi_core, + const nveu32_t ptp_clock); /** Called to configure the PTP RX packets Queue */ nve32_t (*config_ptp_rxq)(struct osi_core_priv_data *const osi_core, const unsigned int rxq_idx, diff --git a/osi/core/eqos_core.c b/osi/core/eqos_core.c index 2091815..d97e0cc 100644 --- a/osi/core/eqos_core.c +++ b/osi/core/eqos_core.c @@ -2740,11 +2740,12 @@ static inline nve32_t eqos_poll_for_tsinit_complete( if ((*mac_tcr & EQOS_MAC_TCR_TSINIT) == 0U) { cond = COND_MET; } + count++; - osi_core->osd_ops.udelay(1000U); + osi_core->osd_ops.udelay(OSI_DELAY_1000US); } - return 0; + return -1; } /** @@ -2779,6 +2780,7 @@ static nve32_t eqos_set_systime_to_mac( nveu32_t mac_tcr; nve32_t ret; + /* To be sure previous write was flushed (if Any) */ ret = eqos_poll_for_tsinit_complete(osi_core, &mac_tcr); if (ret == -1) { return -1; @@ -2852,11 +2854,12 @@ static inline nve32_t eqos_poll_for_addend_complete( if ((*mac_tcr & EQOS_MAC_TCR_TSADDREG) == 0U) { cond = COND_MET; } + count++; - osi_core->osd_ops.udelay(1000U); + osi_core->osd_ops.udelay(OSI_DELAY_1000US); } - return 0; + return -1; } /** @@ -2886,6 +2889,7 @@ static nve32_t eqos_config_addend(struct osi_core_priv_data *const osi_core, nveu32_t mac_tcr; nve32_t ret; + /* To be sure previous write was flushed (if Any) */ ret = eqos_poll_for_addend_complete(osi_core, &mac_tcr); if (ret == -1) { return -1; @@ -2955,11 +2959,12 @@ static inline nve32_t eqos_poll_for_update_ts_complete( if ((*mac_tcr & EQOS_MAC_TCR_TSUPDT) == 0U) { cond = COND_MET; } + count++; - osi_core->osd_ops.udelay(1000U); + osi_core->osd_ops.udelay(OSI_DELAY_1000US); } - return 0; + return -1; } @@ -3082,58 +3087,54 @@ static void eqos_config_tscr(struct osi_core_priv_data *const osi_core, void *addr = osi_core->base; nveu32_t mac_tcr = 0U, i = 0U, temp = 0U; - if (ptp_filter == OSI_DISABLE) { + if (ptp_filter != OSI_DISABLE) { + mac_tcr = (OSI_MAC_TCR_TSENA | + OSI_MAC_TCR_TSCFUPDT | + OSI_MAC_TCR_TSCTRLSSR); + + for (i = 0U; i < 32U; i++) { + temp = ptp_filter & OSI_BIT(i); + + switch (temp) { + case OSI_MAC_TCR_SNAPTYPSEL_1: + mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_1; + break; + case OSI_MAC_TCR_SNAPTYPSEL_2: + mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_2; + break; + case OSI_MAC_TCR_TSIPV4ENA: + mac_tcr |= OSI_MAC_TCR_TSIPV4ENA; + break; + case OSI_MAC_TCR_TSIPV6ENA: + mac_tcr |= OSI_MAC_TCR_TSIPV6ENA; + break; + case OSI_MAC_TCR_TSEVENTENA: + mac_tcr |= OSI_MAC_TCR_TSEVENTENA; + break; + case OSI_MAC_TCR_TSMASTERENA: + mac_tcr |= OSI_MAC_TCR_TSMASTERENA; + break; + case OSI_MAC_TCR_TSVER2ENA: + mac_tcr |= OSI_MAC_TCR_TSVER2ENA; + break; + case OSI_MAC_TCR_TSIPENA: + mac_tcr |= OSI_MAC_TCR_TSIPENA; + break; + case OSI_MAC_TCR_AV8021ASMEN: + mac_tcr |= OSI_MAC_TCR_AV8021ASMEN; + break; + case OSI_MAC_TCR_TSENALL: + mac_tcr |= OSI_MAC_TCR_TSENALL; + break; + default: + /* To avoid MISRA violation */ + mac_tcr |= mac_tcr; + break; + } + } + } else { /* Disabling the MAC time stamping */ mac_tcr = OSI_DISABLE; - eqos_core_safety_writel(osi_core, mac_tcr, - (nveu8_t *)addr + EQOS_MAC_TCR, - EQOS_MAC_TCR_IDX); - return; - } - - mac_tcr = (OSI_MAC_TCR_TSENA | - OSI_MAC_TCR_TSCFUPDT | - OSI_MAC_TCR_TSCTRLSSR); - - for (i = 0U; i < 32U; i++) { - temp = ptp_filter & OSI_BIT(i); - - switch (temp) { - case OSI_MAC_TCR_SNAPTYPSEL_1: - mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_1; - break; - case OSI_MAC_TCR_SNAPTYPSEL_2: - mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_2; - break; - case OSI_MAC_TCR_TSIPV4ENA: - mac_tcr |= OSI_MAC_TCR_TSIPV4ENA; - break; - case OSI_MAC_TCR_TSIPV6ENA: - mac_tcr |= OSI_MAC_TCR_TSIPV6ENA; - break; - case OSI_MAC_TCR_TSEVENTENA: - mac_tcr |= OSI_MAC_TCR_TSEVENTENA; - break; - case OSI_MAC_TCR_TSMASTERENA: - mac_tcr |= OSI_MAC_TCR_TSMASTERENA; - break; - case OSI_MAC_TCR_TSVER2ENA: - mac_tcr |= OSI_MAC_TCR_TSVER2ENA; - break; - case OSI_MAC_TCR_TSIPENA: - mac_tcr |= OSI_MAC_TCR_TSIPENA; - break; - case OSI_MAC_TCR_AV8021ASMEN: - mac_tcr |= OSI_MAC_TCR_AV8021ASMEN; - break; - case OSI_MAC_TCR_TSENALL: - mac_tcr |= OSI_MAC_TCR_TSENALL; - break; - default: - /* To avoid MISRA violation */ - mac_tcr |= mac_tcr; - break; - } } eqos_core_safety_writel(osi_core, mac_tcr, @@ -3154,12 +3155,12 @@ static void eqos_config_tscr(struct osi_core_priv_data *const osi_core, * - Run time: Yes * - De-initialization: No */ -static void eqos_config_ssir(struct osi_core_priv_data *const osi_core) +static void eqos_config_ssir(struct osi_core_priv_data *const osi_core, + const unsigned int ptp_clock) { nveul64_t val; nveu32_t mac_tcr; void *addr = osi_core->base; - nveu32_t ptp_clock = osi_core->ptp_config.ptp_clock; mac_tcr = osi_readla(osi_core, (nveu8_t *)addr + EQOS_MAC_TCR); diff --git a/osi/core/ivc_core.c b/osi/core/ivc_core.c index 137e680..118d66d 100644 --- a/osi/core/ivc_core.c +++ b/osi/core/ivc_core.c @@ -815,9 +815,9 @@ static void ivc_config_tscr(struct osi_core_priv_data *const osi_core, * * @note MAC should be init and started. see osi_start_mac() */ -static void ivc_config_ssir(struct osi_core_priv_data *const osi_core) +static void ivc_config_ssir(struct osi_core_priv_data *const osi_core, + const unsigned int ptp_clock) { - nveu32_t ptp_clock = osi_core->ptp_config.ptp_clock; ivc_msg_common msg_common; nve32_t index = 0; diff --git a/osi/core/mgbe_core.c b/osi/core/mgbe_core.c index a0dcf41..fdbc0fd 100644 --- a/osi/core/mgbe_core.c +++ b/osi/core/mgbe_core.c @@ -369,7 +369,6 @@ err_dma_chan: return ret; } - /** * @brief mgbe_update_mac_addr_low_high_reg- Update L2 address in filter * register @@ -3382,6 +3381,416 @@ static int mgbe_get_hw_features(struct osi_core_priv_data *osi_core, return 0; } +/** + * @brief mgbe_poll_for_tsinit_complete - Poll for time stamp init complete + * + * Algorithm: Read TSINIT value from MAC TCR register until it is + * equal to zero. + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] mac_tcr: Address to store time stamp control register read value + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +static inline int mgbe_poll_for_tsinit_complete( + struct osi_core_priv_data *osi_core, + unsigned int *mac_tcr) +{ + unsigned int retry = 0U; + + while (retry < OSI_POLL_COUNT) { + /* Read and Check TSINIT in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)osi_core->base + + MGBE_MAC_TCR); + if ((*mac_tcr & MGBE_MAC_TCR_TSINIT) == 0U) { + return 0; + } + + retry++; + osi_core->osd_ops.udelay(OSI_DELAY_1000US); + } + + return -1; +} + +/** + * @brief mgbe_set_systime - Set system time + * + * Algorithm: Updates system time (seconds and nano seconds) + * in hardware registers + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] sec: Seconds to be configured + * @param[in] nsec: Nano Seconds to be configured + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +static int mgbe_set_systime_to_mac(struct osi_core_priv_data *osi_core, + unsigned int sec, + unsigned int nsec) +{ + unsigned int mac_tcr; + void *addr = osi_core->base; + int ret; + + /* To be sure previous write was flushed (if Any) */ + ret = mgbe_poll_for_tsinit_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + /* write seconds value to MAC_System_Time_Seconds_Update register */ + osi_writel(sec, (unsigned char *)addr + MGBE_MAC_STSUR); + + /* write nano seconds value to MAC_System_Time_Nanoseconds_Update + * register + */ + osi_writel(nsec, (unsigned char *)addr + MGBE_MAC_STNSUR); + + /* issue command to update the configured secs and nsecs values */ + mac_tcr |= MGBE_MAC_TCR_TSINIT; + osi_writel(mac_tcr, (unsigned char *)addr + MGBE_MAC_TCR); + + ret = mgbe_poll_for_tsinit_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * @brief mgbe_poll_for_addend_complete - Poll for addend value write complete + * + * Algorithm: Read TSADDREG value from MAC TCR register until it is + * equal to zero. + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] mac_tcr: Address to store time stamp control register read value + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +static inline int mgbe_poll_for_addend_complete( + struct osi_core_priv_data *osi_core, + unsigned int *mac_tcr) +{ + unsigned int retry = 0U; + + /* Poll */ + while (retry < OSI_POLL_COUNT) { + /* Read and Check TSADDREG in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)osi_core->base + + MGBE_MAC_TCR); + if ((*mac_tcr & MGBE_MAC_TCR_TSADDREG) == 0U) { + return 0; + } + + retry++; + osi_core->osd_ops.udelay(OSI_DELAY_1000US); + } + + return -1; +} + +/** + * @brief mgbe_config_addend - Configure addend + * + * Algorithm: Updates the Addend value in HW register + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] addend: Addend value to be configured + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +static int mgbe_config_addend(struct osi_core_priv_data *osi_core, + unsigned int addend) +{ + unsigned int mac_tcr; + void *addr = osi_core->base; + int ret; + + /* To be sure previous write was flushed (if Any) */ + ret = mgbe_poll_for_addend_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + /* write addend value to MAC_Timestamp_Addend register */ + osi_writel(addend, (unsigned char *)addr + MGBE_MAC_TAR); + + /* issue command to update the configured addend value */ + mac_tcr |= MGBE_MAC_TCR_TSADDREG; + osi_writel(mac_tcr, (unsigned char *)addr + MGBE_MAC_TCR); + + ret = mgbe_poll_for_addend_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * @brief mgbe_poll_for_update_ts_complete - Poll for update time stamp + * + * Algorithm: Read time stamp update value from TCR register until it is + * equal to zero. + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] mac_tcr: Address to store time stamp control register read value + * + * @note MAC should be init and started. see osi_start_mac() + * + * @retval 0 on success + * @retval -1 on failure. + */ +static inline int mgbe_poll_for_update_ts_complete(struct osi_core_priv_data *osi_core, + unsigned int *mac_tcr) +{ + unsigned int retry = 0U; + + while (retry < OSI_POLL_COUNT) { + /* Read and Check TSUPDT in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)osi_core->base + + MGBE_MAC_TCR); + if ((*mac_tcr & MGBE_MAC_TCR_TSUPDT) == 0U) { + return 0; + } + + retry++; + osi_core->osd_ops.udelay(OSI_DELAY_1000US); + } + + return -1; +} + +/** + * @brief mgbe_adjust_mactime - Adjust MAC time with system time + * + * Algorithm: Update MAC time with system time + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] sec: Seconds to be configured + * @param[in] nsec: Nano seconds to be configured + * @param[in] add_sub: To decide on add/sub with system time + * @param[in] one_nsec_accuracy: One nano second accuracy + * + * @note 1) MAC should be init and started. see osi_start_mac() + * 2) osi_core->ptp_config.one_nsec_accuracy need to be set to 1 + * + * @retval 0 on success + * @retval -1 on failure. + */ +static int mgbe_adjust_mactime(struct osi_core_priv_data *osi_core, + unsigned int sec, unsigned int nsec, + unsigned int add_sub, + unsigned int one_nsec_accuracy) +{ + void *addr = osi_core->base; + unsigned int mac_tcr; + unsigned int value = 0; + unsigned long long temp = 0; + int ret; + + /* To be sure previous write was flushed (if Any) */ + ret = mgbe_poll_for_update_ts_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + if (add_sub != 0U) { + /* If the new sec value needs to be subtracted with + * the system time, then MAC_STSUR reg should be + * programmed with (2^32 – ) + */ + temp = (TWO_POWER_32 - sec); + if (temp < UINT_MAX) { + sec = (unsigned int)temp; + } else { + /* do nothing here */ + } + + /* If the new nsec value need to be subtracted with + * the system time, then MAC_STNSUR.TSSS field should be + * programmed with, (10^9 - ) if + * MAC_TCR.TSCTRLSSR is set or + * (2^32 - if MAC_TCR.TSCTRLSSR is reset) + */ + if (one_nsec_accuracy == OSI_ENABLE) { + if (nsec < UINT_MAX) { + nsec = (TEN_POWER_9 - nsec); + } + } else { + if (nsec < UINT_MAX) { + nsec = (TWO_POWER_31 - nsec); + } + } + } + + /* write seconds value to MAC_System_Time_Seconds_Update register */ + osi_writel(sec, (unsigned char *)addr + MGBE_MAC_STSUR); + + /* write nano seconds value and add_sub to + * MAC_System_Time_Nanoseconds_Update register + */ + value |= nsec; + value |= (add_sub << MGBE_MAC_STNSUR_ADDSUB_SHIFT); + osi_writel(value, (unsigned char *)addr + MGBE_MAC_STNSUR); + + /* issue command to initialize system time with the value + * specified in MAC_STSUR and MAC_STNSUR + */ + mac_tcr |= MGBE_MAC_TCR_TSUPDT; + osi_writel(mac_tcr, (unsigned char *)addr + MGBE_MAC_TCR); + + ret = mgbe_poll_for_update_ts_complete(osi_core, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * @brief mgbe_config_tscr - Configure Time Stamp Register + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * @param[in] ptp_filter: PTP rx filter parameters + * + * @note MAC should be init and started. see osi_start_mac() + */ +static void mgbe_config_tscr(struct osi_core_priv_data *osi_core, + unsigned int ptp_filter) +{ + unsigned int mac_tcr = 0; + void *addr = osi_core->base; + + if (ptp_filter != OSI_DISABLE) { + mac_tcr = (OSI_MAC_TCR_TSENA | + OSI_MAC_TCR_TSCFUPDT | + OSI_MAC_TCR_TSCTRLSSR); + + if ((ptp_filter & OSI_MAC_TCR_SNAPTYPSEL_1) == + OSI_MAC_TCR_SNAPTYPSEL_1) { + mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_1; + } + if ((ptp_filter & OSI_MAC_TCR_SNAPTYPSEL_2) == + OSI_MAC_TCR_SNAPTYPSEL_2) { + mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_2; + } + if ((ptp_filter & OSI_MAC_TCR_SNAPTYPSEL_3) == + OSI_MAC_TCR_SNAPTYPSEL_3) { + mac_tcr |= OSI_MAC_TCR_SNAPTYPSEL_3; + } + if ((ptp_filter & OSI_MAC_TCR_TSIPV4ENA) == + OSI_MAC_TCR_TSIPV4ENA) { + mac_tcr |= OSI_MAC_TCR_TSIPV4ENA; + } + if ((ptp_filter & OSI_MAC_TCR_TSIPV6ENA) == + OSI_MAC_TCR_TSIPV6ENA) { + mac_tcr |= OSI_MAC_TCR_TSIPV6ENA; + } + if ((ptp_filter & OSI_MAC_TCR_TSEVENTENA) == + OSI_MAC_TCR_TSEVENTENA) { + mac_tcr |= OSI_MAC_TCR_TSEVENTENA; + } + if ((ptp_filter & OSI_MAC_TCR_TSMASTERENA) == + OSI_MAC_TCR_TSMASTERENA) { + mac_tcr |= OSI_MAC_TCR_TSMASTERENA; + } + if ((ptp_filter & OSI_MAC_TCR_TSVER2ENA) == + OSI_MAC_TCR_TSVER2ENA) { + mac_tcr |= OSI_MAC_TCR_TSVER2ENA; + } + if ((ptp_filter & OSI_MAC_TCR_TSIPENA) == + OSI_MAC_TCR_TSIPENA) { + mac_tcr |= OSI_MAC_TCR_TSIPENA; + } + if ((ptp_filter & OSI_MAC_TCR_AV8021ASMEN) == + OSI_MAC_TCR_AV8021ASMEN) { + mac_tcr |= OSI_MAC_TCR_AV8021ASMEN; + } + if ((ptp_filter & OSI_MAC_TCR_TSENALL) == + OSI_MAC_TCR_TSENALL) { + mac_tcr |= OSI_MAC_TCR_TSENALL; + } + if ((ptp_filter & OSI_MAC_TCR_CSC) == + OSI_MAC_TCR_CSC) { + mac_tcr |= OSI_MAC_TCR_CSC; + } + } else { + /* Disabling the MAC time stamping */ + mac_tcr = OSI_DISABLE; + } + + osi_writel(mac_tcr, (unsigned char *)addr + MGBE_MAC_TCR); +} + +/** + * @brief mgbe_config_ssir - Configure SSIR + * + * @param[in] addr: Base address indicating the start of + * memory mapped IO region of the MAC. + * it compiled earlier + * @param[in] ptp_clock: PTP required clock frequency + * + * @note MAC should be init and started. see osi_start_mac() + */ +static void mgbe_config_ssir(struct osi_core_priv_data *const osi_core, + const unsigned int ptp_clock) +{ + unsigned long long val; + unsigned int mac_tcr; + void *addr = osi_core->base; + + mac_tcr = osi_readl((unsigned char *)addr + MGBE_MAC_TCR); + + /* convert the PTP required clock frequency to nano second. + * formula is : ((1/ptp_clock) * 1000000000) + * where, ptp_clock = OSI_PTP_REQ_CLK_FREQ if FINE correction + * and ptp_clock = PTP reference clock if COARSE correction + */ + + if ((mac_tcr & MGBE_MAC_TCR_TSCFUPDT) == MGBE_MAC_TCR_TSCFUPDT) { + val = ((1U * OSI_NSEC_PER_SEC) / OSI_PTP_REQ_CLK_FREQ); + } else { + val = ((1U * OSI_NSEC_PER_SEC) / ptp_clock); + } + + /* 0.465ns accurecy */ + if ((mac_tcr & MGBE_MAC_TCR_TSCTRLSSR) == 0U) { + if (val < UINT_MAX) { + val = (val * 1000U) / 465U; + } + } + + val |= (val << MGBE_MAC_SSIR_SSINC_SHIFT); + /* update Sub-second Increment Value */ + if (val < UINT_MAX) { + osi_writel((unsigned int)val, + (unsigned char *)addr + MGBE_MAC_SSIR); + } +} + /** * @brief mgbe_init_core_ops - Initialize MGBE MAC core operations */ @@ -3421,11 +3830,11 @@ void mgbe_init_core_ops(struct core_ops *ops) ops->update_l4_port_no = mgbe_update_l4_port_no; ops->config_vlan_filtering = mgbe_config_vlan_filtering; ops->update_vlan_id = mgbe_update_vlan_id; - ops->set_systime_to_mac = OSI_NULL; - ops->config_addend = OSI_NULL; - ops->adjust_mactime = OSI_NULL, - ops->config_tscr = OSI_NULL; - ops->config_ssir = OSI_NULL; + ops->set_systime_to_mac = mgbe_set_systime_to_mac; + ops->config_addend = mgbe_config_addend; + ops->adjust_mactime = mgbe_adjust_mactime; + ops->config_tscr = mgbe_config_tscr; + ops->config_ssir = mgbe_config_ssir, ops->config_ptp_rxq = mgbe_config_ptp_rxq; ops->write_phy_reg = mgbe_write_phy_reg; ops->read_phy_reg = mgbe_read_phy_reg; diff --git a/osi/core/mgbe_core.h b/osi/core/mgbe_core.h index 3635d24..4f8d074 100644 --- a/osi/core/mgbe_core.h +++ b/osi/core/mgbe_core.h @@ -377,6 +377,16 @@ #define MGBE_MTL_RXQ_SIZE_SHIFT 16U #define MGBE_MAC_RMCR_GPSL_MSK 0x3FFF0000U #define MGBE_MTL_RXQ_OP_MODE_FEP OSI_BIT(4) +#define MGBE_MAC_TCR_TSCFUPDT OSI_BIT(1) +#define MGBE_MAC_TCR_TSINIT OSI_BIT(2) +#define MGBE_MAC_TCR_TSUPDT OSI_BIT(3) +#define MGBE_MAC_TCR_TSADDREG OSI_BIT(5) +#define MGBE_MAC_TCR_TSCTRLSSR OSI_BIT(9) +#define MGBE_MAC_TCR_TSENMACADDR OSI_BIT(18) +#define MGBE_MAC_STNSUR_ADDSUB_SHIFT 31U +#define MGBE_MAC_SSIR_SSINC_SHIFT 16U +#define MGBE_MAC_STNSR_TSSS_MASK 0x7FFFFFFFU +#define MGBE_MAC_TCR_SNAPTYPSEL_SHIFT 16 #define MGBE_MAC_QX_TX_FLW_CTRL_TFE OSI_BIT(1) #define MGBE_MAC_RX_FLW_CTRL_RFE OSI_BIT(0) #define MGBE_MAC_PAUSE_TIME 0xFFFF0000U diff --git a/osi/core/osi_core.c b/osi/core/osi_core.c index 8216b95..507e383 100644 --- a/osi/core/osi_core.c +++ b/osi/core/osi_core.c @@ -667,7 +667,7 @@ nve32_t osi_ptp_configuration(struct osi_core_priv_data *const osi_core, ops_p->config_tscr(osi_core, osi_core->ptp_config.ptp_filter); /* Program Sub Second Increment Register */ - ops_p->config_ssir(osi_core); + ops_p->config_ssir(osi_core, osi_core->ptp_config.ptp_clock); /* formula for calculating addend value is * TSAR = (2^32 * 1000) / (ptp_ref_clk_rate in MHz * SSINC) diff --git a/osi/dma/dma_local.h b/osi/dma/dma_local.h index c07e0e1..3a0fca7 100644 --- a/osi/dma/dma_local.h +++ b/osi/dma/dma_local.h @@ -101,6 +101,11 @@ struct desc_ops { /** Called to get rx HASH from descriptor */ void (*get_rx_hash)(struct osi_rx_desc *rx_desc, struct osi_rx_pkt_cx *rx_pkt_cx); + /** Called to get RX hw timestamp */ + int (*get_rx_hwstamp)(struct osi_dma_priv_data *osi_dma, + struct osi_rx_desc *rx_desc, + struct osi_rx_desc *context_desc, + struct osi_rx_pkt_cx *rx_pkt_cx); }; /** diff --git a/osi/dma/eqos_desc.c b/osi/dma/eqos_desc.c index 42fc363..89bdee5 100644 --- a/osi/dma/eqos_desc.c +++ b/osi/dma/eqos_desc.c @@ -175,6 +175,70 @@ static void eqos_get_rx_hash(struct osi_rx_desc *rx_desc, { } +/** + * @brief eqos_get_rx_hwstamp - Get Rx HW Time stamp + * + * Algorithm: + * 1) Check for TS availability. + * 2) call get_tx_tstamp_status if TS is valid or not. + * 3) If yes, set a bit and update nano seconds in rx_pkt_cx so that OSD + * layer can extract the time by checking this bit. + * + * @param[in] rx_desc: Rx descriptor + * @param[in] context_desc: Rx context descriptor + * @param[in] rx_pkt_cx: Rx packet context + * + * @retval -1 if TimeStamp is not available + * @retval 0 if TimeStamp is available. + */ +static int eqos_get_rx_hwstamp(struct osi_dma_priv_data *osi_dma, + struct osi_rx_desc *rx_desc, + struct osi_rx_desc *context_desc, + struct osi_rx_pkt_cx *rx_pkt_cx) +{ + int retry; + + /* Check for RS1V/TSA/TD valid */ + if (((rx_desc->rdes3 & RDES3_RS1V) == RDES3_RS1V) && + ((rx_desc->rdes1 & RDES1_TSA) == RDES1_TSA) && + ((rx_desc->rdes1 & RDES1_TD) == 0U)) { + for (retry = 0; retry < 10; retry++) { + if (((context_desc->rdes3 & RDES3_OWN) == 0U) && + ((context_desc->rdes3 & RDES3_CTXT) == + RDES3_CTXT)) { + if ((context_desc->rdes0 == + OSI_INVALID_VALUE) && + (context_desc->rdes1 == + OSI_INVALID_VALUE)) { + return -1; + } + /* Update rx pkt context flags to indicate + * PTP */ + rx_pkt_cx->flags |= OSI_PKT_CX_PTP; + /* Time Stamp can be read */ + break; + } else { + /* TS not available yet, so retrying */ + osi_dma->osd_ops.udelay(OSI_DELAY_1US); + } + } + if (retry == 10) { + /* Timed out waiting for Rx timestamp */ + return -1; + } + + rx_pkt_cx->ns = context_desc->rdes0 + + (OSI_NSEC_PER_SEC * context_desc->rdes1); + if (rx_pkt_cx->ns < context_desc->rdes0) { + /* Will not hit this case */ + return -1; + } + } else { + return -1; + } + + return 0; +} void eqos_init_desc_ops(struct desc_ops *d_ops) { @@ -182,4 +246,5 @@ void eqos_init_desc_ops(struct desc_ops *d_ops) d_ops->update_rx_err_stats = eqos_update_rx_err_stats; d_ops->get_rx_vlan = eqos_get_rx_vlan; d_ops->get_rx_hash = eqos_get_rx_hash; + d_ops->get_rx_hwstamp = eqos_get_rx_hwstamp; } diff --git a/osi/dma/hw_desc.h b/osi/dma/hw_desc.h index 239a2cc..45cf896 100644 --- a/osi/dma/hw_desc.h +++ b/osi/dma/hw_desc.h @@ -35,6 +35,7 @@ #define RDES3_CTXT OSI_BIT(30) #define RDES3_IOC OSI_BIT(30) #define RDES3_B1V OSI_BIT(24) +#define RDES3_CDA OSI_BIT(27) #define RDES3_LD OSI_BIT(28) #define RDES3_FD OSI_BIT(29) #define RDES3_ERR_CRC OSI_BIT(24) @@ -50,14 +51,16 @@ #define RDES3_RS0V OSI_BIT(25) #define RDES3_RS1V OSI_BIT(26) #define RDES3_RSV OSI_BIT(26) +#define RDES0_OVT 0x0000FFFFU +#define RDES3_TSD OSI_BIT(6) +#define RDES3_TSA OSI_BIT(4) +#define RDES1_TSA OSI_BIT(14) +#define RDES1_TD OSI_BIT(15) #define RDES3_L34T 0x00F00000U #define RDES3_L34T_IPV4_TCP OSI_BIT(20) #define RDES3_L34T_IPV4_UDP OSI_BIT(21) #define RDES3_L34T_IPV6_TCP (OSI_BIT(23) | OSI_BIT(20)) #define RDES3_L34T_IPV6_UDP (OSI_BIT(23) | OSI_BIT(21)) -#define RDES0_OVT 0x0000FFFFU -#define RDES1_TSA OSI_BIT(14) -#define RDES1_TD OSI_BIT(15) #define RDES1_IPCE OSI_BIT(7) #define RDES1_IPCB OSI_BIT(6) @@ -96,6 +99,7 @@ #define TDES3_TCMSSV OSI_BIT(26) #define TDES3_FD OSI_BIT(29) #define TDES3_LD OSI_BIT(28) +#define TDES3_OSTC OSI_BIT(27) #define TDES3_TSE OSI_BIT(18) #define TDES3_HW_CIC_ALL (OSI_BIT(16) | OSI_BIT(17)) #define TDES3_HW_CIC_IP_ONLY (OSI_BIT(16)) @@ -106,6 +110,7 @@ #define TDES3_THL_SHIFT 19U #define TDES3_VLTV OSI_BIT(16) #define TDES3_TTSS OSI_BIT(17) +#define TDES3_PIDV OSI_BIT(25) /* Tx Errors */ #define TDES3_IP_HEADER_ERR OSI_BIT(0) diff --git a/osi/dma/mgbe_desc.c b/osi/dma/mgbe_desc.c index a94008c..12f12ee 100644 --- a/osi/dma/mgbe_desc.c +++ b/osi/dma/mgbe_desc.c @@ -132,10 +132,73 @@ static void mgbe_get_rx_hash(struct osi_rx_desc *rx_desc, rx_pkt_cx->flags |= OSI_PKT_CX_RSS; } +/** + * @brief mgbe_get_rx_hwstamp - Get Rx HW Time stamp + * + * Algorithm: + * 1) Check for TS availability. + * 2) call get_tx_tstamp_status if TS is valid or not. + * 3) If yes, set a bit and update nano seconds in rx_pkt_cx so that OSD + * layer can extract the time by checking this bit. + * + * @param[in] rx_desc: Rx descriptor + * @param[in] context_desc: Rx context descriptor + * @param[in] rx_pkt_cx: Rx packet context + * + * @retval -1 if TimeStamp is not available + * @retval 0 if TimeStamp is available. + */ +static int mgbe_get_rx_hwstamp(struct osi_dma_priv_data *osi_dma, + struct osi_rx_desc *rx_desc, + struct osi_rx_desc *context_desc, + struct osi_rx_pkt_cx *rx_pkt_cx) +{ + int retry; + + if ((rx_desc->rdes3 & RDES3_CDA) != RDES3_CDA) { + return -1; + } + + for (retry = 0; retry < 10; retry++) { + if (((context_desc->rdes3 & RDES3_OWN) == 0U) && + ((context_desc->rdes3 & RDES3_CTXT) == RDES3_CTXT) && + ((context_desc->rdes3 & RDES3_TSA) == RDES3_TSA) && + ((context_desc->rdes3 & RDES3_TSD) != RDES3_TSD)) { + if ((context_desc->rdes0 == OSI_INVALID_VALUE) && + (context_desc->rdes1 == OSI_INVALID_VALUE)) { + /* Invalid time stamp */ + return -1; + } + /* Update rx pkt context flags to indicate PTP */ + rx_pkt_cx->flags |= OSI_PKT_CX_PTP; + /* Time Stamp can be read */ + break; + } else { + /* TS not available yet, so retrying */ + osi_dma->osd_ops.udelay(OSI_DELAY_1US); + } + } + + if (retry == 10) { + /* Timed out waiting for Rx timestamp */ + return -1; + } + + rx_pkt_cx->ns = context_desc->rdes0 + + (OSI_NSEC_PER_SEC * context_desc->rdes1); + if (rx_pkt_cx->ns < context_desc->rdes0) { + /* Will not hit this case */ + return -1; + } + + return 0; +} + void mgbe_init_desc_ops(struct desc_ops *d_ops) { d_ops->get_rx_csum = mgbe_get_rx_csum; d_ops->update_rx_err_stats = mgbe_update_rx_err_stats; d_ops->get_rx_vlan = mgbe_get_rx_vlan; d_ops->get_rx_hash = mgbe_get_rx_hash; + d_ops->get_rx_hwstamp = mgbe_get_rx_hwstamp; } diff --git a/osi/dma/mgbe_dma.h b/osi/dma/mgbe_dma.h index 04e4e4c..480db86 100644 --- a/osi/dma/mgbe_dma.h +++ b/osi/dma/mgbe_dma.h @@ -23,6 +23,17 @@ #ifndef INCLUDED_MGBE_DMA_H #define INCLUDED_MGBE_DMA_H +/** + * @@addtogroup Timestamp Capture Register + * @brief MGBE MAC Timestamp Register offset + * @{ + */ +#define MGBE_MAC_TSS 0X0D20 +#define MGBE_MAC_TS_NSEC 0x0D30 +#define MGBE_MAC_TS_SEC 0x0D34 +#define MGBE_MAC_TS_PID 0x0D38 +/** @} */ + /** * @addtogroup MGBE_DMA DMA Channel Register offsets * @@ -95,4 +106,24 @@ #define MGBE_VIRT_INTR_CHX_CNTRL_TX OSI_BIT(0) #define MGBE_VIRT_INTR_CHX_CNTRL_RX OSI_BIT(1) /** @} */ -#endif /* INCLUDED_MGBE_DMA_H */ + +/** + * @addtogroup MGBE MAC timestamp registers bit field. + * + * @brief Values defined for the MGBE timestamp registers + * @{ + */ +#define MGBE_MAC_TSS_TXTSC OSI_BIT(15) +#define MGBE_MAC_TS_PID_MASK 0x3FFU +#define MGBE_MAC_TS_NSEC_MASK 0x7FFFFFFFU +/** @} */ + +/** + * @brief mgbe_get_dma_chan_ops - MGBE get DMA channel operations + * + * Algorithm: Returns pointer DMA channel operations structure. + * + * @returns Pointer to DMA channel operations structure + */ +struct osi_dma_chan_ops *mgbe_get_dma_chan_ops(void); +#endif diff --git a/osi/dma/osi_dma_local.h b/osi/dma/osi_dma_local.h index 52c6221..962df94 100644 --- a/osi/dma/osi_dma_local.h +++ b/osi/dma/osi_dma_local.h @@ -44,6 +44,10 @@ struct desc_ops { /** Called to get rx HASH from descriptor */ void (*get_rx_hash)(struct osi_rx_desc *rx_desc, struct osi_rx_pkt_cx *rx_pkt_cx); + /** Called to get RX hw timestamp */ + int (*get_rx_hwstamp)(struct osi_rx_desc *rx_desc, + struct osi_rx_desc *context_desc, + struct osi_rx_pkt_cx *rx_pkt_cx); }; /** diff --git a/osi/dma/osi_dma_txrx.c b/osi/dma/osi_dma_txrx.c index a911fd8..5abb19c 100644 --- a/osi/dma/osi_dma_txrx.c +++ b/osi/dma/osi_dma_txrx.c @@ -25,119 +25,10 @@ #include "../osi/common/type.h" #include "hw_desc.h" #include "../osi/common/common.h" +#include "mgbe_dma.h" static struct desc_ops d_ops; -/** - * @brief get_rx_tstamp_status - Get Tx Time stamp status - * - * @note - * Algorithm: - * - Check if the received descriptor is a context descriptor. - * - If yes, check whether the time stamp is valid or not. - * - * @param[in] context_desc: Rx context descriptor - * - * @note - * API Group: - * - Initialization: No - * - Run time: Yes - * - De-initialization: No - * - * @retval -1 if TimeStamp is not valid - * @retval 0 if TimeStamp is valid. - */ -static inline nve32_t get_rx_tstamp_status(struct osi_rx_desc *context_desc) -{ - if (((context_desc->rdes3 & RDES3_OWN) != RDES3_OWN) && - ((context_desc->rdes3 & RDES3_CTXT) == RDES3_CTXT)) { - if (((context_desc->rdes0 == OSI_INVALID_VALUE) && - (context_desc->rdes1 == OSI_INVALID_VALUE))) { - /* Invalid time stamp */ - return -1; - } - /* tstamp can be read */ - return 0; - } - /* Busy */ - return -2; -} - -/** - * @brief get_rx_hwstamp - Get Rx HW Time stamp - * - * @note - * Algorithm: - * - Check for TS availability. - * - call get_tx_tstamp_status if TS is valid or not. - * - If yes, set a bit and update nano seconds in rx_pkt_cx so that OSD - * layer can extract the time by checking this bit. - * - * @param[in] osi_dma: OSI private data structure. - * @param[in] rx_desc: Rx descriptor - * @param[in] context_desc: Rx context descriptor - * @param[in, out] rx_pkt_cx: Rx packet context - * - * @note - * API Group: - * - Initialization: No - * - Run time: Yes - * - De-initialization: No - * - * @retval -1 if TimeStamp is not available - * @retval 0 if TimeStamp is available. - */ -static nve32_t get_rx_hwstamp(struct osi_dma_priv_data *osi_dma, - struct osi_rx_desc *rx_desc, - struct osi_rx_desc *context_desc, - struct osi_rx_pkt_cx *rx_pkt_cx) -{ - nve32_t retry, ret = -1; - - /* Check for RS1V/TSA/TD valid */ - if (((rx_desc->rdes3 & RDES3_RS1V) == RDES3_RS1V) && - ((rx_desc->rdes1 & RDES1_TSA) == RDES1_TSA) && - ((rx_desc->rdes1 & RDES1_TD) != RDES1_TD)) { - for (retry = 0; retry < 10; retry++) { - ret = get_rx_tstamp_status(context_desc); - if (ret == 0) { - /* Update rx pkt context flags to indicate PTP */ - rx_pkt_cx->flags |= OSI_PKT_CX_PTP; - /* Time Stamp can be read */ - break; - } else if (ret != -2) { - /* Failed to get Rx timestamp */ - return ret; - } else { - /* Do nothing here */ - } - /* TS not available yet, so retrying */ - osi_dma->osd_ops.udelay(1U); - } - if (ret != 0) { - /* Timed out waiting for Rx timestamp */ - return ret; - } - - if (OSI_NSEC_PER_SEC > (OSI_ULLONG_MAX / context_desc->rdes1)) { - /* Will not hit this case */ - } else if ((OSI_ULLONG_MAX - - (context_desc->rdes1 * OSI_NSEC_PER_SEC)) < - context_desc->rdes0) { - /* Will not hit this case */ - } else { - rx_pkt_cx->ns = context_desc->rdes0 + - (OSI_NSEC_PER_SEC * context_desc->rdes1); - } - - if (rx_pkt_cx->ns < context_desc->rdes0) { - /* Will not hit this case */ - return -1; - } - } - return ret; -} - /** * @brief get_rx_err_stats - Detect Errors from Rx Descriptor * @@ -339,8 +230,8 @@ nve32_t osi_process_rx_completions(struct osi_dma_priv_data *osi_dma, context_desc = rx_ring->rx_desc + rx_ring->cur_rx_idx; /* Get rx time stamp */ - ret = get_rx_hwstamp(osi_dma, rx_desc, context_desc, - rx_pkt_cx); + ret =d_ops.get_rx_hwstamp(osi_dma, rx_desc, + context_desc, rx_pkt_cx); if (ret == 0) { ptp_rx_swcx = rx_ring->rx_swcx + rx_ring->cur_rx_idx; @@ -616,8 +507,121 @@ static inline nve32_t validate_tx_completions_arg( return 0; } -nve32_t osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, - nveu32_t chan, nve32_t budget) +/** + * @brief poll_for_ts_update - Poll for TXTSC bit set for timestamp capture + * + * Algorithm: This routine will be invoked by get_mac_tx_timestamp to poll + * on TXTSC bit to get set or timedout. + * + * @param[in] addr: Base address + * @param[in] chan: Current counter value + * + * @retval -1 on failure + * @retval 0 on success + */ +static inline int poll_for_ts_update(struct osi_dma_priv_data *osi_dma, + unsigned int *count) +{ + unsigned int retry = OSI_POLL_COUNT; + unsigned int val = 0U; + + while (*count < retry) { + /* Read and Check TXTSC in MAC_Timestamp_Control register */ + val = osi_readl((unsigned char *)osi_dma->base + + MGBE_MAC_TSS); + if ((val & MGBE_MAC_TSS_TXTSC) == MGBE_MAC_TSS_TXTSC) { + return 0; + } + (*count)++; + osi_dma->osd_ops.udelay(OSI_DELAY_1US); + } + + return -1; +} + +/** + * @brief get_mac_tx_timestamp - get TX timestamp from timestamp capture + * registers + * + * Algorithm: This routine will be invoked on TX_DONE interrupt and if hw + * timestamp capture enabled for that descriptor. SW will check for Packet + * id maching with dma channel number as for same DMA all tx are FIFO. If match + * update hwtimestamp into local variables. + * + * @param[in] osi: OSI private data structure. + * @param[in] tx_desc: Pointer to tranmit descriptor. + * @param[out] txdone_pkt_cx: Pointer to txdone packet descriptor to be filled + * @param[in] chan: Rx channel number. + * + */ +static void get_mac_tx_timestamp(struct osi_dma_priv_data *osi_dma, + struct osi_tx_desc *tx_desc, + struct osi_txdone_pkt_cx *txdone_pkt_cx, + unsigned int chan) +{ + unsigned char *addr = (unsigned char *)osi_dma->base; + int ret = -1; + int found = 1; + unsigned int count = 0; + unsigned long long var = 0; + + ret = poll_for_ts_update(osi_dma, &count); + if (ret < 0) { + OSI_DMA_ERR(OSI_NULL, OSI_LOG_ARG_HW_FAIL, + "timestamp done failed\n", 0ULL); + found = 0; + } + + /* check if pkt id is also correct for pkt. current implemtation + * use dma channel index as pktid, we will use pktid from index 0 to + * max DMA channels -1 */ + while (found == 1) { + if (((osi_readl(addr + MGBE_MAC_TS_PID) & + MGBE_MAC_TS_PID_MASK) == chan)) { + txdone_pkt_cx->flags |= OSI_TXDONE_CX_TS; + txdone_pkt_cx->ns = osi_readl(addr + MGBE_MAC_TS_NSEC); + txdone_pkt_cx->ns &= MGBE_MAC_TS_NSEC_MASK; + var = osi_readl(addr + MGBE_MAC_TS_SEC); + if (OSI_NSEC_PER_SEC > (OSI_ULLONG_MAX / var)) { + /* Will not hit this case */ + } else if ((OSI_ULLONG_MAX - (var * OSI_NSEC_PER_SEC)) < + txdone_pkt_cx->ns) { + /* Will not hit this case */ + } else { + txdone_pkt_cx->ns += var * OSI_NSEC_PER_SEC; + } + + found = 0; + } else { + OSI_DMA_INFO(OSI_NULL, OSI_LOG_ARG_HW_FAIL, + "packet ID mismatch \n", 0ULL); + ret = poll_for_ts_update(osi_dma, &count); + if (ret < 0) { + found = 0; + } + } + } +} + +/** + * @brief is_ptp_twostep_or_slave_mode - check for dut in ptp 2step or slave + * mode + * + * @param[in] ptp_flag: osi statructure variable to identify current ptp + * configuration + * + * @retval 1 if condition is true + * @retval 0 if condition is false. + */ +static inline unsigned int is_ptp_twostep_or_slave_mode(unsigned int ptp_flag) +{ + return (((ptp_flag & OSI_PTP_SYNC_SLAVE) == OSI_PTP_SYNC_SLAVE) || + ((ptp_flag & OSI_PTP_SYNC_TWOSTEP) == OSI_PTP_SYNC_TWOSTEP)) ? + OSI_ENABLE : OSI_DISABLE; +} + +int osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, + unsigned int chan, int budget) { struct osi_tx_ring *tx_ring = OSI_NULL; struct osi_txdone_pkt_cx *txdone_pkt_cx = OSI_NULL; @@ -690,9 +694,19 @@ nve32_t osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, } else { /* Do nothing here */ } + } else if (((tx_swcx->flags & OSI_PKT_CX_PTP) == + OSI_PKT_CX_PTP) && + // if not master in onestep mode + (is_ptp_twostep_or_slave_mode(osi_dma->ptp_flag) == + OSI_ENABLE) && + ((tx_desc->tdes3 & TDES3_CTXT) == 0U)) { + get_mac_tx_timestamp(osi_dma, tx_desc, txdone_pkt_cx, chan); + } else { + /* Do nothing here */ } - if (tx_swcx->is_paged_buf == 1U) { + if ((tx_swcx->flags & OSI_PKT_CX_PAGED_BUF) == + OSI_PKT_CX_PAGED_BUF) { txdone_pkt_cx->flags |= OSI_TXDONE_CX_PAGED_BUF; } @@ -718,7 +732,7 @@ nve32_t osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, tx_swcx->buf_virt_addr = OSI_NULL; tx_swcx->buf_phy_addr = 0; - tx_swcx->is_paged_buf = 0; + tx_swcx->flags = 0; INCR_TX_DESC_INDEX(entry, 1U); /* Don't wait to update tx_ring->clean-idx. It will @@ -743,6 +757,8 @@ nve32_t osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, * * @param[in, out] tx_pkt_cx: Pointer to transmit packet context structure * @param[in, out] tx_desc: Pointer to transmit descriptor to be filled. + * @param[in] sync_mode: PTP sync mode to indetify. + * @param[in] mac: HW MAC ver * * @note * API Group: @@ -753,40 +769,85 @@ nve32_t osi_process_tx_completions(struct osi_dma_priv_data *osi_dma, * @retval 0 - cntx desc not used * @retval 1 - cntx desc used. */ + static inline nve32_t need_cntx_desc(struct osi_tx_pkt_cx *tx_pkt_cx, - struct osi_tx_desc *tx_desc) + struct osi_tx_desc *tx_desc, + unsigned int ptp_sync_flag, + unsigned int mac) { nve32_t ret = 0; if (((tx_pkt_cx->flags & OSI_PKT_CX_VLAN) == OSI_PKT_CX_VLAN) || - ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO)) { - /* Set context type */ - tx_desc->tdes3 |= TDES3_CTXT; + ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO) || + ((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP)) { if ((tx_pkt_cx->flags & OSI_PKT_CX_VLAN) == OSI_PKT_CX_VLAN) { + /* Set context type */ + tx_desc->tdes3 |= TDES3_CTXT; /* Remove any overflow bits. VT field is 16bit field */ tx_pkt_cx->vtag_id &= TDES3_VT_MASK; /* Fill VLAN Tag ID */ tx_desc->tdes3 |= tx_pkt_cx->vtag_id; /* Set VLAN TAG Valid */ tx_desc->tdes3 |= TDES3_VLTV; + ret = 1; } if ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO) { + /* Set context type */ + tx_desc->tdes3 |= TDES3_CTXT; /* Remove any overflow bits. MSS is 13bit field */ tx_pkt_cx->mss &= TDES2_MSS_MASK; /* Fill MSS */ tx_desc->tdes2 |= tx_pkt_cx->mss; /* Set MSS valid */ tx_desc->tdes3 |= TDES3_TCMSSV; + ret = 1; } - ret = 1; + /* This part of code must be at the end of function */ + if ((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) { + if ((mac == OSI_MAC_HW_EQOS) && + ((ptp_sync_flag & OSI_PTP_SYNC_TWOSTEP) == + OSI_PTP_SYNC_TWOSTEP)){ + /* return the current ret value */ + return ret; + } + + /* Set context type */ + tx_desc->tdes3 |= TDES3_CTXT; + /* in case of One-step sync */ + if ((ptp_sync_flag & OSI_PTP_SYNC_ONESTEP) == + OSI_PTP_SYNC_ONESTEP) { + /* Set TDES3_OSTC */ + tx_desc->tdes3 |= TDES3_OSTC; + tx_desc->tdes3 &= ~TDES3_TCMSSV; + } + + ret = 1; + } } return ret; } +/** + * @brief is_ptp_onestep_and_master_mode - check for dut is in master and + * onestep mode + * + * @param[in] ptp_flag: osi statructure variable to identify current ptp + * configuration + * + * @retval 1 if condition is true + * @retval 0 if condition is false. + */ +static inline unsigned int is_ptp_onestep_and_master_mode(unsigned int ptp_flag) +{ + return (((ptp_flag & OSI_PTP_SYNC_MASTER) == OSI_PTP_SYNC_MASTER) && + ((ptp_flag & OSI_PTP_SYNC_ONESTEP) == OSI_PTP_SYNC_ONESTEP)) ? + OSI_ENABLE : OSI_DISABLE; +} + /** * @brief fill_first_desc - Helper function to fill the first transmit * descriptor. @@ -812,7 +873,8 @@ static inline nve32_t need_cntx_desc(struct osi_tx_pkt_cx *tx_pkt_cx, static inline void fill_first_desc(struct osi_tx_ring *tx_ring, struct osi_tx_pkt_cx *tx_pkt_cx, struct osi_tx_desc *tx_desc, - struct osi_tx_swcx *tx_swcx) + struct osi_tx_swcx *tx_swcx, + unsigned int ptp_flag) { nveu64_t tmp; @@ -850,6 +912,12 @@ static inline void fill_first_desc(struct osi_tx_ring *tx_ring, /* if TS is set enable timestamping */ if ((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) { tx_desc->tdes2 |= TDES2_TTSE; + tx_swcx->flags |= OSI_PKT_CX_PTP; + //ptp master mode in one step sync + if (is_ptp_onestep_and_master_mode(ptp_flag) == + OSI_ENABLE) { + tx_desc->tdes2 &= ~TDES2_TTSE; + } } /* if LEN bit is set, update packet payload len */ @@ -954,19 +1022,28 @@ nve32_t hw_transmit(struct osi_dma_priv_data *osi_dma, 1UL); } - cntx_desc_consumed = need_cntx_desc(tx_pkt_cx, tx_desc); + cntx_desc_consumed = need_cntx_desc(tx_pkt_cx, tx_desc, osi_dma->ptp_flag, + osi_dma->mac); if (cntx_desc_consumed == 1) { + if (((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) && + (osi_dma->mac == OSI_MAC_HW_MGBE)) { + /* mark packet id valid */ + tx_desc->tdes3 |= TDES3_PIDV; + /* Packet id */ + tx_desc->tdes0 = chan; + } INCR_TX_DESC_INDEX(entry, 1U); /* Storing context descriptor to set DMA_OWN at last */ cx_desc = tx_desc; tx_desc = tx_ring->tx_desc + entry; tx_swcx = tx_ring->tx_swcx + entry; + desc_cnt--; } /* Fill first descriptor */ - fill_first_desc(tx_ring, tx_pkt_cx, tx_desc, tx_swcx); + fill_first_desc(tx_ring, tx_pkt_cx, tx_desc, tx_swcx, osi_dma->ptp_flag); INCR_TX_DESC_INDEX(entry, 1U); @@ -1262,7 +1339,7 @@ static nve32_t tx_dma_desc_init(struct osi_dma_priv_data *osi_dma, tx_swcx->len = 0; tx_swcx->buf_virt_addr = OSI_NULL; tx_swcx->buf_phy_addr = 0; - tx_swcx->is_paged_buf = 0; + tx_swcx->flags = 0; } tx_ring->cur_tx_idx = 0;