net: ethernet: ti: netcp: add support of cpts
This patch adds support of the cpts device found in the gbe and 10gbe ethernet switches on the keystone 2 SoCs (66AK2E/L/Hx, 66AK2Gx). Cc: Richard Cochran <richardcochran@gmail.com> Signed-off-by: WingMan Kwok <w-kwok2@ti.com> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
529ed12752
commit
6246168b4a
|
@ -75,12 +75,13 @@ config TI_CPSW
|
|||
|
||||
config TI_CPTS
|
||||
tristate "TI Common Platform Time Sync (CPTS) Support"
|
||||
depends on TI_CPSW
|
||||
depends on TI_CPSW || TI_KEYSTONE_NETCP
|
||||
select PTP_1588_CLOCK
|
||||
---help---
|
||||
This driver supports the Common Platform Time Sync unit of
|
||||
the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4
|
||||
and Layer 2 packets, and the driver offers a PTP Hardware Clock.
|
||||
the CPSW Ethernet Switch and Keystone 2 1g/10g Switch Subsystem.
|
||||
The unit can time stamp PTP UDP/IPv4 and Layer 2 packets, and the
|
||||
driver offers a PTP Hardware Clock.
|
||||
|
||||
config TI_KEYSTONE_NETCP
|
||||
tristate "TI Keystone NETCP Core Support"
|
||||
|
|
|
@ -121,7 +121,7 @@ struct netcp_packet {
|
|||
bool rxtstamp_complete;
|
||||
void *ts_context;
|
||||
|
||||
int (*txtstamp_complete)(void *ctx, struct netcp_packet *pkt);
|
||||
void (*txtstamp)(void *ctx, struct sk_buff *skb);
|
||||
};
|
||||
|
||||
static inline u32 *netcp_push_psdata(struct netcp_packet *p_info,
|
||||
|
|
|
@ -100,6 +100,11 @@ struct netcp_intf_modpriv {
|
|||
void *module_priv;
|
||||
};
|
||||
|
||||
struct netcp_tx_cb {
|
||||
void *ts_context;
|
||||
void (*txtstamp)(void *context, struct sk_buff *skb);
|
||||
};
|
||||
|
||||
static LIST_HEAD(netcp_devices);
|
||||
static LIST_HEAD(netcp_modules);
|
||||
static DEFINE_MUTEX(netcp_modules_lock);
|
||||
|
@ -544,6 +549,7 @@ int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netcp_register_rxhook);
|
||||
|
||||
int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
|
||||
netcp_hook_rtn *hook_rtn, void *hook_data)
|
||||
|
@ -566,6 +572,7 @@ int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
|
|||
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netcp_unregister_rxhook);
|
||||
|
||||
static void netcp_frag_free(bool is_frag, void *ptr)
|
||||
{
|
||||
|
@ -730,6 +737,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
|
|||
|
||||
/* Call each of the RX hooks */
|
||||
p_info.skb = skb;
|
||||
skb->dev = netcp->ndev;
|
||||
p_info.rxtstamp_complete = false;
|
||||
list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) {
|
||||
int ret;
|
||||
|
@ -987,6 +995,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
|
|||
unsigned int budget)
|
||||
{
|
||||
struct knav_dma_desc *desc;
|
||||
struct netcp_tx_cb *tx_cb;
|
||||
struct sk_buff *skb;
|
||||
unsigned int dma_sz;
|
||||
dma_addr_t dma;
|
||||
|
@ -1014,6 +1023,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
|
|||
continue;
|
||||
}
|
||||
|
||||
tx_cb = (struct netcp_tx_cb *)skb->cb;
|
||||
if (tx_cb->txtstamp)
|
||||
tx_cb->txtstamp(tx_cb->ts_context, skb);
|
||||
|
||||
if (netif_subqueue_stopped(netcp->ndev, skb) &&
|
||||
netif_running(netcp->ndev) &&
|
||||
(knav_pool_count(netcp->tx_pool) >
|
||||
|
@ -1154,6 +1167,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
|
|||
struct netcp_tx_pipe *tx_pipe = NULL;
|
||||
struct netcp_hook_list *tx_hook;
|
||||
struct netcp_packet p_info;
|
||||
struct netcp_tx_cb *tx_cb;
|
||||
unsigned int dma_sz;
|
||||
dma_addr_t dma;
|
||||
u32 tmp = 0;
|
||||
|
@ -1164,7 +1178,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
|
|||
p_info.tx_pipe = NULL;
|
||||
p_info.psdata_len = 0;
|
||||
p_info.ts_context = NULL;
|
||||
p_info.txtstamp_complete = NULL;
|
||||
p_info.txtstamp = NULL;
|
||||
p_info.epib = desc->epib;
|
||||
p_info.psdata = (u32 __force *)desc->psdata;
|
||||
memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(__le32));
|
||||
|
@ -1189,6 +1203,10 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
|
|||
goto out;
|
||||
}
|
||||
|
||||
tx_cb = (struct netcp_tx_cb *)skb->cb;
|
||||
tx_cb->ts_context = p_info.ts_context;
|
||||
tx_cb->txtstamp = p_info.txtstamp;
|
||||
|
||||
/* update descriptor */
|
||||
if (p_info.psdata_len) {
|
||||
/* psdata points to both native-endian and device-endian data */
|
||||
|
|
|
@ -23,10 +23,13 @@
|
|||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/ptp_classify.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "cpsw_ale.h"
|
||||
#include "netcp.h"
|
||||
#include "cpts.h"
|
||||
|
||||
#define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver"
|
||||
#define NETCP_DRIVER_VERSION "v1.0"
|
||||
|
@ -51,6 +54,7 @@
|
|||
#define GBE13_EMAC_OFFSET 0x100
|
||||
#define GBE13_SLAVE_PORT2_OFFSET 0x200
|
||||
#define GBE13_HW_STATS_OFFSET 0x300
|
||||
#define GBE13_CPTS_OFFSET 0x500
|
||||
#define GBE13_ALE_OFFSET 0x600
|
||||
#define GBE13_HOST_PORT_NUM 0
|
||||
#define GBE13_NUM_ALE_ENTRIES 1024
|
||||
|
@ -74,6 +78,7 @@
|
|||
#define GBENU_SLAVE_PORT_OFFSET 0x2000
|
||||
#define GBENU_EMAC_OFFSET 0x2330
|
||||
#define GBENU_HW_STATS_OFFSET 0x1a000
|
||||
#define GBENU_CPTS_OFFSET 0x1d000
|
||||
#define GBENU_ALE_OFFSET 0x1e000
|
||||
#define GBENU_HOST_PORT_NUM 0
|
||||
#define GBENU_NUM_ALE_ENTRIES 1024
|
||||
|
@ -93,6 +98,7 @@
|
|||
#define XGBE10_HOST_PORT_OFFSET 0x34
|
||||
#define XGBE10_SLAVE_PORT_OFFSET 0x64
|
||||
#define XGBE10_EMAC_OFFSET 0x400
|
||||
#define XGBE10_CPTS_OFFSET 0x600
|
||||
#define XGBE10_ALE_OFFSET 0x700
|
||||
#define XGBE10_HW_STATS_OFFSET 0x800
|
||||
#define XGBE10_HOST_PORT_NUM 0
|
||||
|
@ -155,6 +161,7 @@
|
|||
|
||||
#define GBE_TX_QUEUE 648
|
||||
#define GBE_TXHOOK_ORDER 0
|
||||
#define GBE_RXHOOK_ORDER 0
|
||||
#define GBE_DEFAULT_ALE_AGEOUT 30
|
||||
#define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY)
|
||||
#define NETCP_LINK_STATE_INVALID -1
|
||||
|
@ -169,6 +176,56 @@
|
|||
|
||||
#define HOST_TX_PRI_MAP_DEFAULT 0x00000000
|
||||
|
||||
#if IS_ENABLED(CONFIG_TI_CPTS)
|
||||
/* Px_TS_CTL register fields */
|
||||
#define TS_RX_ANX_F_EN BIT(0)
|
||||
#define TS_RX_VLAN_LT1_EN BIT(1)
|
||||
#define TS_RX_VLAN_LT2_EN BIT(2)
|
||||
#define TS_RX_ANX_D_EN BIT(3)
|
||||
#define TS_TX_ANX_F_EN BIT(4)
|
||||
#define TS_TX_VLAN_LT1_EN BIT(5)
|
||||
#define TS_TX_VLAN_LT2_EN BIT(6)
|
||||
#define TS_TX_ANX_D_EN BIT(7)
|
||||
#define TS_LT2_EN BIT(8)
|
||||
#define TS_RX_ANX_E_EN BIT(9)
|
||||
#define TS_TX_ANX_E_EN BIT(10)
|
||||
#define TS_MSG_TYPE_EN_SHIFT 16
|
||||
#define TS_MSG_TYPE_EN_MASK 0xffff
|
||||
|
||||
/* Px_TS_SEQ_LTYPE register fields */
|
||||
#define TS_SEQ_ID_OFS_SHIFT 16
|
||||
#define TS_SEQ_ID_OFS_MASK 0x3f
|
||||
|
||||
/* Px_TS_CTL_LTYPE2 register fields */
|
||||
#define TS_107 BIT(16)
|
||||
#define TS_129 BIT(17)
|
||||
#define TS_130 BIT(18)
|
||||
#define TS_131 BIT(19)
|
||||
#define TS_132 BIT(20)
|
||||
#define TS_319 BIT(21)
|
||||
#define TS_320 BIT(22)
|
||||
#define TS_TTL_NONZERO BIT(23)
|
||||
#define TS_UNI_EN BIT(24)
|
||||
#define TS_UNI_EN_SHIFT 24
|
||||
|
||||
#define TS_TX_ANX_ALL_EN \
|
||||
(TS_TX_ANX_D_EN | TS_TX_ANX_E_EN | TS_TX_ANX_F_EN)
|
||||
|
||||
#define TS_RX_ANX_ALL_EN \
|
||||
(TS_RX_ANX_D_EN | TS_RX_ANX_E_EN | TS_RX_ANX_F_EN)
|
||||
|
||||
#define TS_CTL_DST_PORT TS_319
|
||||
#define TS_CTL_DST_PORT_SHIFT 21
|
||||
|
||||
#define TS_CTL_MADDR_ALL \
|
||||
(TS_107 | TS_129 | TS_130 | TS_131 | TS_132)
|
||||
|
||||
#define TS_CTL_MADDR_SHIFT 16
|
||||
|
||||
/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */
|
||||
#define EVENT_MSG_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3))
|
||||
#endif /* CONFIG_TI_CPTS */
|
||||
|
||||
struct xgbe_ss_regs {
|
||||
u32 id_ver;
|
||||
u32 synce_count;
|
||||
|
@ -616,6 +673,13 @@ struct gbe_hw_stats {
|
|||
#define GBE_MAX_HW_STAT_MODS 9
|
||||
#define GBE_HW_STATS_REG_MAP_SZ 0x100
|
||||
|
||||
struct ts_ctl {
|
||||
int uni;
|
||||
u8 dst_port_map;
|
||||
u8 maddr_map;
|
||||
u8 ts_mcast_type;
|
||||
};
|
||||
|
||||
struct gbe_slave {
|
||||
void __iomem *port_regs;
|
||||
void __iomem *emac_regs;
|
||||
|
@ -630,6 +694,7 @@ struct gbe_slave {
|
|||
u32 mac_control;
|
||||
u8 phy_port_t;
|
||||
struct device_node *phy_node;
|
||||
struct ts_ctl ts_ctl;
|
||||
struct list_head slave_list;
|
||||
};
|
||||
|
||||
|
@ -655,6 +720,7 @@ struct gbe_priv {
|
|||
void __iomem *switch_regs;
|
||||
void __iomem *host_port_regs;
|
||||
void __iomem *ale_reg;
|
||||
void __iomem *cpts_reg;
|
||||
void __iomem *sgmii_port_regs;
|
||||
void __iomem *sgmii_port34_regs;
|
||||
void __iomem *xgbe_serdes_regs;
|
||||
|
@ -678,6 +744,9 @@ struct gbe_priv {
|
|||
int num_et_stats;
|
||||
/* Lock for updating the hwstats */
|
||||
spinlock_t hw_stats_lock;
|
||||
|
||||
int cpts_registered;
|
||||
struct cpts *cpts;
|
||||
};
|
||||
|
||||
struct gbe_intf {
|
||||
|
@ -1912,6 +1981,49 @@ static int keystone_set_link_ksettings(struct net_device *ndev,
|
|||
return phy_ethtool_ksettings_set(phy, cmd);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_TI_CPTS)
|
||||
static int keystone_get_ts_info(struct net_device *ndev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct netcp_intf *netcp = netdev_priv(ndev);
|
||||
struct gbe_intf *gbe_intf;
|
||||
|
||||
gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
|
||||
if (!gbe_intf || !gbe_intf->gbe_dev->cpts)
|
||||
return -EINVAL;
|
||||
|
||||
info->so_timestamping =
|
||||
SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
info->phc_index = gbe_intf->gbe_dev->cpts->phc_index;
|
||||
info->tx_types =
|
||||
(1 << HWTSTAMP_TX_OFF) |
|
||||
(1 << HWTSTAMP_TX_ON);
|
||||
info->rx_filters =
|
||||
(1 << HWTSTAMP_FILTER_NONE) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int keystone_get_ts_info(struct net_device *ndev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
info->so_timestamping =
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE;
|
||||
info->phc_index = -1;
|
||||
info->tx_types = 0;
|
||||
info->rx_filters = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TI_CPTS */
|
||||
|
||||
static const struct ethtool_ops keystone_ethtool_ops = {
|
||||
.get_drvinfo = keystone_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
|
@ -1922,6 +2034,7 @@ static const struct ethtool_ops keystone_ethtool_ops = {
|
|||
.get_ethtool_stats = keystone_get_ethtool_stats,
|
||||
.get_link_ksettings = keystone_get_link_ksettings,
|
||||
.set_link_ksettings = keystone_set_link_ksettings,
|
||||
.get_ts_info = keystone_get_ts_info,
|
||||
};
|
||||
|
||||
#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
|
||||
|
@ -2365,16 +2478,279 @@ static int gbe_del_vid(void *intf_priv, int vid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_TI_CPTS)
|
||||
#define HAS_PHY_TXTSTAMP(p) ((p)->drv && (p)->drv->txtstamp)
|
||||
#define HAS_PHY_RXTSTAMP(p) ((p)->drv && (p)->drv->rxtstamp)
|
||||
|
||||
static void gbe_txtstamp(void *context, struct sk_buff *skb)
|
||||
{
|
||||
struct gbe_intf *gbe_intf = context;
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
|
||||
cpts_tx_timestamp(gbe_dev->cpts, skb);
|
||||
}
|
||||
|
||||
static bool gbe_need_txtstamp(struct gbe_intf *gbe_intf,
|
||||
const struct netcp_packet *p_info)
|
||||
{
|
||||
struct sk_buff *skb = p_info->skb;
|
||||
unsigned int class = ptp_classify_raw(skb);
|
||||
|
||||
if (class == PTP_CLASS_NONE)
|
||||
return false;
|
||||
|
||||
switch (class) {
|
||||
case PTP_CLASS_V1_IPV4:
|
||||
case PTP_CLASS_V1_IPV6:
|
||||
case PTP_CLASS_V2_IPV4:
|
||||
case PTP_CLASS_V2_IPV6:
|
||||
case PTP_CLASS_V2_L2:
|
||||
case (PTP_CLASS_V2_VLAN | PTP_CLASS_L2):
|
||||
case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV4):
|
||||
case (PTP_CLASS_V2_VLAN | PTP_CLASS_IPV6):
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int gbe_txtstamp_mark_pkt(struct gbe_intf *gbe_intf,
|
||||
struct netcp_packet *p_info)
|
||||
{
|
||||
struct phy_device *phydev = p_info->skb->dev->phydev;
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
|
||||
if (!(skb_shinfo(p_info->skb)->tx_flags & SKBTX_HW_TSTAMP) ||
|
||||
!cpts_is_tx_enabled(gbe_dev->cpts))
|
||||
return 0;
|
||||
|
||||
/* If phy has the txtstamp api, assume it will do it.
|
||||
* We mark it here because skb_tx_timestamp() is called
|
||||
* after all the txhooks are called.
|
||||
*/
|
||||
if (phydev && HAS_PHY_TXTSTAMP(phydev)) {
|
||||
skb_shinfo(p_info->skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gbe_need_txtstamp(gbe_intf, p_info)) {
|
||||
p_info->txtstamp = gbe_txtstamp;
|
||||
p_info->ts_context = (void *)gbe_intf;
|
||||
skb_shinfo(p_info->skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gbe_rxtstamp(struct gbe_intf *gbe_intf, struct netcp_packet *p_info)
|
||||
{
|
||||
struct phy_device *phydev = p_info->skb->dev->phydev;
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
|
||||
if (p_info->rxtstamp_complete)
|
||||
return 0;
|
||||
|
||||
if (phydev && HAS_PHY_RXTSTAMP(phydev)) {
|
||||
p_info->rxtstamp_complete = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpts_rx_timestamp(gbe_dev->cpts, p_info->skb);
|
||||
p_info->rxtstamp_complete = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gbe_hwtstamp_get(struct gbe_intf *gbe_intf, struct ifreq *ifr)
|
||||
{
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
struct cpts *cpts = gbe_dev->cpts;
|
||||
struct hwtstamp_config cfg;
|
||||
|
||||
if (!cpts)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
cfg.flags = 0;
|
||||
cfg.tx_type = cpts_is_tx_enabled(cpts) ?
|
||||
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
||||
cfg.rx_filter = (cpts_is_rx_enabled(cpts) ?
|
||||
cpts->rx_enable : HWTSTAMP_FILTER_NONE);
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static void gbe_hwtstamp(struct gbe_intf *gbe_intf)
|
||||
{
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
struct gbe_slave *slave = gbe_intf->slave;
|
||||
u32 ts_en, seq_id, ctl;
|
||||
|
||||
if (!cpts_is_rx_enabled(gbe_dev->cpts) &&
|
||||
!cpts_is_tx_enabled(gbe_dev->cpts)) {
|
||||
writel(0, GBE_REG_ADDR(slave, port_regs, ts_ctl));
|
||||
return;
|
||||
}
|
||||
|
||||
seq_id = (30 << TS_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
|
||||
ts_en = EVENT_MSG_BITS << TS_MSG_TYPE_EN_SHIFT;
|
||||
ctl = ETH_P_1588 | TS_TTL_NONZERO |
|
||||
(slave->ts_ctl.dst_port_map << TS_CTL_DST_PORT_SHIFT) |
|
||||
(slave->ts_ctl.uni ? TS_UNI_EN :
|
||||
slave->ts_ctl.maddr_map << TS_CTL_MADDR_SHIFT);
|
||||
|
||||
if (cpts_is_tx_enabled(gbe_dev->cpts))
|
||||
ts_en |= (TS_TX_ANX_ALL_EN | TS_TX_VLAN_LT1_EN);
|
||||
|
||||
if (cpts_is_rx_enabled(gbe_dev->cpts))
|
||||
ts_en |= (TS_RX_ANX_ALL_EN | TS_RX_VLAN_LT1_EN);
|
||||
|
||||
writel(ts_en, GBE_REG_ADDR(slave, port_regs, ts_ctl));
|
||||
writel(seq_id, GBE_REG_ADDR(slave, port_regs, ts_seq_ltype));
|
||||
writel(ctl, GBE_REG_ADDR(slave, port_regs, ts_ctl_ltype2));
|
||||
}
|
||||
|
||||
static int gbe_hwtstamp_set(struct gbe_intf *gbe_intf, struct ifreq *ifr)
|
||||
{
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
struct cpts *cpts = gbe_dev->cpts;
|
||||
struct hwtstamp_config cfg;
|
||||
|
||||
if (!cpts)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
|
||||
return -EFAULT;
|
||||
|
||||
/* reserved for future extensions */
|
||||
if (cfg.flags)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cfg.tx_type) {
|
||||
case HWTSTAMP_TX_OFF:
|
||||
cpts_tx_enable(cpts, 0);
|
||||
break;
|
||||
case HWTSTAMP_TX_ON:
|
||||
cpts_tx_enable(cpts, 1);
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
switch (cfg.rx_filter) {
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
cpts_rx_enable(cpts, 0);
|
||||
break;
|
||||
case HWTSTAMP_FILTER_ALL:
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
|
||||
cpts_rx_enable(cpts, HWTSTAMP_FILTER_PTP_V1_L4_EVENT);
|
||||
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||
cpts_rx_enable(cpts, HWTSTAMP_FILTER_PTP_V2_EVENT);
|
||||
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
gbe_hwtstamp(gbe_intf);
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static void gbe_register_cpts(struct gbe_priv *gbe_dev)
|
||||
{
|
||||
if (!gbe_dev->cpts)
|
||||
return;
|
||||
|
||||
if (gbe_dev->cpts_registered > 0)
|
||||
goto done;
|
||||
|
||||
if (cpts_register(gbe_dev->cpts)) {
|
||||
dev_err(gbe_dev->dev, "error registering cpts device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
done:
|
||||
++gbe_dev->cpts_registered;
|
||||
}
|
||||
|
||||
static void gbe_unregister_cpts(struct gbe_priv *gbe_dev)
|
||||
{
|
||||
if (!gbe_dev->cpts || (gbe_dev->cpts_registered <= 0))
|
||||
return;
|
||||
|
||||
if (--gbe_dev->cpts_registered)
|
||||
return;
|
||||
|
||||
cpts_unregister(gbe_dev->cpts);
|
||||
}
|
||||
#else
|
||||
static inline int gbe_txtstamp_mark_pkt(struct gbe_intf *gbe_intf,
|
||||
struct netcp_packet *p_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gbe_rxtstamp(struct gbe_intf *gbe_intf,
|
||||
struct netcp_packet *p_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int gbe_hwtstamp(struct gbe_intf *gbe_intf,
|
||||
struct ifreq *ifr, int cmd)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void gbe_register_cpts(struct gbe_priv *gbe_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void gbe_unregister_cpts(struct gbe_priv *gbe_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int gbe_hwtstamp_get(struct gbe_intf *gbe_intf, struct ifreq *req)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int gbe_hwtstamp_set(struct gbe_intf *gbe_intf, struct ifreq *req)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* CONFIG_TI_CPTS */
|
||||
|
||||
static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd)
|
||||
{
|
||||
struct gbe_intf *gbe_intf = intf_priv;
|
||||
struct phy_device *phy = gbe_intf->slave->phy;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (!phy || !phy->drv->hwtstamp) {
|
||||
switch (cmd) {
|
||||
case SIOCGHWTSTAMP:
|
||||
return gbe_hwtstamp_get(gbe_intf, req);
|
||||
case SIOCSHWTSTAMP:
|
||||
return gbe_hwtstamp_set(gbe_intf, req);
|
||||
}
|
||||
}
|
||||
|
||||
if (phy)
|
||||
ret = phy_mii_ioctl(phy, req, cmd);
|
||||
return phy_mii_ioctl(phy, req, cmd);
|
||||
|
||||
return ret;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void netcp_ethss_timer(unsigned long arg)
|
||||
|
@ -2410,12 +2786,20 @@ static void netcp_ethss_timer(unsigned long arg)
|
|||
add_timer(&gbe_dev->timer);
|
||||
}
|
||||
|
||||
static int gbe_tx_hook(int order, void *data, struct netcp_packet *p_info)
|
||||
static int gbe_txhook(int order, void *data, struct netcp_packet *p_info)
|
||||
{
|
||||
struct gbe_intf *gbe_intf = data;
|
||||
|
||||
p_info->tx_pipe = &gbe_intf->tx_pipe;
|
||||
return 0;
|
||||
|
||||
return gbe_txtstamp_mark_pkt(gbe_intf, p_info);
|
||||
}
|
||||
|
||||
static int gbe_rxhook(int order, void *data, struct netcp_packet *p_info)
|
||||
{
|
||||
struct gbe_intf *gbe_intf = data;
|
||||
|
||||
return gbe_rxtstamp(gbe_intf, p_info);
|
||||
}
|
||||
|
||||
static int gbe_open(void *intf_priv, struct net_device *ndev)
|
||||
|
@ -2465,11 +2849,14 @@ static int gbe_open(void *intf_priv, struct net_device *ndev)
|
|||
if (ret)
|
||||
goto fail;
|
||||
|
||||
netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
|
||||
gbe_intf);
|
||||
netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_txhook, gbe_intf);
|
||||
netcp_register_rxhook(netcp, GBE_RXHOOK_ORDER, gbe_rxhook, gbe_intf);
|
||||
|
||||
slave->open = true;
|
||||
netcp_ethss_update_link_state(gbe_dev, slave, ndev);
|
||||
|
||||
gbe_register_cpts(gbe_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
@ -2481,16 +2868,36 @@ static int gbe_close(void *intf_priv, struct net_device *ndev)
|
|||
{
|
||||
struct gbe_intf *gbe_intf = intf_priv;
|
||||
struct netcp_intf *netcp = netdev_priv(ndev);
|
||||
struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
|
||||
|
||||
gbe_unregister_cpts(gbe_dev);
|
||||
|
||||
gbe_slave_stop(gbe_intf);
|
||||
netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
|
||||
gbe_intf);
|
||||
|
||||
netcp_unregister_rxhook(netcp, GBE_RXHOOK_ORDER, gbe_rxhook, gbe_intf);
|
||||
netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_txhook, gbe_intf);
|
||||
|
||||
gbe_intf->slave->open = false;
|
||||
atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_TI_CPTS)
|
||||
static void init_slave_ts_ctl(struct gbe_slave *slave)
|
||||
{
|
||||
slave->ts_ctl.uni = 1;
|
||||
slave->ts_ctl.dst_port_map =
|
||||
(TS_CTL_DST_PORT >> TS_CTL_DST_PORT_SHIFT) & 0x3;
|
||||
slave->ts_ctl.maddr_map =
|
||||
(TS_CTL_MADDR_ALL >> TS_CTL_MADDR_SHIFT) & 0x1f;
|
||||
}
|
||||
|
||||
#else
|
||||
static void init_slave_ts_ctl(struct gbe_slave *slave)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_TI_CPTS */
|
||||
|
||||
static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
|
||||
struct device_node *node)
|
||||
{
|
||||
|
@ -2605,6 +3012,8 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
|
|||
}
|
||||
|
||||
atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID);
|
||||
|
||||
init_slave_ts_ctl(slave);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2795,6 +3204,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
|
|||
XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i);
|
||||
|
||||
gbe_dev->ale_reg = gbe_dev->switch_regs + XGBE10_ALE_OFFSET;
|
||||
gbe_dev->cpts_reg = gbe_dev->switch_regs + XGBE10_CPTS_OFFSET;
|
||||
gbe_dev->ale_ports = gbe_dev->max_num_ports;
|
||||
gbe_dev->host_port = XGBE10_HOST_PORT_NUM;
|
||||
gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES;
|
||||
|
@ -2917,6 +3327,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
|
|||
(GBE_HW_STATS_REG_MAP_SZ * (i & 0x1));
|
||||
}
|
||||
|
||||
gbe_dev->cpts_reg = gbe_dev->switch_regs + GBE13_CPTS_OFFSET;
|
||||
gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET;
|
||||
gbe_dev->ale_ports = gbe_dev->max_num_ports;
|
||||
gbe_dev->host_port = GBE13_HOST_PORT_NUM;
|
||||
|
@ -3006,6 +3417,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev,
|
|||
gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs +
|
||||
GBENU_HW_STATS_OFFSET + (GBENU_HW_STATS_REG_MAP_SZ * i);
|
||||
|
||||
gbe_dev->cpts_reg = gbe_dev->switch_regs + GBENU_CPTS_OFFSET;
|
||||
gbe_dev->ale_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET;
|
||||
gbe_dev->ale_ports = gbe_dev->max_num_ports;
|
||||
gbe_dev->host_port = GBENU_HOST_PORT_NUM;
|
||||
|
@ -3187,6 +3599,12 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
|
|||
dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
|
||||
}
|
||||
|
||||
gbe_dev->cpts = cpts_create(gbe_dev->dev, gbe_dev->cpts_reg, node);
|
||||
if (IS_ENABLED(CONFIG_TI_CPTS) && IS_ERR(gbe_dev->cpts)) {
|
||||
ret = PTR_ERR(gbe_dev->cpts);
|
||||
goto free_sec_ports;
|
||||
}
|
||||
|
||||
/* initialize host port */
|
||||
gbe_init_host_port(gbe_dev);
|
||||
|
||||
|
@ -3275,6 +3693,7 @@ static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
|
|||
struct gbe_priv *gbe_dev = inst_priv;
|
||||
|
||||
del_timer_sync(&gbe_dev->timer);
|
||||
cpts_release(gbe_dev->cpts);
|
||||
cpsw_ale_stop(gbe_dev->ale);
|
||||
cpsw_ale_destroy(gbe_dev->ale);
|
||||
netcp_txpipe_close(&gbe_dev->tx_pipe);
|
||||
|
|
Loading…
Reference in a new issue