Skip to content

Commit

Permalink
Merge branch 'cpsw-allow-vlan-h-w-timestamping'
Browse files Browse the repository at this point in the history
Ivan Khoronzhuk says:

====================
net: ethernet: ti: cpsw: allow vlan h/w timestamping

The patchset adds several improvements and allows vlan h/w ts.

Based on net-next/master
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 14, 2018
2 parents 3e536cf + 1ebb244 commit 4fd3e2a
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 84 deletions.
51 changes: 27 additions & 24 deletions drivers/net/ethernet/ti/cpsw.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ struct cpsw_ss_regs {

#define CTRL_V2_TS_BITS \
(TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\
TS_TTL_NONZERO | TS_ANNEX_D_EN | TS_LTYPE1_EN)
TS_TTL_NONZERO | TS_ANNEX_D_EN | TS_LTYPE1_EN | VLAN_LTYPE1_EN)

#define CTRL_V2_ALL_TS_MASK (CTRL_V2_TS_BITS | TS_TX_EN | TS_RX_EN)
#define CTRL_V2_TX_TS_BITS (CTRL_V2_TS_BITS | TS_TX_EN)
Expand All @@ -293,7 +293,7 @@ struct cpsw_ss_regs {
#define CTRL_V3_TS_BITS \
(TS_107 | TS_320 | TS_319 | TS_132 | TS_131 | TS_130 | TS_129 |\
TS_TTL_NONZERO | TS_ANNEX_F_EN | TS_ANNEX_D_EN |\
TS_LTYPE1_EN)
TS_LTYPE1_EN | VLAN_LTYPE1_EN)

#define CTRL_V3_ALL_TS_MASK (CTRL_V3_TS_BITS | TS_TX_EN | TS_RX_EN)
#define CTRL_V3_TX_TS_BITS (CTRL_V3_TS_BITS | TS_TX_EN)
Expand Down Expand Up @@ -466,6 +466,8 @@ struct cpsw_priv {
bool mqprio_hw;
int fifo_bw[CPSW_TC_NUM];
int shp_cfg_speed;
int tx_ts_enabled;
int rx_ts_enabled;
u32 emac_port;
struct cpsw_common *cpsw;
};
Expand Down Expand Up @@ -905,6 +907,7 @@ static void cpsw_rx_handler(void *token, int len, int status)
struct net_device *ndev = skb->dev;
int ret = 0, port;
struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
struct cpsw_priv *priv;

if (cpsw->data.dual_emac) {
port = CPDMA_RX_SOURCE_PORT(status);
Expand Down Expand Up @@ -939,7 +942,9 @@ static void cpsw_rx_handler(void *token, int len, int status)
skb_put(skb, len);
if (status & CPDMA_RX_VLAN_ENCAP)
cpsw_rx_vlan_encap(skb);
cpts_rx_timestamp(cpsw->cpts, skb);
priv = netdev_priv(ndev);
if (priv->rx_ts_enabled)
cpts_rx_timestamp(cpsw->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
netif_receive_skb(skb);
ndev->stats.rx_bytes += len;
Expand Down Expand Up @@ -2126,7 +2131,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
}

if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
cpts_is_tx_enabled(cpts) && cpts_can_timestamp(cpts, skb))
priv->tx_ts_enabled && cpts_can_timestamp(cpts, skb))
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;

q_idx = skb_get_queue_mapping(skb);
Expand Down Expand Up @@ -2170,24 +2175,24 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,

#if IS_ENABLED(CONFIG_TI_CPTS)

static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
{
struct cpsw_common *cpsw = priv->cpsw;
struct cpsw_slave *slave = &cpsw->slaves[cpsw->data.active_slave];
u32 ts_en, seq_id;

if (!cpts_is_tx_enabled(cpsw->cpts) &&
!cpts_is_rx_enabled(cpsw->cpts)) {
if (!priv->tx_ts_enabled && !priv->rx_ts_enabled) {
slave_write(slave, 0, CPSW1_TS_CTL);
return;
}

seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;

if (cpts_is_tx_enabled(cpsw->cpts))
if (priv->tx_ts_enabled)
ts_en |= CPSW_V1_TS_TX_EN;

if (cpts_is_rx_enabled(cpsw->cpts))
if (priv->rx_ts_enabled)
ts_en |= CPSW_V1_TS_RX_EN;

slave_write(slave, ts_en, CPSW1_TS_CTL);
Expand All @@ -2207,20 +2212,20 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
case CPSW_VERSION_2:
ctrl &= ~CTRL_V2_ALL_TS_MASK;

if (cpts_is_tx_enabled(cpsw->cpts))
if (priv->tx_ts_enabled)
ctrl |= CTRL_V2_TX_TS_BITS;

if (cpts_is_rx_enabled(cpsw->cpts))
if (priv->rx_ts_enabled)
ctrl |= CTRL_V2_RX_TS_BITS;
break;
case CPSW_VERSION_3:
default:
ctrl &= ~CTRL_V3_ALL_TS_MASK;

if (cpts_is_tx_enabled(cpsw->cpts))
if (priv->tx_ts_enabled)
ctrl |= CTRL_V3_TX_TS_BITS;

if (cpts_is_rx_enabled(cpsw->cpts))
if (priv->rx_ts_enabled)
ctrl |= CTRL_V3_RX_TS_BITS;
break;
}
Expand All @@ -2230,14 +2235,14 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
slave_write(slave, mtype, CPSW2_TS_SEQ_MTYPE);
slave_write(slave, ctrl, CPSW2_CONTROL);
writel_relaxed(ETH_P_1588, &cpsw->regs->ts_ltype);
writel_relaxed(ETH_P_8021Q, &cpsw->regs->vlan_ltype);
}

static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
{
struct cpsw_priv *priv = netdev_priv(dev);
struct hwtstamp_config cfg;
struct cpsw_common *cpsw = priv->cpsw;
struct cpts *cpts = cpsw->cpts;

if (cpsw->version != CPSW_VERSION_1 &&
cpsw->version != CPSW_VERSION_2 &&
Expand All @@ -2256,15 +2261,15 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)

switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
cpts_rx_enable(cpts, 0);
priv->rx_ts_enabled = 0;
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_NTP_ALL:
return -ERANGE;
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);
priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
Expand All @@ -2276,18 +2281,18 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
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);
priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V2_EVENT;
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
return -ERANGE;
}

cpts_tx_enable(cpts, cfg.tx_type == HWTSTAMP_TX_ON);
priv->tx_ts_enabled = cfg.tx_type == HWTSTAMP_TX_ON;

switch (cpsw->version) {
case CPSW_VERSION_1:
cpsw_hwtstamp_v1(cpsw);
cpsw_hwtstamp_v1(priv);
break;
case CPSW_VERSION_2:
case CPSW_VERSION_3:
Expand All @@ -2303,7 +2308,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
{
struct cpsw_common *cpsw = ndev_to_cpsw(dev);
struct cpts *cpts = cpsw->cpts;
struct cpsw_priv *priv = netdev_priv(dev);
struct hwtstamp_config cfg;

if (cpsw->version != CPSW_VERSION_1 &&
Expand All @@ -2312,10 +2317,8 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
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);
cfg.tx_type = priv->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
cfg.rx_filter = priv->rx_ts_enabled;

return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
Expand Down
32 changes: 25 additions & 7 deletions drivers/net/ethernet/ti/cpts.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,25 @@ static int cpts_purge_events(struct cpts *cpts)
return removed ? 0 : -1;
}

static void cpts_purge_txq(struct cpts *cpts)
{
struct cpts_skb_cb_data *skb_cb;
struct sk_buff *skb, *tmp;
int removed = 0;

skb_queue_walk_safe(&cpts->txq, skb, tmp) {
skb_cb = (struct cpts_skb_cb_data *)skb->cb;
if (time_after(jiffies, skb_cb->tmo)) {
__skb_unlink(skb, &cpts->txq);
dev_consume_skb_any(skb);
++removed;
}
}

if (removed)
dev_dbg(cpts->dev, "txq cleaned up %d\n", removed);
}

static bool cpts_match_tx_ts(struct cpts *cpts, struct cpts_event *event)
{
struct sk_buff *skb, *tmp;
Expand Down Expand Up @@ -119,9 +138,7 @@ static bool cpts_match_tx_ts(struct cpts *cpts, struct cpts_event *event)

if (time_after(jiffies, skb_cb->tmo)) {
/* timeout any expired skbs over 1s */
dev_dbg(cpts->dev,
"expiring tx timestamp mtype %u seqid %04x\n",
mtype, seqid);
dev_dbg(cpts->dev, "expiring tx timestamp from txq\n");
__skb_unlink(skb, &cpts->txq);
dev_consume_skb_any(skb);
}
Expand Down Expand Up @@ -294,8 +311,11 @@ static long cpts_overflow_check(struct ptp_clock_info *ptp)
spin_lock_irqsave(&cpts->lock, flags);
ts = ns_to_timespec64(timecounter_read(&cpts->tc));

if (!skb_queue_empty(&cpts->txq))
delay = CPTS_SKB_TX_WORK_TIMEOUT;
if (!skb_queue_empty(&cpts->txq)) {
cpts_purge_txq(cpts);
if (!skb_queue_empty(&cpts->txq))
delay = CPTS_SKB_TX_WORK_TIMEOUT;
}
spin_unlock_irqrestore(&cpts->lock, flags);

pr_debug("cpts overflow check at %lld.%09ld\n",
Expand Down Expand Up @@ -410,8 +430,6 @@ void cpts_rx_timestamp(struct cpts *cpts, struct sk_buff *skb)
u64 ns;
struct skb_shared_hwtstamps *ssh;

if (!cpts->rx_enable)
return;
ns = cpts_find_ts(cpts, skb, CPTS_EV_RX);
if (!ns)
return;
Expand Down
38 changes: 0 additions & 38 deletions drivers/net/ethernet/ti/cpts.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,26 +136,6 @@ struct cpts *cpts_create(struct device *dev, void __iomem *regs,
struct device_node *node);
void cpts_release(struct cpts *cpts);

static inline void cpts_rx_enable(struct cpts *cpts, int enable)
{
cpts->rx_enable = enable;
}

static inline bool cpts_is_rx_enabled(struct cpts *cpts)
{
return !!cpts->rx_enable;
}

static inline void cpts_tx_enable(struct cpts *cpts, int enable)
{
cpts->tx_enable = enable;
}

static inline bool cpts_is_tx_enabled(struct cpts *cpts)
{
return !!cpts->tx_enable;
}

static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
unsigned int class = ptp_classify_raw(skb);
Expand Down Expand Up @@ -197,24 +177,6 @@ static inline void cpts_unregister(struct cpts *cpts)
{
}

static inline void cpts_rx_enable(struct cpts *cpts, int enable)
{
}

static inline bool cpts_is_rx_enabled(struct cpts *cpts)
{
return false;
}

static inline void cpts_tx_enable(struct cpts *cpts, int enable)
{
}

static inline bool cpts_is_tx_enabled(struct cpts *cpts)
{
return false;
}

static inline bool cpts_can_timestamp(struct cpts *cpts, struct sk_buff *skb)
{
return false;
Expand Down
Loading

0 comments on commit 4fd3e2a

Please sign in to comment.