nvethernetrm: mgbe: add PTP support

Change takes care of -
o Enable PTP for MGBE
o Added flags for One step/two step and also
for PTP master/slave
o Getting timestamp from MAC registers for MGBE.

Bug 200565914

Change-Id: I17346451f2619f0526a737a4a6bffdf130af4fc0
Signed-off-by: rakesh goyal <rgoyal@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/kernel/nvethernetrm/+/2314201
Reviewed-by: Bhadram Varka <vbhadram@nvidia.com>
This commit is contained in:
Rakesh Goyal
2020-01-07 20:48:08 +05:30
committed by Bhadram Varka
parent d17a9e4c63
commit f6cbb32a42
19 changed files with 1017 additions and 207 deletions

View File

@@ -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 */

View File

@@ -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

View File

@@ -26,6 +26,19 @@
#include <osi_common.h>
#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;
};

72
osi/common/mgbe_common.c Normal file
View File

@@ -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;
}

38
osi/common/mgbe_common.h Normal file
View File

@@ -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 */

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 <new_sec_value>)
*/
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 - <new_nsec_value>) if
* MAC_TCR.TSCTRLSSR is set or
* (2^32 - <new_nsec_value> 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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
};
/**

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
};
/**

View File

@@ -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;