nvethernet: 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: Id647db1f60582717a09f24699841e00d7a582a1d
Signed-off-by: Narayan Reddy <narayanr@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2123439
GVS: Gerrit_Virtual_Submit
Reviewed-by: Srinivas Ramachandran <srinivasra@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Narayan Reddy
2019-05-15 23:36:32 +05:30
committed by Revanth Kumar Uppala
parent 6a3fdf61b3
commit 21dcef7b83
6 changed files with 511 additions and 8 deletions

View File

@@ -24,6 +24,7 @@ nvethernet-objs:= ether_linux.o \
ethtool.o \
sysfs.o \
ioctl.o \
ptp.o \
$(OSI_CORE)/osi_core.o \
$(OSI_CORE)/osi_common.o \
$(OSI_DMA)/osi_dma.o \

View File

@@ -925,6 +925,15 @@ static int ether_open(struct net_device *dev)
/* Start the MAC */
osi_start_mac(pdata->osi_core);
/* Initialize PTP */
ret = ether_ptp_init(pdata);
if (ret < 0) {
dev_err(pdata->dev,
"%s:failed to initialize PTP with reason %d\n",
__func__, ret);
goto err_hw_init;
}
ether_napi_enable(pdata);
/* start PHY */
@@ -988,6 +997,9 @@ static int ether_close(struct net_device *dev)
/* free DMA resources after DMA stop */
free_dma_resources(pdata->osi_dma, pdata->dev);
/* PTP de-init */
ether_ptp_remove(pdata);
/* Stop the MAC */
osi_stop_mac(pdata->osi_core);
@@ -1104,6 +1116,11 @@ static int ether_tx_swcx_alloc(struct device *dev,
tx_pkt_cx->flags |= OSI_PKT_CX_VLAN;
}
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_pkt_cx->flags |= OSI_PKT_CX_PTP;
}
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)) {
tx_swcx = tx_ring->tx_swcx + cur_tx_idx;
@@ -1577,6 +1594,10 @@ static int ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
ret = ether_handle_priv_ioctl(dev, rq);
break;
case SIOCSHWTSTAMP:
ret = ether_handle_hwtstamp_ioctl(pdata, rq);
break;
default:
netdev_err(dev, "%s: Unsupported ioctl %d\n",
__func__, cmd);
@@ -2384,6 +2405,15 @@ static int ether_configure_car(struct platform_device *pdev,
return ret;
}
/* set PTP clock rate*/
ret = clk_set_rate(pdata->ptp_ref_clk, pdata->ptp_ref_clock_speed);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set ptp clk rate\n");
return ret;
} else {
osi_core->ptp_config.ptp_ref_clk_rate = pdata->ptp_ref_clock_speed;
}
ret = ether_enable_clks(pdata);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable clks\n");
@@ -2576,20 +2606,27 @@ static void ether_parse_queue_prio(struct ether_priv_data *pdata,
*/
static int ether_parse_dt(struct ether_priv_data *pdata)
{
struct device *dev = pdata->dev;
struct platform_device *pdev = to_platform_device(dev);
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct osi_dma_priv_data *osi_dma = pdata->osi_dma;
struct device *dev = pdata->dev;
struct device_node *np = dev->of_node;
struct platform_device *pdev = to_platform_device(dev);
int ret = -EINVAL;
/* read ptp clock */
ret = of_property_read_u32(np, "nvidia,ptp_ref_clock_speed",
&pdata->ptp_ref_clock_speed);
if (ret != 0) {
dev_err(dev, "setting default PTP clk rate as 312.5MHz\n");
pdata->ptp_ref_clock_speed = ETHER_DFLT_PTP_CLK;
}
/* Read Pause frame feature support */
ret = of_property_read_u32(np, "nvidia,pause_frames",
&pdata->osi_core->pause_frames);
if (ret < 0) {
dev_err(dev, "Failed to read nvida,pause_frames, so"
" setting to default support as enable\n");
pdata->osi_core->pause_frames = OSI_PAUSE_FRAMES_ENABLE;
" setting to default support as disable\n");
pdata->osi_core->pause_frames = OSI_PAUSE_FRAMES_DISABLE;
}
/* Check if IOMMU is enabled */

View File

@@ -17,8 +17,10 @@
#ifndef ETHER_LINUX_H
#define ETHER_LINUX_H
#include <linux/ptp_clock_kernel.h>
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/net_tstamp.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/of_gpio.h>
@@ -34,6 +36,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/of.h>
#include <linux/ktime.h>
#include <osi_core.h>
#include <osi_dma.h>
@@ -45,6 +48,7 @@
#define ETHER_QUEUE_PRIO_DEFAULT 0U
#define ETHER_QUEUE_PRIO_MAX 7U
#define ETHER_QUEUE_PRIO_INVALID 0xFFU
#define ETHER_DFLT_PTP_CLK 312500000U
#define EQOS_CONFIG_FAIL -3
#define EQOS_CONFIG_SUCCESS 0
@@ -172,6 +176,11 @@ struct ether_rx_napi {
* @l3_l4_filter: L3_l4 filter enabled 1: enabled
* @vlan_hash_filtering: vlan hash filter 1: hash, 0: perfect
* @l2_filtering_mode: l2 filter mode 1: hash 0: perfect
* @ptp_clock_ops: PTP clock operations structure.
* @ptp_clock: PTP system clock
* @ptp_ref_clock_speed: PTP reference clock supported by platform
* @hwts_tx_en: HW tx time stamping enable
* @hwts_rx_en: HW rx time stamping enable
*/
struct ether_priv_data {
struct osi_core_priv_data *osi_core;
@@ -231,9 +240,20 @@ struct ether_priv_data {
unsigned int l3_l4_filter;
unsigned int vlan_hash_filtering;
unsigned int l2_filtering_mode;
/* for PTP */
struct ptp_clock_info ptp_clock_ops;
struct ptp_clock *ptp_clock;
unsigned int ptp_ref_clock_speed;
unsigned int hwts_tx_en;
unsigned int hwts_rx_en;
};
void ether_set_ethtool_ops(struct net_device *ndev);
int ether_sysfs_register(struct device *dev);
void ether_sysfs_unregister(struct device *dev);
int ether_ptp_init(struct ether_priv_data *pdata);
void ether_ptp_remove(struct ether_priv_data *pdata);
int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata,
struct ifreq *ifr);
#endif /* ETHER_LINUX_H */

View File

@@ -128,6 +128,44 @@ static int ether_set_pauseparam(struct net_device *ndev,
return ret;
}
/**
* ether_get_ts_info: Get HW supported time stamping.
* @net: Net device data.
* @info: Holds device supported timestamping types
*
* Algorithm: Function used to query the PTP capabilities for given netdev.
*
* Dependencies: HW need to support PTP functionality.
*
* Protection: None.
*
* Return: Return can't be a -ve value.
*/
static int ether_get_ts_info(struct net_device *net,
struct ethtool_ts_info *info)
{
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_RAW_HARDWARE |
SOF_TIMESTAMPING_SOFTWARE;
info->phc_index = 0;
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
info->rx_filters |= ((1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
(1 << HWTSTAMP_FILTER_NONE));
return 0;
}
static const struct ethtool_ops ether_ethtool_ops = {
.get_link = ethtool_op_get_link,
@@ -135,6 +173,7 @@ static const struct ethtool_ops ether_ethtool_ops = {
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_pauseparam = ether_get_pauseparam,
.set_pauseparam = ether_set_pauseparam,
.get_ts_info = ether_get_ts_info,
};
/**

View File

@@ -212,17 +212,19 @@ static void ether_realloc_rx_skb(struct ether_priv_data *pdata,
* Return: None.
*/
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)
{
struct ether_priv_data *pdata = (struct ether_priv_data *)priv;
struct ether_rx_napi *rx_napi = pdata->rx_napi[chan];
struct osi_rx_ring *rx_ring = (struct osi_rx_ring *)rxring;
struct osi_rx_swcx *rx_swcx = rx_ring->rx_swcx + rx_ring->cur_rx_idx;
struct osi_rx_swcx *rx_swcx = (struct osi_rx_swcx *)rx_pkt_swcx;
struct osi_rx_pkt_cx *rx_pkt_cx = (struct osi_rx_pkt_cx *)rxpkt_cx;
struct sk_buff *skb = (struct sk_buff *)rx_swcx->buf_virt_addr;
dma_addr_t dma_addr = (dma_addr_t)rx_swcx->buf_phy_addr;
struct net_device *ndev = pdata->ndev;
struct osi_pkt_err_stats *pkt_err_stat = &pdata->osi_dma->pkt_err_stats;
struct skb_shared_hwtstamps *shhwtstamp;
dma_unmap_single(pdata->dev, dma_addr, dma_buf_len, DMA_FROM_DEVICE);
@@ -242,6 +244,14 @@ void osd_receive_packet(void *priv, void *rxring, unsigned int chan,
rx_pkt_cx->vlan_tag);
}
/* Handle time stamp */
if ((rx_pkt_cx->flags & OSI_PKT_CX_PTP) == OSI_PKT_CX_PTP) {
shhwtstamp = skb_hwtstamps(skb);
memset(shhwtstamp, 0,
sizeof(struct skb_shared_hwtstamps));
shhwtstamp->hwtstamp = ns_to_ktime(rx_pkt_cx->ns);
}
skb->dev = ndev;
skb->protocol = eth_type_trans(skb, ndev);
ndev->stats.rx_bytes += skb->len;
@@ -259,8 +269,6 @@ void osd_receive_packet(void *priv, void *rxring, unsigned int chan,
rx_swcx->buf_virt_addr = NULL;
rx_swcx->buf_phy_addr = 0;
INCR_RX_DESC_INDEX(rx_ring->cur_rx_idx, 1U);
if (osi_get_refill_rx_desc_cnt(rx_ring) >= 16U)
ether_realloc_rx_skb(pdata, rx_ring, chan);
}
@@ -278,6 +286,7 @@ void osd_receive_packet(void *priv, void *rxring, unsigned int chan,
* Algorithm:
* 1) Updates stats for linux network stack.
* 2) unmap and free the buffer DMA address and buffer.
* 3) Time stamp will be update to stack if available.
*
* Dependencies: Tx completion need to make sure that Tx descriptors
* processed properly.
@@ -295,6 +304,7 @@ void osd_transmit_complete(void *priv, void *buffer, unsigned long dmaaddr,
struct osi_dma_priv_data *osi_dma = pdata->osi_dma;
struct sk_buff *skb = (struct sk_buff *)buffer;
dma_addr_t dma_addr = (dma_addr_t)dmaaddr;
struct skb_shared_hwtstamps shhwtstamp;
struct net_device *ndev = pdata->ndev;
struct osi_tx_ring *tx_ring;
struct netdev_queue *txq;
@@ -303,6 +313,13 @@ void osd_transmit_complete(void *priv, void *buffer, unsigned long dmaaddr,
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
if ((txdone_pkt_cx->flags & OSI_TXDONE_CX_TS) == OSI_TXDONE_CX_TS) {
memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp.hwtstamp = ns_to_ktime(txdone_pkt_cx->ns);
/* pass tstamp to stack */
skb_tstamp_tx(skb, &shhwtstamp);
}
if (dma_addr) {
if ((txdone_pkt_cx->flags & OSI_TXDONE_CX_PAGED_BUF) ==
OSI_TXDONE_CX_PAGED_BUF) {

View File

@@ -0,0 +1,389 @@
/*
* Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ether_linux.h"
/**
* ether_adjust_time: Adjust hardware time
* @ptp: Pointer to ptp_clock_info structure.
* @delta: Desired change in nanoseconds.
*
* Algorithm: This function is used to shift/adjust the time of the
* hardware clock.
*
* Dependencies:
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_adjust_time(struct ptp_clock_info *ptp, s64 delta)
{
struct ether_priv_data *pdata = container_of(ptp,
struct ether_priv_data,
ptp_clock_ops);
struct osi_core_priv_data *osi_core = pdata->osi_core;
int ret = -1;
ret = osi_adjust_time(osi_core, delta);
if (ret < 0) {
dev_err(pdata->dev,
"%s:failed to adjust time with reason %d\n",
__func__, ret);
}
return ret;
}
/**
* ether_adjust_freq: Adjust hardware time
* @ptp: Pointer to ptp_clock_info structure.
* @ppb: Desired period change in parts per billion.
*
* Algorithm: This function is used to adjust the frequency of the
* hardware clock.
*
* Dependencies:
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
{
struct ether_priv_data *pdata = container_of(ptp,
struct ether_priv_data,
ptp_clock_ops);
struct osi_core_priv_data *osi_core = pdata->osi_core;
int ret = -1;
ret = osi_adjust_freq(osi_core, ppb);
if (ret < 0) {
dev_err(pdata->dev,
"%s:failed to adjust frequency with reason code %d\n",
__func__, ret);
}
return ret;
}
/**
* ether_get_time: Get current time
* @ptp: Pointer to ptp_clock_info structure.
* @ts: Pointer to hole time.
*
* Algorithm: This function is used to read the current time from the
* hardware clock
*
* Dependencies:
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
{
struct ether_priv_data *pdata = container_of(ptp,
struct ether_priv_data,
ptp_clock_ops);
struct osi_core_priv_data *osi_core = pdata->osi_core;
unsigned int sec, nsec;
osi_get_systime_from_mac(osi_core, &sec, &nsec);
ts->tv_sec = sec;
ts->tv_nsec = nsec;
return 0;
}
/**
* ether_set_time: Set current time
* @ptp: Pointer to ptp_clock_info structure.
* @ts: Time value to set.
*
* Algorithm: This function is used to set the current time to the
* hardware clock.
*
* Dependencies:
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_set_time(struct ptp_clock_info *ptp,
const struct timespec *ts)
{
struct ether_priv_data *pdata = container_of(ptp,
struct ether_priv_data,
ptp_clock_ops);
struct osi_core_priv_data *osi_core = pdata->osi_core;
int ret = -1;
ret = osi_set_systime_to_mac(osi_core, ts->tv_sec, ts->tv_nsec);
if (ret < 0) {
dev_err(pdata->dev,
"%s:failed to set system time with reason %d\n",
__func__, ret);
}
return ret;
}
/* structure describing a PTP hardware clock */
static struct ptp_clock_info ether_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "ether_ptp_clk",
.max_adj = OSI_ETHER_SYSCLOCK,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0,
.pps = 0,
.adjfreq = ether_adjust_freq,
.adjtime = ether_adjust_time,
.gettime64 = ether_get_time,
.settime64 = ether_set_time,
};
/**
* ether_ptp_init: Function to register ptp clock driver.
* @pdata: Pointer to private data structure.
*
* Algorithm: This function is used to register the ptp clock
* driver to kernel.
*
* Dependencies: Ethernet driver probe need to be completed successfully
* with ethernet network device created.
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
int ether_ptp_init(struct ether_priv_data *pdata)
{
if (pdata->hw_feat.tsstssel == OSI_DISABLE) {
pdata->ptp_clock = NULL;
dev_err(pdata->dev, "No PTP supports in HW\n"
"Aborting PTP clock driver registration\n");
return -1;
}
pdata->ptp_clock_ops = ether_ptp_clock_ops;
pdata->ptp_clock = ptp_clock_register(&pdata->ptp_clock_ops,
pdata->dev);
if (IS_ERR(pdata->ptp_clock)) {
pdata->ptp_clock = NULL;
dev_err(pdata->dev, "Fail to register PTP clock\n");
return -1;
}
/* By default enable nano second accuracy */
pdata->osi_core->ptp_config.one_nsec_accuracy = OSI_ENABLE;
return 0;
}
/**
* ether_ptp_remove: Function to de register ptp clock driver.
* @pdata: Pointer to private data structure.
*
* Algorithm: This function is used to de register the ptp clock
*
* Dependencies: PTP clock driver need to be sucessfully registered during
* initialization
*
* Protection: None.
*
* Return: None.
*/
void ether_ptp_remove(struct ether_priv_data *pdata)
{
if (pdata->ptp_clock) {
ptp_clock_unregister(pdata->ptp_clock);
}
}
/**
* ether_handle_hwtstamp_ioctl: Function to handle PTP settings.
* @pdata: Pointer to private data structure.
* @ifr: Interface request structure used for socket ioctl
*
* Algorithm: This function is used to handle the hardware PTP settings.
*
* Dependencies: PTP clock driver need to be sucessfully registered during
* initialization and HW need to support PTP functionality.
*
* Protection: None.
*
* Return: None.
*/
int ether_handle_hwtstamp_ioctl(struct ether_priv_data *pdata,
struct ifreq *ifr)
{
struct osi_core_priv_data *osi_core = pdata->osi_core;
struct hwtstamp_config config;
unsigned int hwts_rx_en = 1;
struct timespec now;
if (pdata->hw_feat.tsstssel == OSI_DISABLE) {
dev_err(pdata->dev, "HW timestamping not available\n");
return -EOPNOTSUPP;
}
if (copy_from_user(&config, ifr->ifr_data,
sizeof(struct hwtstamp_config))) {
return -EFAULT;
}
dev_err(pdata->dev, "config.flags = %#x, tx_type = %#x,"
"rx_filter = %#x\n", config.flags, config.tx_type,
config.rx_filter);
/* reserved for future extensions */
if (config.flags) {
return -EINVAL;
}
switch (config.tx_type) {
case HWTSTAMP_TX_OFF:
pdata->hwts_tx_en = OSI_DISABLE;
break;
case HWTSTAMP_TX_ON:
pdata->hwts_tx_en = OSI_ENABLE;
break;
default:
dev_err(pdata->dev, "tx_type is out of range\n");
return -ERANGE;
}
/* Initialize ptp filter to 0 */
osi_core->ptp_config.ptp_filter = 0;
switch (config.rx_filter) {
/* time stamp no incoming packet at all */
case HWTSTAMP_FILTER_NONE:
hwts_rx_en = 0;
break;
/* PTP v1, UDP, any kind of event packet */
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_SNAPTYPSEL_1 |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA;
break;
/* PTP v1, UDP, Sync packet */
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA;
break;
/* PTP v1, UDP, Delay_req packet */
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSMASTERENA |
OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA;
break;
/* PTP v2, UDP, any kind of event packet */
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_SNAPTYPSEL_1 |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA;
break;
/* PTP v2, UDP, Sync packet */
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA;
break;
/* PTP v2, UDP, Delay_req packet */
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_TSMASTERENA |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA;
break;
/* PTP v2/802.AS1, any layer, any kind of event packet */
case HWTSTAMP_FILTER_PTP_V2_EVENT:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_SNAPTYPSEL_1 |
OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA |
OSI_MAC_TCR_TSIPENA;
break;
/* PTP v2/802.AS1, any layer, Sync packet */
case HWTSTAMP_FILTER_PTP_V2_SYNC:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA |
OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_TSIPENA |
OSI_MAC_TCR_AV8021ASMEN;
break;
/* PTP v2/802.AS1, any layer, Delay_req packet */
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSIPV4ENA |
OSI_MAC_TCR_TSIPV6ENA |
OSI_MAC_TCR_TSVER2ENA |
OSI_MAC_TCR_TSEVENTENA |
OSI_MAC_TCR_AV8021ASMEN |
OSI_MAC_TCR_TSMASTERENA |
OSI_MAC_TCR_TSIPENA;
break;
/* time stamp any incoming packet */
case HWTSTAMP_FILTER_ALL:
osi_core->ptp_config.ptp_filter = OSI_MAC_TCR_TSENALL;
break;
default:
dev_err(pdata->dev, "rx_filter is out of range\n");
return -ERANGE;
}
if (!pdata->hwts_tx_en && !hwts_rx_en) {
/* disable the PTP configuration */
osi_ptp_configuration(osi_core, OSI_DISABLE);
} else {
/* Store SYS CLOCK */
osi_core->ptp_config.ptp_clock = OSI_ETHER_SYSCLOCK;
/* initialize system time */
getnstimeofday(&now);
/* Store sec and nsec */
osi_core->ptp_config.sec = now.tv_sec;
osi_core->ptp_config.nsec = now.tv_nsec;
/* one nsec accuracy */
osi_core->ptp_config.one_nsec_accuracy = OSI_ENABLE;
/* Enable the PTP configuration */
osi_ptp_configuration(osi_core, OSI_ENABLE);
}
return (copy_to_user(ifr->ifr_data, &config,
sizeof(struct hwtstamp_config))) ? -EFAULT : 0;
}