From efb739e01cf4edad8b5df143c96111da15f1af13 Mon Sep 17 00:00:00 2001 From: Narayan Reddy Date: Wed, 29 May 2019 13:33:51 +0530 Subject: [PATCH] nvethernetrm: add PTP support This takes care of implementing the PTP support which includes PTP V1/V2 over IPV4,IPV6,Ethernet,gPTP. Bug 200524751 Change-Id: Ieb680d818be81c1a1a8349ddd9ff02bba1896b08 Signed-off-by: Narayan Reddy Reviewed-on: https://git-master.nvidia.com/r/2127117 Reviewed-by: svc-mobile-coverity Reviewed-by: svc-mobile-misra GVS: Gerrit_Virtual_Submit Reviewed-by: Srinivas Ramachandran Reviewed-by: mobile promotions Tested-by: mobile promotions --- include/osd.h | 3 +- include/osi_common.h | 28 ++ include/osi_core.h | 201 +++++++++++++- include/osi_dma.h | 7 + include/osi_dma_txrx.h | 5 + osi/core/eqos_core.c | 464 +++++++++++++++++++++++++++++++- osi/core/eqos_core.h | 17 +- osi/core/libnvethernetrm.export | 5 + osi/core/osi_core.c | 274 ++++++++++++++++--- osi/dma/osi_dma_txrx.c | 127 ++++++++- 10 files changed, 1084 insertions(+), 47 deletions(-) diff --git a/include/osd.h b/include/osd.h index 0f87379..6096d2d 100644 --- a/include/osd.h +++ b/include/osd.h @@ -29,7 +29,8 @@ void osd_udelay(unsigned long usec); void osd_info(void *priv, const char *fmt, ...); void osd_err(void *priv, const char *fmt, ...); void osd_receive_packet(void *priv, void *rxring, unsigned int chan, - unsigned int dma_buf_len, void *rxpkt_cx); + unsigned int dma_buf_len, void *rxpkt_cx, + void *rx_pkt_swcx); void osd_transmit_complete(void *priv, void *buffer, unsigned long dmaaddr, unsigned int len, void *txdone_pkt_cx); #endif diff --git a/include/osi_common.h b/include/osi_common.h index 0bbf743..a4b5a5c 100644 --- a/include/osi_common.h +++ b/include/osi_common.h @@ -23,6 +23,15 @@ #ifndef OSI_COMMON_H #define OSI_COMMON_H +#define TEN_POWER_9 0x3B9ACA00U +#define TWO_POWER_32 0x100000000ULL +#define TWO_POWER_31 0x80000000U +#define OSI_NSEC_PER_SEC 1000000000ULL +#define OSI_INVALID_VALUE 0xFFFFFFFFU + +/* System clock is 62.5MHz */ +#define OSI_ETHER_SYSCLOCK 62500000ULL + #define OSI_PAUSE_FRAMES_ENABLE 0U #define OSI_PAUSE_FRAMES_DISABLE 1U #define OSI_FLOW_CTRL_TX OSI_BIT(0) @@ -36,6 +45,25 @@ #ifndef ULONG_MAX #define ULONG_MAX (~0UL) #endif +#ifndef UNIT_MAX +#define UINT_MAX (~0U) +#endif + +/* MAC Time stamp contorl reg bit fields */ +#define OSI_MAC_TCR_TSENA OSI_BIT(0) +#define OSI_MAC_TCR_TSCFUPDT OSI_BIT(1) +#define OSI_MAC_TCR_TSENALL OSI_BIT(8) +#define OSI_MAC_TCR_TSCTRLSSR OSI_BIT(9) +#define OSI_MAC_TCR_TSVER2ENA OSI_BIT(10) +#define OSI_MAC_TCR_TSIPENA OSI_BIT(11) +#define OSI_MAC_TCR_TSIPV6ENA OSI_BIT(12) +#define OSI_MAC_TCR_TSIPV4ENA OSI_BIT(13) +#define OSI_MAC_TCR_TSEVENTENA OSI_BIT(14) +#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_SNAPTYPSEL_3 (OSI_BIT(16) | OSI_BIT(17)) +#define OSI_MAC_TCR_AV8021ASMEN OSI_BIT(28) /* Default maximum Gaint Packet Size Limit */ #define OSI_MAX_MTU_SIZE 9000U diff --git a/include/osi_core.h b/include/osi_core.h index 6f5af66..d911b23 100644 --- a/include/osi_core.h +++ b/include/osi_core.h @@ -146,6 +146,12 @@ struct osi_core_avb_algorithm { * @update_l4_port_no: Called to update L4 Port for filter packet. * @config_vlan_filtering: Called to configure VLAN filtering. * @update_vlan_id: called to update VLAN id. + * @set_systime_to_mac: Called to set current system time to MAC. + * @config_addend: Called to set the addend value to adjust the time. + * @adjust_systime: Called to adjust the system time. + * @get_systime_from_mac: Called to get the current time from MAC. + * @config_tscr: Called to configure the TimeStampControl register. + * @config_ssir: Called to configure the sub second increment register. */ struct osi_core_ops { /* initialize MAC/MTL/DMA Common registers */ @@ -209,6 +215,48 @@ struct osi_core_ops { unsigned int perfect_hash_filtering, unsigned int perfect_inverse_match); int (*update_vlan_id)(void *base, unsigned int vid); + int (*set_systime_to_mac)(void *addr, unsigned int sec, + unsigned int nsec); + int (*config_addend)(void *addr, unsigned int addend); + int (*adjust_systime)(void *addr, unsigned int sec, unsigned int nsec, + unsigned int neg_adj, + unsigned int one_nsec_accuracy); + unsigned long long (*get_systime_from_mac)(void *addr); + void (*config_tscr)(void *addr, unsigned int ptp_filter); + void (*config_ssir)(void *addr, unsigned int ptp_clock); +}; + +/** + * struct osi_ptp_config - PTP configuration + * @ptp_filter: PTP filter parameters bit fields. + * Enable Time stamp,Fine Timestamp,1 nanosecond accuracy are enabled by + * default. + * Need to set below bit fields accordingly as per the requirements. + * Enable Timestamp for All Packets OSI_BIT(8) + * Enable PTP Packet Processing for Version 2 Format OSI_BIT(10) + * Enable Processing of PTP over Ethernet Packets OSI_BIT(11) + * Enable Processing of PTP Packets Sent over IPv6-UDP OSI_BIT(12) + * Enable Processing of PTP Packets Sent over IPv4-UDP OSI_BIT(13) + * Enable Timestamp Snapshot for Event Messages OSI_BIT(14) + * Enable Snapshot for Messages Relevant to Master OSI_BIT(15) + * Select PTP packets for Taking Snapshots OSI_BIT(16) + * Select PTP packets for Taking Snapshots OSI_BIT(17) + * Select PTP packets for Taking Snapshots (OSI_BIT(16) | OSI_BIT(17)) + * AV 802.1AS Mode Enable OSI_BIT(28) + * if ptp_fitler is set to Zero then Time stamping is disabled. + * @sec: Seconds + * @nsec: Nano seconds + * @ptp_ref_clk_rate: PTP reference clock read from DT + * @one_nsec_accuracy: Use one nsec accuracy (need to set 1) + * @ptp_clock: PTP system clock which is 62500000Hz + */ +struct osi_ptp_config { + unsigned int ptp_filter; + unsigned int sec; + unsigned int nsec; + unsigned int ptp_ref_clk_rate; + unsigned int one_nsec_accuracy; + unsigned int ptp_clock; }; /** @@ -228,6 +276,8 @@ struct osi_core_ops { * @mac_addr: Ethernet MAC address. * @pause_frames: DT entry to enable(0) or disable(1) pause frame support * @flow_ctrl: Current flow control settings + * @ptp_config: PTP configuration settings. + * @default_addend: Default addend value. */ struct osi_core_priv_data { void *base; @@ -244,6 +294,8 @@ struct osi_core_priv_data { unsigned char mac_addr[OSI_ETH_ALEN]; unsigned int pause_frames; unsigned int flow_ctrl; + struct osi_ptp_config ptp_config; + unsigned int default_addend; }; /** @@ -797,10 +849,157 @@ int osi_config_l2_da_perfect_inverse_match(struct osi_core_priv_data *osi_core, */ int osi_update_vlan_id(struct osi_core_priv_data *osi_core, unsigned int vid); - +/** + * osi_write_phy_reg - Write to a PHY register through MAC over MDIO bus. + * @osi_core: OSI private data structure. + * @phyaddr: PHY address (PHY ID) associated with PHY + * @phyreg: Register which needs to be write to PHY. + * @phydata: Data to write to a PHY register. + * + * Algorithm: + * 1) Before proceding for reading for PHY register check whether any MII + * operation going on MDIO bus by polling MAC_GMII_BUSY bit. + * 2) Program data into MAC MDIO data register. + * 3) Populate required parameters like phy address, phy register etc,, + * in MAC MDIO Address register. write and GMII busy bits needs to be set + * in this operation. + * 4) Write into MAC MDIO address register poll for GMII busy for MDIO + * operation to complete. + * + * Dependencies: MAC IP should be out of reset + * + * Protection: None + * + * Return: 0 - success, -1 - failure + */ int osi_write_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg, unsigned short phydata); + +/** + * osi_read_phy_reg - Read from a PHY register through MAC over MDIO bus. + * @osi_core: OSI private data structure. + * @phyaddr: PHY address (PHY ID) associated with PHY + * @phyreg: Register which needs to be read from PHY. + * + * Algorithm: + * 1) Before proceding for reading for PHY register check whether any MII + * operation going on MDIO bus by polling MAC_GMII_BUSY bit. + * 2) Populate required parameters like phy address, phy register etc,, + * in program it in MAC MDIO Address register. Read and GMII busy bits + * needs to be set in this operation. + * 3) Write into MAC MDIO address register poll for GMII busy for MDIO + * operation to complete. After this data will be available at MAC MDIO + * data register. + * + * Dependencies: MAC IP should be out of reset + * + * Protection: None + * + * Return: data from PHY register - success, -1 - failure + */ int osi_read_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg); void osi_init_core_ops(struct osi_core_priv_data *osi_core); + +/** + * osi_set_systime_to_mac - Handles setting of system time. + * @osi_core: OSI private data structure. + * @sec: Seconds to be configured. + * @nsec: Nano seconds to be configured. + * + * Algorithm: Set current system time to MAC. + * + * Dependencies: MAC init should be complete. See osi_hw_core_init() and + * osi_hw_dma_init() + * + * Protection: None. + * + * Return: 0 - success, -1 - failure. + */ +int osi_set_systime_to_mac(struct osi_core_priv_data *osi_core, + unsigned int sec, unsigned int nsec); +/** + * osi_adjust_freq - Adjust frequency + * @osi: OSI private data structure. + * @ppb: Parts per Billion + * + * Algorithm: Adjust a drift of +/- comp nanoseconds per second. + * "Compensation" is the difference in frequency between + * the master and slave clocks in Parts Per Billion. + * + * Dependencies: MAC IP should be out of reset and need to be + * initialized as the requirements + * + * Protection: None + * + * Return: 0 - success, -1 - failure + */ +int osi_adjust_freq(struct osi_core_priv_data *osi_core, int ppb); + +/** + * + * osi_adjust_time - Adjust time + * @osi_core: OSI private data structure. + * @delta: Delta time + * + * Algorithm: Adjust/update the MAC system time (delta passed in + * nanoseconds, can be + or -). + * + * Dependencies: MAC IP should be out of reset + * and need to be initialized as the requirements + * 1) osi_core->ptp_config.one_nsec_accuracy need to be set to 1 + * + * Protection: None + * + * Return: 0 - success, -1 - failure + */ +int osi_adjust_time(struct osi_core_priv_data *osi_core, long delta); + +/** + * osi_get_systime - Get system time + * @osi: OSI private data structure. + * @sec: Value read in Seconds + * @nsec: Value read in Nano seconds + * + * Algorithm: Gets the current system time + * + * Dependencies: MAC IP should be out of reset and need to be + * initialized as the requirements. + * + * Protection: None + * + * Return: None (sec and nsec stores the read seconds and nanoseconds + * values from MAC) + */ +void osi_get_systime_from_mac(struct osi_core_priv_data *osi_core, + unsigned int *sec, + unsigned int *nsec); +/** + * osi_ptp_configuration - Configure PTP + * @osi: OSI private data structure. + * @enable: Enable or disable Time Stamping. + * 0: Disable 1: Enable + * + * Algorithm: Configure the PTP registers that are required for PTP. + * + * Dependencies: MAC IP should be out of reset and need to be initialized + * as the requirements. + * 1) osi->ptp_config.ptp_filter need to be filled accordingly to the + * filter that need to be set for PTP packets. Please check osi_ptp_config + * structure declaration on the bit fields that need to be filled. + * 2) osi->ptp_config.ptp_clock need to be filled with the ptp system clk. + * Currently it is set to 62500000Hz. + * 3) osi->ptp_config.ptp_ref_clk_rate need to be filled with the ptp + * reference clock that platform supports. + * 4) osi->ptp_config.sec need to be filled with current time of seconds + * 5) osi->ptp_config.nsec need to be filled with current time of nseconds + * 6) osi->base need to be filled with the ioremapped base address + * + * Protection: None + * + * Return: None + */ + +void osi_ptp_configuration(struct osi_core_priv_data *osi_core, + unsigned int enable); #endif /* OSI_CORE_H */ diff --git a/include/osi_dma.h b/include/osi_dma.h index d5d549c..d1eb05a 100644 --- a/include/osi_dma.h +++ b/include/osi_dma.h @@ -30,6 +30,7 @@ #define OSI_PKT_CX_VALID OSI_BIT(10) #define OSI_PKT_CX_CSUM OSI_BIT(1) #define OSI_PKT_CX_TSO OSI_BIT(2) +#define OSI_PKT_CX_PTP OSI_BIT(3) /* Flag to indicate if buffer programmed in desc. is DMA map'd from * linear/Paged buffer from OS layer. @@ -37,6 +38,7 @@ #define OSI_TXDONE_CX_PAGED_BUF OSI_BIT(0) /* Flag to indicate if there was any tx error */ #define OSI_TXDONE_CX_ERROR OSI_BIT(1) +#define OSI_TXDONE_CX_TS OSI_BIT(2) /* Checksum offload result flags */ #define OSI_CHECKSUM_NONE 0x0U @@ -104,12 +106,14 @@ struct osi_rx_swcx { * @rxcsum: Stores the Rx csum * @vlan_tag: Stores the VLAN tag ID in received packet. * @pkt_len: Length of received packet. + * @ns: TS in nsec for the received packet */ struct osi_rx_pkt_cx { unsigned int flags; unsigned int rxcsum; unsigned int vlan_tag; unsigned int pkt_len; + unsigned long long ns; }; /** @@ -183,9 +187,12 @@ struct osi_tx_pkt_cx { * struct osi_txdone_pkt_cx - Transmit done packet context for a packet * @flags: Indicates status flags for Tx complete (tx error occured, or * indicate whether desc. had buf mapped from paged/linear memory etc.) + * @ns: TS captured for the tx packet and this is valid only when the PTP + * bit is set in fields */ struct osi_txdone_pkt_cx { unsigned int flags; + unsigned long long ns; }; /** diff --git a/include/osi_dma_txrx.h b/include/osi_dma_txrx.h index 40e69ec..da0c56b 100644 --- a/include/osi_dma_txrx.h +++ b/include/osi_dma_txrx.h @@ -34,6 +34,7 @@ #define DECR_RX_DESC_INDEX(idx, i) ((idx) = ((idx) - (i)) & (RX_DESC_CNT - 1U)) #define RDES3_OWN OSI_BIT(31) +#define RDES3_CTXT OSI_BIT(30) #define RDES3_IOC OSI_BIT(30) #define RDES3_B1V OSI_BIT(24) #define RDES3_LD OSI_BIT(28) @@ -50,6 +51,8 @@ #define RDES3_RS0V OSI_BIT(25) #define RDES3_RS1V OSI_BIT(26) #define RDES0_OVT 0x0000FFFFU +#define RDES1_TSA OSI_BIT(14) /* Timestamp available */ +#define RDES1_TD OSI_BIT(15) /* Timestamp Dropped */ #define RDES1_IPCE OSI_BIT(7) #define RDES1_IPCB OSI_BIT(6) @@ -73,6 +76,7 @@ #define TDES3_TPL_MASK 0x3FFFFU #define TDES3_THL_SHIFT 19U #define TDES3_VLTV OSI_BIT(16) +#define TDES3_TTSS OSI_BIT(17) /* Tx Errors */ #define TDES3_IP_HEADER_ERR OSI_BIT(0) @@ -90,6 +94,7 @@ * MAC_VLAN_Incl register or context descriptor.) */ #define TDES2_VTIR ((unsigned int)0x2 << 14U) +#define TDES2_TTSE ((unsigned int)0x1 << 30U) #define TDES3_ES_BITS (TDES3_IP_HEADER_ERR | \ TDES3_UNDER_FLOW_ERR | \ diff --git a/osi/core/eqos_core.c b/osi/core/eqos_core.c index d8b810e..39b83f9 100644 --- a/osi/core/eqos_core.c +++ b/osi/core/eqos_core.c @@ -977,7 +977,9 @@ static void eqos_configure_mac(struct osi_core_priv_data *osi_core) /* Enable Multicast and Broadcast Queue, default is Q0 */ value = osi_readl((unsigned char *)osi_core->base + EQOS_MAC_RQC1R); - value |= EQOS_MAC_RQC1R_MCBCQEN; + value |= EQOS_MAC_RQC1R_MCBCQEN; + /* Routing Multicast and Broadcast to Q1 */ + value |= EQOS_MAC_RQC1R_MCBCQ1; osi_writel(value, (unsigned char *)osi_core->base + EQOS_MAC_RQC1R); /* Disable all MMC interrupts */ @@ -2165,6 +2167,460 @@ static inline int eqos_update_vlan_id(void *base, unsigned int vid) return 0; } +/** + * eqos_poll_for_tsinit_complete - Poll for time stamp init complete + * @addr: MAC base address. + * @mac_tcr: Address to store time stamp control register read value + * + * Algorithm: Read TSINIT value from MAC TCR register until it is + * equal to zero. + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static inline int eqos_poll_for_tsinit_complete(void *addr, + unsigned int *mac_tcr) +{ + unsigned int retry = 1000; + unsigned int count; + int cond = 1; + + /* Wait for previous(if any) Initialize Timestamp value + * update to complete + */ + count = 0; + while (cond == 1) { + if (count > retry) { + return -1; + } + /* Read and Check TSINIT in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)addr + EQOS_MAC_TCR); + if ((*mac_tcr & EQOS_MAC_TCR_TSINIT) == 0U) { + cond = 0; + } + count++; + osd_msleep(1U); + } + + return 0; +} + +/** + * eqos_set_systime - Set system time + * @addr: MAC base address. + * @sec: Seconds to be configured + * @nsec: Nano Seconds to be configured + * + * Algorithm: Updates system time (seconds and nano seconds) + * in hardware registers + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static int eqos_set_systime_to_mac(void *addr, unsigned int sec, + unsigned int nsec) +{ + unsigned int mac_tcr; + int ret; + + ret = eqos_poll_for_tsinit_complete(addr, &mac_tcr); + if (ret == -1) { + return -1; + } + + /* write seconds value to MAC_System_Time_Seconds_Update register */ + osi_writel(sec, (unsigned char *)addr + EQOS_MAC_STSUR); + + /* write nano seconds value to MAC_System_Time_Nanoseconds_Update + * register + */ + osi_writel(nsec, (unsigned char *)addr + EQOS_MAC_STNSUR); + + /* issue command to update the configured secs and nsecs values */ + mac_tcr |= EQOS_MAC_TCR_TSINIT; + osi_writel(mac_tcr, (unsigned char *)addr + EQOS_MAC_TCR); + + ret = eqos_poll_for_tsinit_complete(addr, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * eqos_poll_for_tsinit_complete - Poll for addend value write complete + * @addr: MAC base address. + * @mac_tcr: Address to store time stamp control register read value + * + * Algorithm: Read TSADDREG value from MAC TCR register until it is + * equal to zero. + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static inline int eqos_poll_for_addend_complete(void *addr, + unsigned int *mac_tcr) +{ + unsigned int retry = 1000; + unsigned int count; + int cond = 1; + + /* Wait for previous(if any) addend value update to complete */ + /* Poll */ + count = 0; + while (cond == 1) { + if (count > retry) { + return -1; + } + /* Read and Check TSADDREG in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)addr + EQOS_MAC_TCR); + if ((*mac_tcr & EQOS_MAC_TCR_TSADDREG) == 0U) { + cond = 0; + } + count++; + osd_msleep(1U); + } + + return 0; +} + +/** + * eqos_config_addend - Configure addend + * @addr: MAC base address. + * @addend: Addend value to be configured + * + * Algorithm: Updates the Addend value in HW register + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static int eqos_config_addend(void *addr, unsigned int addend) +{ + unsigned int mac_tcr; + int ret; + + ret = eqos_poll_for_addend_complete(addr, &mac_tcr); + if (ret == -1) { + return -1; + } + + /* write addend value to MAC_Timestamp_Addend register */ + osi_writel(addend, (unsigned char *)addr + EQOS_MAC_TAR); + + /* issue command to update the configured addend value */ + mac_tcr |= EQOS_MAC_TCR_TSADDREG; + osi_writel(mac_tcr, (unsigned char *)addr + EQOS_MAC_TCR); + + ret = eqos_poll_for_addend_complete(addr, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * eqos_poll_for_update_ts_complete - Poll for update time stamp + * @addr: MAC base address. + * @mac_tcr: Address to store time stamp control register read value + * + * Algorithm: Read time stamp update value from TCR register until it is + * equal to zero. + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static inline int eqos_poll_for_update_ts_complete(void *addr, + unsigned int *mac_tcr) +{ + unsigned int retry = 1000; + unsigned int count; + int cond = 1; + + /* Wait for previous(if any) time stamp value update to complete */ + count = 0; + while (cond == 1) { + if (count > retry) { + return -1; + } + /* Read and Check TSUPDT in MAC_Timestamp_Control register */ + *mac_tcr = osi_readl((unsigned char *)addr + EQOS_MAC_TCR); + if ((*mac_tcr & EQOS_MAC_TCR_TSUPDT) == 0U) { + cond = 0; + } + count++; + osd_msleep(1U); + } + + return 0; + +} + +/** + * eqos_adjust_systime - Adjust system time + * @addr: MAC base address. + * @sec: Seconds to be configured + * @nsec: Nano seconds to be configured + * @add_sub: To decide on add/sub with system time + * @one_nsec_accuracy: One nano second accuracy + * + * Algorithm: Update the system time + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static int eqos_adjust_systime(void *addr, unsigned int sec, unsigned int nsec, + unsigned int add_sub, + unsigned int one_nsec_accuracy) +{ + unsigned int mac_tcr; + unsigned int value = 0; + unsigned long long temp = 0; + int ret; + + ret = eqos_poll_for_update_ts_complete(addr, &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 + EQOS_MAC_STSUR); + + /* write nano seconds value and add_sub to + * MAC_System_Time_Nanoseconds_Update register + */ + value |= nsec; + value |= add_sub << EQOS_MAC_STNSUR_ADDSUB_SHIFT; + osi_writel(value, (unsigned char *)addr + EQOS_MAC_STNSUR); + + /* issue command to initialize system time with the value + * specified in MAC_STSUR and MAC_STNSUR + */ + mac_tcr |= EQOS_MAC_TCR_TSUPDT; + osi_writel(mac_tcr, (unsigned char *)addr + EQOS_MAC_TCR); + + ret = eqos_poll_for_update_ts_complete(addr, &mac_tcr); + if (ret == -1) { + return -1; + } + + return 0; +} + +/** + * eqos_get_systime - Get system time from MAC + * @addr: MAC base address. + * + * Algorithm: Get current system time + * + * Dependencies: None. + * + * Protection: None. + * + * Return: 0 - success, -1 - failure + */ +static unsigned long long eqos_get_systime_from_mac(void *addr) +{ + unsigned long long ns1, ns2, ns = 0; + unsigned int varmac_stnsr, temp1; + unsigned int varmac_stsr; + + varmac_stnsr = osi_readl((unsigned char *)addr + EQOS_MAC_STNSR); + temp1 = (varmac_stnsr & EQOS_MAC_STNSR_TSSS_MASK); + ns1 = (unsigned long long)temp1; + + varmac_stsr = osi_readl((unsigned char *)addr + EQOS_MAC_STSR); + + varmac_stnsr = osi_readl((unsigned char *)addr + EQOS_MAC_STNSR); + temp1 = (varmac_stnsr & EQOS_MAC_STNSR_TSSS_MASK); + ns2 = (unsigned long long)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((unsigned char *)addr + EQOS_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; +} + +/** + * eqos_config_tscr - Configure Time Stamp Register + * @addr: MAC base address. + * @ptp_filter: PTP rx filter parameters + * + * Algorithm: Configure Time Stamp Register + * + * Dependencies: None. + * + * Protection: None. + * + * Return: None. + **/ +static void eqos_config_tscr(void *addr, unsigned int ptp_filter) +{ + unsigned int mac_tcr = 0; + + 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; + } + } else { + /* Disabling the MAC time stamping */ + mac_tcr = OSI_DISABLE; + } + + osi_writel(mac_tcr, (unsigned char *)addr + EQOS_MAC_TCR); +} + +/** + * eqos_config_ssir - Configure SSIR + * @addr: MAC base address. + * @ptp_clock: PTP clock + * + * Algorithm: Configure Sub Second Increment Register + * + * Dependencies: None. + * + * Protection: None. + * + * Return: None. + */ +static void eqos_config_ssir(void *addr, unsigned int ptp_clock) +{ + unsigned int val; + unsigned int mac_tcr; + + mac_tcr = osi_readl((unsigned char *)addr + EQOS_MAC_TCR); + + /* convert the PTP_CLOCK to nano second. + * formula is : ((1/ptp_clock) * 1000000000) + * where, ptp_clock = 50MHz if FINE correction + * and ptp_clock = EQOS_SYSCLOCK if COARSE correction + */ + + if ((mac_tcr & EQOS_MAC_TCR_TSCFUPDT) == EQOS_MAC_TCR_TSCFUPDT) { + val = ((1U * (unsigned int)OSI_NSEC_PER_SEC) / + (unsigned int)OSI_ETHER_SYSCLOCK); + } else { + val = ((1U * (unsigned int)OSI_NSEC_PER_SEC) / ptp_clock); + } + + /* 0.465ns accurecy */ + if ((mac_tcr & EQOS_MAC_TCR_TSCTRLSSR) == 0U) { + if (val < UINT_MAX) { + val = (val * 1000U) / 465U; + } + } + + val |= val << EQOS_MAC_SSIR_SSINC_SHIFT; + /* update Sub-second Increment Value */ + osi_writel(val, (unsigned char *)addr + EQOS_MAC_SSIR); +} + static struct osi_core_ops eqos_core_ops = { .poll_for_swr = eqos_poll_for_swr, .core_init = eqos_core_init, @@ -2197,6 +2653,12 @@ static struct osi_core_ops eqos_core_ops = { .update_l4_port_no = eqos_update_l4_port_no, .config_vlan_filtering = eqos_config_vlan_filtering, .update_vlan_id = eqos_update_vlan_id, + .set_systime_to_mac = eqos_set_systime_to_mac, + .config_addend = eqos_config_addend, + .adjust_systime = eqos_adjust_systime, + .get_systime_from_mac = eqos_get_systime_from_mac, + .config_tscr = eqos_config_tscr, + .config_ssir = eqos_config_ssir, }; struct osi_core_ops *eqos_get_hw_core_ops(void) diff --git a/osi/core/eqos_core.h b/osi/core/eqos_core.h index 4aefc30..1dec605 100644 --- a/osi/core/eqos_core.h +++ b/osi/core/eqos_core.h @@ -111,6 +111,13 @@ #define EQOS_MAC_L3_AD2R(x) ((0x0030U * (x)) + 0x0918U) #define EQOS_MAC_L3_AD3R(x) ((0x0030U * (x)) + 0x091CU) #define EQOS_MAC_PFR 0x0008U +#define EQOS_MAC_TCR 0x0B00 +#define EQOS_MAC_SSIR 0x0B04 +#define EQOS_MAC_STSR 0x0B08 +#define EQOS_MAC_STNSR 0x0B0C +#define EQOS_MAC_STSUR 0x0B10 +#define EQOS_MAC_STNSUR 0x0B14 +#define EQOS_MAC_TAR 0x0B18 /* EQOS MTL registers*/ #define EQOS_MTL_CHX_TX_OP_MODE(x) ((0x0040U * (x)) + 0x0D00U) @@ -178,6 +185,7 @@ #define EQOS_DMA_SBUS_EAME OSI_BIT(11) #define EQOS_DMA_BMR_SWR OSI_BIT(0) #define EQOS_DMA_BMR_DPSW OSI_BIT(8) +#define EQOS_MAC_RQC1R_MCBCQ1 OSI_BIT(16) #define EQOS_MAC_RQC1R_MCBCQEN OSI_BIT(20) #define EQOS_MTL_QTOMR_FTQ_LPOS OSI_BIT(0) #define EQOS_DMA_ISR_MACIS OSI_BIT(17) @@ -276,6 +284,13 @@ #define EQOS_MAC_RQC2_PSRQ_SHIFT 8U #define EQOS_MAC_VLAN_TR_ETV_SHIFT 16U #define EQOS_MAC_MAX_HTR_REG_LEN 8U - +#define EQOS_MAC_TCR_TSADDREG OSI_BIT(5) +#define EQOS_MAC_TCR_TSINIT OSI_BIT(2) +#define EQOS_MAC_TCR_TSUPDT OSI_BIT(3) +#define EQOS_MAC_STNSUR_ADDSUB_SHIFT 31U +#define EQOS_MAC_TCR_TSCFUPDT OSI_BIT(1) +#define EQOS_MAC_TCR_TSCTRLSSR OSI_BIT(9) +#define EQOS_MAC_SSIR_SSINC_SHIFT 16U +#define EQOS_MAC_STNSR_TSSS_MASK 0x7FFFFFFFU void update_ehfc_rfa_rfd(unsigned int rx_fifo, unsigned int *value); #endif diff --git a/osi/core/libnvethernetrm.export b/osi/core/libnvethernetrm.export index 0a6daa7..74829fa 100644 --- a/osi/core/libnvethernetrm.export +++ b/osi/core/libnvethernetrm.export @@ -58,3 +58,8 @@ osi_config_vlan_filtering osi_config_l2_da_perfect_inverse_match osi_update_vlan_id osi_config_fw_err_pkts +osi_ptp_configuration +osi_get_systime_from_mac +osi_adjust_time +osi_adjust_freq +osi_set_systime_to_mac diff --git a/osi/core/osi_core.c b/osi/core/osi_core.c index 51d8d8b..8473c8e 100644 --- a/osi/core/osi_core.c +++ b/osi/core/osi_core.c @@ -37,27 +37,6 @@ extern struct osi_core_ops *eqos_get_hw_core_ops(void); -/** - * osi_write_phy_reg - Write to a PHY register through MAC over MDIO bus. - * @osi: OSI private data structure. - * @phyaddr: PHY address (PHY ID) associated with PHY - * @phyreg: Register which needs to be write to PHY. - * @phydata: Data to write to a PHY register. - * - * Algorithm: - * 1) Before proceding for reading for PHY register check whether any MII - * operation going on MDIO bus by polling MAC_GMII_BUSY bit. - * 2) Program data into MAC MDIO data register. - * 3) Populate required parameters like phy address, phy register etc,, - * in MAC MDIO Address register. write and GMII busy bits needs to be set - * in this operation. - * 4) Write into MAC MDIO address register poll for GMII busy for MDIO - * operation to complete. - * - * Dependencies: MAC IP should be out of reset - * - * Return: 0 - success, -1 - failure - */ int osi_write_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg, unsigned short phydata) { @@ -129,27 +108,6 @@ int osi_write_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, return 0; } -/** - * osi_read_phy_reg - Read from a PHY register through MAC over MDIO bus. - * @osi: OSI private data structure. - * @phyaddr: PHY address (PHY ID) associated with PHY - * @phyreg: Register which needs to be read from PHY. - * - * Algorithm: - * 1) Before proceding for reading for PHY register check whether any MII - * operation going on MDIO bus by polling MAC_GMII_BUSY bit. - * 2) Populate required parameters like phy address, phy register etc,, - * in program it in MAC MDIO Address register. Read and GMII busy bits - * needs to be set in this operation. - * 3) Write into MAC MDIO address register poll for GMII busy for MDIO - * operation to complete. After this data will be available at MAC MDIO - * data register. - * - * Dependencies: MAC IP should be out of reset - * - * Return: data from PHY register - success, -1 - failure - */ - int osi_read_phy_reg(struct osi_core_priv_data *osi_core, unsigned int phyaddr, unsigned int phyreg) { @@ -634,3 +592,235 @@ int osi_update_vlan_id(struct osi_core_priv_data *osi_core, return ret; } + +int osi_set_systime_to_mac(struct osi_core_priv_data *osi_core, + unsigned int sec, unsigned int nsec) +{ + int ret = -1; + + if ((osi_core != OSI_NULL) && (osi_core->ops != OSI_NULL) && + (osi_core->ops->set_systime_to_mac != OSI_NULL)) { + ret = osi_core->ops->set_systime_to_mac(osi_core->base, + sec, + nsec); + } + + return ret; +} + +/** + * div_u64_rem - updates remainder and returns Quotient + * @dividend: Dividend value + * @divisor: Divisor value + * @remainder: Remainder + * + * Algorithm: Dividend will be divided by divisor and stores the + * remainder value and returns quotient + * + * Dependencies: MAC IP should be out of reset + * and need to be initialized as the requirements + * + * Protection: None + * + * Return: Quotient + */ +static inline unsigned long div_u64_rem(unsigned long dividend, + unsigned long divisor, + unsigned long *remain) +{ + unsigned long ret = 0; + + if (divisor != 0U) { + *remain = dividend % divisor; + ret = dividend / divisor; + } else { + ret = 0; + } + return ret; +} + +/** + * div_u64 - Calls a function which returns quotient + * @dividend: Dividend + * @divisor: Divisor + * + * Algorithm: Calls a function which returns quotient. + * + * Dependencies: MAC IP should be out of reset + * and need to be initialized as the requirements. + * + * Protection: None + * + * Return: Quotient + */ +static inline unsigned long div_u64(unsigned long dividend, + unsigned long divisor) +{ + unsigned long remain; + + return div_u64_rem(dividend, divisor, &remain); +} + +int osi_adjust_freq(struct osi_core_priv_data *osi_core, int ppb) +{ + unsigned long adj; + unsigned long temp; + unsigned int diff = 0; + unsigned int addend; + unsigned int neg_adj = 0; + int ret = -1; + + if (ppb < 0) { + neg_adj = 1U; + ppb = -ppb; + } + + if (osi_core == OSI_NULL) { + return ret; + } + + addend = osi_core->default_addend; + adj = (unsigned long)addend * (unsigned int)ppb; + + /* + * div_u64 will divide the "adj" by "1000000000ULL" + * and return the quotient. + */ + temp = div_u64(adj, OSI_NSEC_PER_SEC); + if (temp < UINT_MAX) { + diff = (unsigned int)temp; + } else { + /* do nothing here */ + } + + if (neg_adj == 0U) { + if (addend <= UINT_MAX - diff) { + addend = (addend + diff); + } else { + /* do nothing here */ + } + } else { + if (addend > diff) { + addend = addend - diff; + } else if (addend < diff) { + addend = diff - addend; + } else { + /* do nothing here */ + } + } + + if ((osi_core->ops != OSI_NULL) && + (osi_core->ops->config_addend != OSI_NULL)) { + ret = osi_core->ops->config_addend(osi_core->base, addend); + } + + return ret; +} + +int osi_adjust_time(struct osi_core_priv_data *osi_core, long delta) +{ + unsigned int neg_adj = 0; + unsigned int sec = 0, nsec = 0; + unsigned long quotient; + unsigned long reminder = 0; + unsigned long udelta = 0; + int ret = -1; + + if (delta < 0) { + neg_adj = 1; + delta = -delta; + } + udelta = (unsigned long) delta; + quotient = div_u64_rem(udelta, OSI_NSEC_PER_SEC, &reminder); + if (quotient <= UINT_MAX) { + sec = (unsigned int)quotient; + } else { + /* do nothing */ + } + if (reminder <= UINT_MAX) { + nsec = (unsigned int)reminder; + } else { + /* do nothing here */ + } + + if ((osi_core != OSI_NULL) && (osi_core->ops != OSI_NULL) && + (osi_core->ops->adjust_systime != OSI_NULL)) { + ret = osi_core->ops->adjust_systime(osi_core->base, sec, nsec, + neg_adj, + osi_core->ptp_config.one_nsec_accuracy); + } + + return ret; +} + +void osi_get_systime_from_mac(struct osi_core_priv_data *osi_core, + unsigned int *sec, + unsigned int *nsec) +{ + unsigned long long ns = 0; + unsigned long long temp = 0; + unsigned long remain = 0; + + if ((osi_core != OSI_NULL) && (osi_core->ops != OSI_NULL) && + (osi_core->ops->adjust_systime != OSI_NULL)) { + ns = osi_core->ops->get_systime_from_mac(osi_core->base); + } + + temp = div_u64_rem((unsigned long)ns, OSI_NSEC_PER_SEC, &remain); + if (temp < UINT_MAX) { + *sec = (unsigned int) temp; + } else { + /* do nothing here */ + } + if (remain < UINT_MAX) { + *nsec = (unsigned int)remain; + } else { + /* do nothing here */ + } +} + +void osi_ptp_configuration(struct osi_core_priv_data *osi_core, + unsigned int enable) +{ + int ret = 0; + unsigned long temp = 0, temp1 = 0; + + if (enable == OSI_DISABLE) { + /* disable hw time stamping */ + /* Program MAC_Timestamp_Control Register */ + osi_core->ops->config_tscr(osi_core->base, OSI_DISABLE); + } else { + /* Program MAC_Timestamp_Control Register */ + osi_core->ops->config_tscr(osi_core->base, + osi_core->ptp_config.ptp_filter); + + /* Program Sub Second Increment Register */ + osi_core->ops->config_ssir(osi_core->base, + osi_core->ptp_config.ptp_clock); + + /* formula for calculating addend value is + * addend = 2^32/freq_div_ratio; + * where, freq_div_ratio = EQOS_SYSCLOCK/50MHz + * hence, addend = ((2^32) * 50MHz)/EQOS_SYSCLOCK; + * NOTE: EQOS_SYSCLOCK must be >= 50MHz to achive 20ns accuracy. + * 2^x * y == (y << x), hence + * 2^32 * 6250000 ==> (6250000 << 32) + */ + temp = (unsigned long)(OSI_ETHER_SYSCLOCK << 32); + temp1 = div_u64(temp, + (unsigned long)osi_core->ptp_config.ptp_ref_clk_rate); + if (temp1 < UINT_MAX) { + osi_core->default_addend = (unsigned int) temp1; + } else { + /* do nothing here */ + } + /* Program addend value */ + ret = osi_core->ops->config_addend(osi_core->base, + osi_core->default_addend); + + /* Set current time */ + ret = osi_core->ops->set_systime_to_mac(osi_core->base, + osi_core->ptp_config.sec, + osi_core->ptp_config.nsec); + } +} diff --git a/osi/dma/osi_dma_txrx.c b/osi/dma/osi_dma_txrx.c index 45f609d..286f616 100644 --- a/osi/dma/osi_dma_txrx.c +++ b/osi/dma/osi_dma_txrx.c @@ -92,6 +92,92 @@ static inline void get_rx_vlan_from_desc(struct osi_rx_desc *rx_desc, } } +/** + * get_rx_tstamp_status - Get Tx Time stamp status + * @context_desc: Rx context descriptor + * + * Algorithm: + * 1) Check if the received descriptor is a context descriptor. + * 2) If yes, check whether the time stamp is valid or not. + * + * Dependencies: None + * + * Protection: None + * + * Return: -1 if TS is not valid and 0 if TS is valid. + */ +static inline int get_rx_tstamp_status(struct osi_rx_desc *context_desc) +{ + 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))) { + /* Invalid time stamp */ + return -1; + } + /* tstamp can be read */ + return 0; + } + /* Busy */ + return -2; +} + +/** + * get_rx_hwstamp - Get Rx HW Time stamp + * @rx_desc: Rx descriptor + * @context_desc: Rx context descriptor + * @rx_pkt_cx: Rx packet context + * + * 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. + * + * Dependencies: None + * + * Protection: None + * + * Return: -1 if TS is not available and 0 if TS is available. + */ +static int get_rx_hwstamp(struct osi_rx_desc *rx_desc, + struct osi_rx_desc *context_desc, + struct osi_rx_pkt_cx *rx_pkt_cx) +{ + int 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) == 0U)) { + + 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 */ + } + if (ret != 0) { + /* Timed out waiting for Rx timestamp */ + return ret; + } + + rx_pkt_cx->ns = context_desc->rdes0 + + (OSI_NSEC_PER_SEC * context_desc->rdes1); + } + return ret; +} + + /** * get_rx_err_stats - Detect Errors from Rx Descriptor * @rx_desc: Rx Descriptor. @@ -144,17 +230,23 @@ int osi_process_rx_completions(struct osi_dma_priv_data *osi, struct osi_rx_ring *rx_ring = osi->rx_ring[chan]; struct osi_rx_pkt_cx *rx_pkt_cx = &rx_ring->rx_pkt_cx; struct osi_rx_desc *rx_desc = OSI_NULL; + struct osi_rx_swcx *rx_swcx = OSI_NULL; + struct osi_rx_desc *context_desc = OSI_NULL; int received = 0; + int ret = 0; while (received < budget) { osi_memset(rx_pkt_cx, 0, sizeof(*rx_pkt_cx)); rx_desc = rx_ring->rx_desc + rx_ring->cur_rx_idx; + rx_swcx = rx_ring->rx_swcx + rx_ring->cur_rx_idx; /* check for data availability */ if ((rx_desc->rdes3 & RDES3_OWN) == RDES3_OWN) { break; } + INCR_RX_DESC_INDEX(rx_ring->cur_rx_idx, 1U); + /* get the length of the packet */ rx_pkt_cx->pkt_len = rx_desc->rdes3 & RDES3_PKT_LEN; @@ -174,8 +266,17 @@ int osi_process_rx_completions(struct osi_dma_priv_data *osi, get_rx_csum(rx_desc, rx_pkt_cx); get_rx_vlan_from_desc(rx_desc, rx_pkt_cx); + context_desc = rx_ring->rx_desc + rx_ring->cur_rx_idx; + /* Get rx time stamp */ + ret = get_rx_hwstamp(rx_desc, context_desc, rx_pkt_cx); + if (ret == 0) { + /* Context descriptor was consumed. Its skb + * and DMA mapping will be recycled + */ + INCR_RX_DESC_INDEX(rx_ring->cur_rx_idx, 1U); + } osd_receive_packet(osi->osd, rx_ring, chan, - osi->rx_buf_len, rx_pkt_cx); + osi->rx_buf_len, rx_pkt_cx, rx_swcx); } received++; @@ -349,6 +450,8 @@ int osi_process_tx_completions(struct osi_dma_priv_data *osi, struct osi_tx_swcx *tx_swcx = OSI_NULL; struct osi_tx_desc *tx_desc = OSI_NULL; unsigned int entry = tx_ring->clean_idx; + unsigned long vartdes1; + unsigned long long ns; int processed = 0; while (entry != tx_ring->cur_tx_idx) { @@ -370,6 +473,23 @@ int osi_process_tx_completions(struct osi_dma_priv_data *osi, } } + if (((tx_desc->tdes3 & TDES3_LD) == TDES3_LD) && + ((tx_desc->tdes3 & TDES3_CTXT) == 0U)) { + /* check tx tstamp status */ + if ((tx_desc->tdes3 & TDES3_TTSS) != 0U) { + txdone_pkt_cx->flags |= OSI_TXDONE_CX_TS; + /* tx timestamp captured for this packet */ + ns = tx_desc->tdes0; + vartdes1 = tx_desc->tdes1; + if (vartdes1 < UINT_MAX) { + ns = ns + (vartdes1 * OSI_NSEC_PER_SEC); + } + txdone_pkt_cx->ns = ns; + } else { + /* Do nothing here */ + } + } + if (tx_swcx->is_paged_buf == 1U) { txdone_pkt_cx->flags |= OSI_TXDONE_CX_PAGED_BUF; } @@ -490,6 +610,11 @@ static inline void fill_first_desc(struct osi_tx_pkt_cx *tx_pkt_cx, tx_desc->tdes2 |= TDES2_VTIR; } + /* if TS is set enable timestamping */ + if ((tx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) { + tx_desc->tdes2 |= TDES2_TTSE; + } + /* Enable TSE bit and update TCP hdr, payload len */ if ((tx_pkt_cx->flags & OSI_PKT_CX_TSO) == OSI_PKT_CX_TSO) { tx_desc->tdes3 |= TDES3_TSE;