dpaa_eth: add support for hardware timestamping
This patch is to add hardware timestamping support for dpaa_eth. On Rx, timestamping is enabled for all frames. On Tx, we only instruct the hardware to timestamp the frames marked accordingly by the stack. Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Acked-by: Madalin Bucur <madalin.bucur@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dcce36ab71
commit
4664856e9c
|
@ -1168,7 +1168,7 @@ static int dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq,
|
|||
buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
|
||||
buf_prefix_content.pass_prs_result = true;
|
||||
buf_prefix_content.pass_hash_result = true;
|
||||
buf_prefix_content.pass_time_stamp = false;
|
||||
buf_prefix_content.pass_time_stamp = true;
|
||||
buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
|
||||
|
||||
params.specific_params.non_rx_params.err_fqid = errq->fqid;
|
||||
|
@ -1210,7 +1210,7 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps,
|
|||
buf_prefix_content.priv_data_size = buf_layout->priv_data_size;
|
||||
buf_prefix_content.pass_prs_result = true;
|
||||
buf_prefix_content.pass_hash_result = true;
|
||||
buf_prefix_content.pass_time_stamp = false;
|
||||
buf_prefix_content.pass_time_stamp = true;
|
||||
buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
|
||||
|
||||
rx_p = ¶ms.specific_params.rx_params;
|
||||
|
@ -1607,14 +1607,28 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
|
|||
{
|
||||
const enum dma_data_direction dma_dir = DMA_TO_DEVICE;
|
||||
struct device *dev = priv->net_dev->dev.parent;
|
||||
struct skb_shared_hwtstamps shhwtstamps;
|
||||
dma_addr_t addr = qm_fd_addr(fd);
|
||||
const struct qm_sg_entry *sgt;
|
||||
struct sk_buff **skbh, *skb;
|
||||
int nr_frags, i;
|
||||
u64 ns;
|
||||
|
||||
skbh = (struct sk_buff **)phys_to_virt(addr);
|
||||
skb = *skbh;
|
||||
|
||||
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
|
||||
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
|
||||
|
||||
if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh,
|
||||
&ns)) {
|
||||
shhwtstamps.hwtstamp = ns_to_ktime(ns);
|
||||
skb_tstamp_tx(skb, &shhwtstamps);
|
||||
} else {
|
||||
dev_warn(dev, "fman_port_get_tstamp failed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
|
||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
dma_unmap_single(dev, addr, qm_fd_get_offset(fd) +
|
||||
|
@ -2086,6 +2100,11 @@ static int dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
|
|||
if (unlikely(err < 0))
|
||||
goto skb_to_fd_failed;
|
||||
|
||||
if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
|
||||
fd.cmd |= cpu_to_be32(FM_FD_CMD_UPD);
|
||||
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
||||
}
|
||||
|
||||
if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0))
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
|
@ -2227,6 +2246,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
|
|||
struct qman_fq *fq,
|
||||
const struct qm_dqrr_entry *dq)
|
||||
{
|
||||
struct skb_shared_hwtstamps *shhwtstamps;
|
||||
struct rtnl_link_stats64 *percpu_stats;
|
||||
struct dpaa_percpu_priv *percpu_priv;
|
||||
const struct qm_fd *fd = &dq->fd;
|
||||
|
@ -2240,6 +2260,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
|
|||
struct sk_buff *skb;
|
||||
int *count_ptr;
|
||||
void *vaddr;
|
||||
u64 ns;
|
||||
|
||||
fd_status = be32_to_cpu(fd->status);
|
||||
fd_format = qm_fd_get_format(fd);
|
||||
|
@ -2304,6 +2325,16 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
|
|||
if (!skb)
|
||||
return qman_cb_dqrr_consume;
|
||||
|
||||
if (priv->rx_tstamp) {
|
||||
shhwtstamps = skb_hwtstamps(skb);
|
||||
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
||||
|
||||
if (!fman_port_get_tstamp(priv->mac_dev->port[RX], vaddr, &ns))
|
||||
shhwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
else
|
||||
dev_warn(net_dev->dev.parent, "fman_port_get_tstamp failed!\n");
|
||||
}
|
||||
|
||||
skb->protocol = eth_type_trans(skb, net_dev);
|
||||
|
||||
if (net_dev->features & NETIF_F_RXHASH && priv->keygen_in_use &&
|
||||
|
@ -2523,11 +2554,58 @@ static int dpaa_eth_stop(struct net_device *net_dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
struct dpaa_priv *priv = netdev_priv(dev);
|
||||
struct hwtstamp_config config;
|
||||
|
||||
if (copy_from_user(&config, rq->ifr_data, sizeof(config)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (config.tx_type) {
|
||||
case HWTSTAMP_TX_OFF:
|
||||
/* Couldn't disable rx/tx timestamping separately.
|
||||
* Do nothing here.
|
||||
*/
|
||||
priv->tx_tstamp = false;
|
||||
break;
|
||||
case HWTSTAMP_TX_ON:
|
||||
priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
|
||||
priv->tx_tstamp = true;
|
||||
break;
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (config.rx_filter == HWTSTAMP_FILTER_NONE) {
|
||||
/* Couldn't disable rx/tx timestamping separately.
|
||||
* Do nothing here.
|
||||
*/
|
||||
priv->rx_tstamp = false;
|
||||
} else {
|
||||
priv->mac_dev->set_tstamp(priv->mac_dev->fman_mac, true);
|
||||
priv->rx_tstamp = true;
|
||||
/* TS is set for all frame types, not only those requested */
|
||||
config.rx_filter = HWTSTAMP_FILTER_ALL;
|
||||
}
|
||||
|
||||
return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
|
||||
static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
if (!net_dev->phydev)
|
||||
return -EINVAL;
|
||||
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (cmd == SIOCGMIIREG) {
|
||||
if (net_dev->phydev)
|
||||
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
|
||||
}
|
||||
|
||||
if (cmd == SIOCSHWTSTAMP)
|
||||
return dpaa_ts_ioctl(net_dev, rq, cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct net_device_ops dpaa_ops = {
|
||||
|
|
|
@ -182,6 +182,9 @@ struct dpaa_priv {
|
|||
|
||||
struct dpaa_buffer_layout buf_layout[2];
|
||||
u16 rx_headroom;
|
||||
|
||||
bool tx_tstamp; /* Tx timestamping enabled */
|
||||
bool rx_tstamp; /* Rx timestamping enabled */
|
||||
};
|
||||
|
||||
/* from dpaa_ethtool.c */
|
||||
|
|
Loading…
Reference in New Issue