Commit 6246168b authored by WingMan Kwok's avatar WingMan Kwok Committed by David S. Miller

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: default avatarWingMan Kwok <w-kwok2@ti.com>
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 529ed127
...@@ -75,12 +75,13 @@ config TI_CPSW ...@@ -75,12 +75,13 @@ config TI_CPSW
config TI_CPTS config TI_CPTS
tristate "TI Common Platform Time Sync (CPTS) Support" tristate "TI Common Platform Time Sync (CPTS) Support"
depends on TI_CPSW depends on TI_CPSW || TI_KEYSTONE_NETCP
select PTP_1588_CLOCK select PTP_1588_CLOCK
---help--- ---help---
This driver supports the Common Platform Time Sync unit of This driver supports the Common Platform Time Sync unit of
the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4 the CPSW Ethernet Switch and Keystone 2 1g/10g Switch Subsystem.
and Layer 2 packets, and the driver offers a PTP Hardware Clock. The unit can time stamp PTP UDP/IPv4 and Layer 2 packets, and the
driver offers a PTP Hardware Clock.
config TI_KEYSTONE_NETCP config TI_KEYSTONE_NETCP
tristate "TI Keystone NETCP Core Support" tristate "TI Keystone NETCP Core Support"
......
...@@ -121,7 +121,7 @@ struct netcp_packet { ...@@ -121,7 +121,7 @@ struct netcp_packet {
bool rxtstamp_complete; bool rxtstamp_complete;
void *ts_context; 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, static inline u32 *netcp_push_psdata(struct netcp_packet *p_info,
......
...@@ -100,6 +100,11 @@ struct netcp_intf_modpriv { ...@@ -100,6 +100,11 @@ struct netcp_intf_modpriv {
void *module_priv; 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_devices);
static LIST_HEAD(netcp_modules); static LIST_HEAD(netcp_modules);
static DEFINE_MUTEX(netcp_modules_lock); static DEFINE_MUTEX(netcp_modules_lock);
...@@ -544,6 +549,7 @@ int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order, ...@@ -544,6 +549,7 @@ int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(netcp_register_rxhook);
int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
netcp_hook_rtn *hook_rtn, void *hook_data) netcp_hook_rtn *hook_rtn, void *hook_data)
...@@ -566,6 +572,7 @@ int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order, ...@@ -566,6 +572,7 @@ int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
return -ENOENT; return -ENOENT;
} }
EXPORT_SYMBOL_GPL(netcp_unregister_rxhook);
static void netcp_frag_free(bool is_frag, void *ptr) 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) ...@@ -730,6 +737,7 @@ static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
/* Call each of the RX hooks */ /* Call each of the RX hooks */
p_info.skb = skb; p_info.skb = skb;
skb->dev = netcp->ndev;
p_info.rxtstamp_complete = false; p_info.rxtstamp_complete = false;
list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) { list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) {
int ret; int ret;
...@@ -987,6 +995,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, ...@@ -987,6 +995,7 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
unsigned int budget) unsigned int budget)
{ {
struct knav_dma_desc *desc; struct knav_dma_desc *desc;
struct netcp_tx_cb *tx_cb;
struct sk_buff *skb; struct sk_buff *skb;
unsigned int dma_sz; unsigned int dma_sz;
dma_addr_t dma; dma_addr_t dma;
...@@ -1014,6 +1023,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp, ...@@ -1014,6 +1023,10 @@ static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
continue; 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) && if (netif_subqueue_stopped(netcp->ndev, skb) &&
netif_running(netcp->ndev) && netif_running(netcp->ndev) &&
(knav_pool_count(netcp->tx_pool) > (knav_pool_count(netcp->tx_pool) >
...@@ -1154,6 +1167,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp, ...@@ -1154,6 +1167,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
struct netcp_tx_pipe *tx_pipe = NULL; struct netcp_tx_pipe *tx_pipe = NULL;
struct netcp_hook_list *tx_hook; struct netcp_hook_list *tx_hook;
struct netcp_packet p_info; struct netcp_packet p_info;
struct netcp_tx_cb *tx_cb;
unsigned int dma_sz; unsigned int dma_sz;
dma_addr_t dma; dma_addr_t dma;
u32 tmp = 0; u32 tmp = 0;
...@@ -1164,7 +1178,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp, ...@@ -1164,7 +1178,7 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
p_info.tx_pipe = NULL; p_info.tx_pipe = NULL;
p_info.psdata_len = 0; p_info.psdata_len = 0;
p_info.ts_context = NULL; p_info.ts_context = NULL;
p_info.txtstamp_complete = NULL; p_info.txtstamp = NULL;
p_info.epib = desc->epib; p_info.epib = desc->epib;
p_info.psdata = (u32 __force *)desc->psdata; p_info.psdata = (u32 __force *)desc->psdata;
memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(__le32)); 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, ...@@ -1189,6 +1203,10 @@ static int netcp_tx_submit_skb(struct netcp_intf *netcp,
goto out; 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 */ /* update descriptor */
if (p_info.psdata_len) { if (p_info.psdata_len) {
/* psdata points to both native-endian and device-endian data */ /* psdata points to both native-endian and device-endian data */
......
...@@ -23,10 +23,13 @@ ...@@ -23,10 +23,13 @@
#include <linux/of_mdio.h> #include <linux/of_mdio.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/ptp_classify.h>
#include <linux/net_tstamp.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include "cpsw_ale.h" #include "cpsw_ale.h"
#include "netcp.h" #include "netcp.h"
#include "cpts.h"
#define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver" #define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver"
#define NETCP_DRIVER_VERSION "v1.0" #define NETCP_DRIVER_VERSION "v1.0"
...@@ -51,6 +54,7 @@ ...@@ -51,6 +54,7 @@
#define GBE13_EMAC_OFFSET 0x100 #define GBE13_EMAC_OFFSET 0x100
#define GBE13_SLAVE_PORT2_OFFSET 0x200 #define GBE13_SLAVE_PORT2_OFFSET 0x200
#define GBE13_HW_STATS_OFFSET 0x300 #define GBE13_HW_STATS_OFFSET 0x300
#define GBE13_CPTS_OFFSET 0x500
#define GBE13_ALE_OFFSET 0x600 #define GBE13_ALE_OFFSET 0x600
#define GBE13_HOST_PORT_NUM 0 #define GBE13_HOST_PORT_NUM 0
#define GBE13_NUM_ALE_ENTRIES 1024 #define GBE13_NUM_ALE_ENTRIES 1024
...@@ -74,6 +78,7 @@ ...@@ -74,6 +78,7 @@
#define GBENU_SLAVE_PORT_OFFSET 0x2000 #define GBENU_SLAVE_PORT_OFFSET 0x2000
#define GBENU_EMAC_OFFSET 0x2330 #define GBENU_EMAC_OFFSET 0x2330
#define GBENU_HW_STATS_OFFSET 0x1a000 #define GBENU_HW_STATS_OFFSET 0x1a000
#define GBENU_CPTS_OFFSET 0x1d000
#define GBENU_ALE_OFFSET 0x1e000 #define GBENU_ALE_OFFSET 0x1e000
#define GBENU_HOST_PORT_NUM 0 #define GBENU_HOST_PORT_NUM 0
#define GBENU_NUM_ALE_ENTRIES 1024 #define GBENU_NUM_ALE_ENTRIES 1024
...@@ -93,6 +98,7 @@ ...@@ -93,6 +98,7 @@
#define XGBE10_HOST_PORT_OFFSET 0x34 #define XGBE10_HOST_PORT_OFFSET 0x34
#define XGBE10_SLAVE_PORT_OFFSET 0x64 #define XGBE10_SLAVE_PORT_OFFSET 0x64
#define XGBE10_EMAC_OFFSET 0x400 #define XGBE10_EMAC_OFFSET 0x400
#define XGBE10_CPTS_OFFSET 0x600
#define XGBE10_ALE_OFFSET 0x700 #define XGBE10_ALE_OFFSET 0x700
#define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HW_STATS_OFFSET 0x800
#define XGBE10_HOST_PORT_NUM 0 #define XGBE10_HOST_PORT_NUM 0
...@@ -155,6 +161,7 @@ ...@@ -155,6 +161,7 @@
#define GBE_TX_QUEUE 648 #define GBE_TX_QUEUE 648
#define GBE_TXHOOK_ORDER 0 #define GBE_TXHOOK_ORDER 0
#define GBE_RXHOOK_ORDER 0
#define GBE_DEFAULT_ALE_AGEOUT 30 #define GBE_DEFAULT_ALE_AGEOUT 30
#define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY) #define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY)
#define NETCP_LINK_STATE_INVALID -1 #define NETCP_LINK_STATE_INVALID -1
...@@ -169,6 +176,56 @@ ...@@ -169,6 +176,56 @@
#define HOST_TX_PRI_MAP_DEFAULT 0x00000000 #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 { struct xgbe_ss_regs {
u32 id_ver; u32 id_ver;
u32 synce_count; u32 synce_count;
...@@ -616,6 +673,13 @@ struct gbe_hw_stats { ...@@ -616,6 +673,13 @@ struct gbe_hw_stats {
#define GBE_MAX_HW_STAT_MODS 9 #define GBE_MAX_HW_STAT_MODS 9
#define GBE_HW_STATS_REG_MAP_SZ 0x100 #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 { struct gbe_slave {
void __iomem *port_regs; void __iomem *port_regs;
void __iomem *emac_regs; void __iomem *emac_regs;
...@@ -630,6 +694,7 @@ struct gbe_slave { ...@@ -630,6 +694,7 @@ struct gbe_slave {
u32 mac_control; u32 mac_control;
u8 phy_port_t; u8 phy_port_t;
struct device_node *phy_node; struct device_node *phy_node;
struct ts_ctl ts_ctl;
struct list_head slave_list; struct list_head slave_list;
}; };
...@@ -655,6 +720,7 @@ struct gbe_priv { ...@@ -655,6 +720,7 @@ struct gbe_priv {
void __iomem *switch_regs; void __iomem *switch_regs;
void __iomem *host_port_regs; void __iomem *host_port_regs;
void __iomem *ale_reg; void __iomem *ale_reg;
void __iomem *cpts_reg;
void __iomem *sgmii_port_regs; void __iomem *sgmii_port_regs;
void __iomem *sgmii_port34_regs; void __iomem *sgmii_port34_regs;
void __iomem *xgbe_serdes_regs; void __iomem *xgbe_serdes_regs;
...@@ -678,6 +744,9 @@ struct gbe_priv { ...@@ -678,6 +744,9 @@ struct gbe_priv {
int num_et_stats; int num_et_stats;
/* Lock for updating the hwstats */ /* Lock for updating the hwstats */
spinlock_t hw_stats_lock; spinlock_t hw_stats_lock;
int cpts_registered;
struct cpts *cpts;
}; };
struct gbe_intf { struct gbe_intf {
...@@ -1912,6 +1981,49 @@ static int keystone_set_link_ksettings(struct net_device *ndev, ...@@ -1912,6 +1981,49 @@ static int keystone_set_link_ksettings(struct net_device *ndev,
return phy_ethtool_ksettings_set(phy, cmd); 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 = { static const struct ethtool_ops keystone_ethtool_ops = {
.get_drvinfo = keystone_get_drvinfo, .get_drvinfo = keystone_get_drvinfo,
.get_link = ethtool_op_get_link, .get_link = ethtool_op_get_link,
...@@ -1922,6 +2034,7 @@ static const struct ethtool_ops keystone_ethtool_ops = { ...@@ -1922,6 +2034,7 @@ static const struct ethtool_ops keystone_ethtool_ops = {
.get_ethtool_stats = keystone_get_ethtool_stats, .get_ethtool_stats = keystone_get_ethtool_stats,
.get_link_ksettings = keystone_get_link_ksettings, .get_link_ksettings = keystone_get_link_ksettings,
.set_link_ksettings = keystone_set_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) | \ #define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
...@@ -2365,16 +2478,279 @@ static int gbe_del_vid(void *intf_priv, int vid) ...@@ -2365,16 +2478,279 @@ static int gbe_del_vid(void *intf_priv, int vid)
return 0; 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) static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd)
{ {
struct gbe_intf *gbe_intf = intf_priv; struct gbe_intf *gbe_intf = intf_priv;
struct phy_device *phy = gbe_intf->slave->phy; 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) 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) static void netcp_ethss_timer(unsigned long arg)
...@@ -2410,12 +2786,20 @@ 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); 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; struct gbe_intf *gbe_intf = data;
p_info->tx_pipe = &gbe_intf->tx_pipe; 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) 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) ...@@ -2465,11 +2849,14 @@ static int gbe_open(void *intf_priv, struct net_device *ndev)
if (ret) if (ret)
goto fail; goto fail;
netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook, netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_txhook, gbe_intf);
gbe_intf); netcp_register_rxhook(netcp, GBE_RXHOOK_ORDER, gbe_rxhook, gbe_intf);
slave->open = true; slave->open = true;
netcp_ethss_update_link_state(gbe_dev, slave, ndev); netcp_ethss_update_link_state(gbe_dev, slave, ndev);
gbe_register_cpts(gbe_dev);
return 0; return 0;
fail: fail:
...@@ -2481,16 +2868,36 @@ static int gbe_close(void *intf_priv, struct net_device *ndev) ...@@ -2481,16 +2868,36 @@ static int gbe_close(void *intf_priv, struct net_device *ndev)
{ {
struct gbe_intf *gbe_intf = intf_priv; struct gbe_intf *gbe_intf = intf_priv;
struct netcp_intf *netcp = netdev_priv(ndev); 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); 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; gbe_intf->slave->open = false;
atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID); atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID);
return 0; 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, static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
struct device_node *node) struct device_node *node)
{ {
...@@ -2605,6 +3012,8 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, ...@@ -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); atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID);
init_slave_ts_ctl(slave);
return 0; return 0;
} }
...@@ -2795,6 +3204,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ...@@ -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); XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i);
gbe_dev->ale_reg = gbe_dev->switch_regs + XGBE10_ALE_OFFSET; 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->ale_ports = gbe_dev->max_num_ports;
gbe_dev->host_port = XGBE10_HOST_PORT_NUM; gbe_dev->host_port = XGBE10_HOST_PORT_NUM;
gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES;
...@@ -2917,6 +3327,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, ...@@ -2917,6 +3327,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
(GBE_HW_STATS_REG_MAP_SZ * (i & 0x1)); (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_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET;
gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->ale_ports = gbe_dev->max_num_ports;
gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->host_port = GBE13_HOST_PORT_NUM;
...@@ -3006,6 +3417,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, ...@@ -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 + gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs +
GBENU_HW_STATS_OFFSET + (GBENU_HW_STATS_REG_MAP_SZ * i); 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_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET;
gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->ale_ports = gbe_dev->max_num_ports;
gbe_dev->host_port = GBENU_HOST_PORT_NUM; gbe_dev->host_port = GBENU_HOST_PORT_NUM;
...@@ -3187,6 +3599,12 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, ...@@ -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"); 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 */ /* initialize host port */
gbe_init_host_port(gbe_dev); gbe_init_host_port(gbe_dev);
...@@ -3275,6 +3693,7 @@ static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv) ...@@ -3275,6 +3693,7 @@ static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
struct gbe_priv *gbe_dev = inst_priv; struct gbe_priv *gbe_dev = inst_priv;
del_timer_sync(&gbe_dev->timer); del_timer_sync(&gbe_dev->timer);
cpts_release(gbe_dev->cpts);
cpsw_ale_stop(gbe_dev->ale); cpsw_ale_stop(gbe_dev->ale);
cpsw_ale_destroy(gbe_dev->ale); cpsw_ale_destroy(gbe_dev->ale);
netcp_txpipe_close(&gbe_dev->tx_pipe); netcp_txpipe_close(&gbe_dev->tx_pipe);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment