Commit 4fd3e2ac authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw-allow-vlan-h-w-timestamping'



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: default avatarDavid S. Miller <davem@davemloft.net>
parents 3e536cff 1ebb2446
Loading
Loading
Loading
Loading
+27 −24
Original line number Diff line number Diff line
@@ -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)
@@ -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)
@@ -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;
};
@@ -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);
@@ -939,6 +942,8 @@ 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);
		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);
@@ -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);
@@ -2170,13 +2175,13 @@ fail:

#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;
	}
@@ -2184,10 +2189,10 @@ static void cpsw_hwtstamp_v1(struct cpsw_common *cpsw)
	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);
@@ -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;
	}
@@ -2230,6 +2235,7 @@ 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)
@@ -2237,7 +2243,6 @@ 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 &&
@@ -2256,7 +2261,7 @@ 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:
@@ -2264,7 +2269,7 @@ static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
	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:
@@ -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:
@@ -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 &&
@@ -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;
}
+25 −7
Original line number Diff line number Diff line
@@ -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;
@@ -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);
		}
@@ -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)) {
		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",
@@ -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;
+0 −38
Original line number Diff line number Diff line
@@ -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);
@@ -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;
+17 −15
Original line number Diff line number Diff line
@@ -763,6 +763,8 @@ struct gbe_priv {

	int                             cpts_registered;
	struct cpts                     *cpts;
	int				rx_ts_enabled;
	int				tx_ts_enabled;
};

struct gbe_intf {
@@ -2564,7 +2566,7 @@ static int gbe_txtstamp_mark_pkt(struct gbe_intf *gbe_intf,
	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))
	    !gbe_dev->tx_ts_enabled)
		return 0;

	/* If phy has the txtstamp api, assume it will do it.
@@ -2598,7 +2600,9 @@ static int gbe_rxtstamp(struct gbe_intf *gbe_intf, struct netcp_packet *p_info)
		return 0;
	}

	if (gbe_dev->rx_ts_enabled)
		cpts_rx_timestamp(gbe_dev->cpts, p_info->skb);

	p_info->rxtstamp_complete = true;

	return 0;
@@ -2614,10 +2618,8 @@ static int gbe_hwtstamp_get(struct gbe_intf *gbe_intf, 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 = gbe_dev->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
	cfg.rx_filter = gbe_dev->rx_ts_enabled;

	return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
@@ -2628,8 +2630,8 @@ static void gbe_hwtstamp(struct gbe_intf *gbe_intf)
	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)) {
	if (!gbe_dev->rx_ts_enabled &&
	    !gbe_dev->tx_ts_enabled) {
		writel(0, GBE_REG_ADDR(slave, port_regs, ts_ctl));
		return;
	}
@@ -2641,10 +2643,10 @@ static void gbe_hwtstamp(struct gbe_intf *gbe_intf)
		(slave->ts_ctl.uni ?  TS_UNI_EN :
			slave->ts_ctl.maddr_map << TS_CTL_MADDR_SHIFT);

	if (cpts_is_tx_enabled(gbe_dev->cpts))
	if (gbe_dev->tx_ts_enabled)
		ts_en |= (TS_TX_ANX_ALL_EN | TS_TX_VLAN_LT1_EN);

	if (cpts_is_rx_enabled(gbe_dev->cpts))
	if (gbe_dev->rx_ts_enabled)
		ts_en |= (TS_RX_ANX_ALL_EN | TS_RX_VLAN_LT1_EN);

	writel(ts_en,  GBE_REG_ADDR(slave, port_regs, ts_ctl));
@@ -2670,10 +2672,10 @@ static int gbe_hwtstamp_set(struct gbe_intf *gbe_intf, struct ifreq *ifr)

	switch (cfg.tx_type) {
	case HWTSTAMP_TX_OFF:
		cpts_tx_enable(cpts, 0);
		gbe_dev->tx_ts_enabled = 0;
		break;
	case HWTSTAMP_TX_ON:
		cpts_tx_enable(cpts, 1);
		gbe_dev->tx_ts_enabled = 1;
		break;
	default:
		return -ERANGE;
@@ -2681,12 +2683,12 @@ static int gbe_hwtstamp_set(struct gbe_intf *gbe_intf, struct ifreq *ifr)

	switch (cfg.rx_filter) {
	case HWTSTAMP_FILTER_NONE:
		cpts_rx_enable(cpts, 0);
		gbe_dev->rx_ts_enabled = HWTSTAMP_FILTER_NONE;
		break;
	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);
		gbe_dev->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:
@@ -2698,7 +2700,7 @@ static int gbe_hwtstamp_set(struct gbe_intf *gbe_intf, 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);
		gbe_dev->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V2_EVENT;
		cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
		break;
	default: