|
@@ -82,6 +82,7 @@
|
|
#include <linux/tcp.h>
|
|
#include <linux/tcp.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/udp.h>
|
|
#include <linux/in.h>
|
|
#include <linux/in.h>
|
|
|
|
+#include <linux/net_tstamp.h>
|
|
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/irq.h>
|
|
@@ -377,6 +378,13 @@ static void gfar_init_mac(struct net_device *ndev)
|
|
rctrl |= RCTRL_PADDING(priv->padding);
|
|
rctrl |= RCTRL_PADDING(priv->padding);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Insert receive time stamps into padding alignment bytes */
|
|
|
|
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) {
|
|
|
|
+ rctrl &= ~RCTRL_PAL_MASK;
|
|
|
|
+ rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8);
|
|
|
|
+ priv->padding = 8;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* keep vlan related bits if it's enabled */
|
|
/* keep vlan related bits if it's enabled */
|
|
if (priv->vlgrp) {
|
|
if (priv->vlgrp) {
|
|
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
|
|
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
|
|
@@ -501,7 +509,8 @@ void unlock_tx_qs(struct gfar_private *priv)
|
|
/* Returns 1 if incoming frames use an FCB */
|
|
/* Returns 1 if incoming frames use an FCB */
|
|
static inline int gfar_uses_fcb(struct gfar_private *priv)
|
|
static inline int gfar_uses_fcb(struct gfar_private *priv)
|
|
{
|
|
{
|
|
- return priv->vlgrp || priv->rx_csum_enable;
|
|
|
|
|
|
+ return priv->vlgrp || priv->rx_csum_enable ||
|
|
|
|
+ (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
|
|
}
|
|
}
|
|
|
|
|
|
static void free_tx_pointers(struct gfar_private *priv)
|
|
static void free_tx_pointers(struct gfar_private *priv)
|
|
@@ -742,7 +751,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
|
|
FSL_GIANFAR_DEV_HAS_CSUM |
|
|
FSL_GIANFAR_DEV_HAS_CSUM |
|
|
FSL_GIANFAR_DEV_HAS_VLAN |
|
|
FSL_GIANFAR_DEV_HAS_VLAN |
|
|
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
|
|
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
|
|
- FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
|
|
|
|
|
|
+ FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
|
|
|
|
+ FSL_GIANFAR_DEV_HAS_TIMER;
|
|
|
|
|
|
ctype = of_get_property(np, "phy-connection-type", NULL);
|
|
ctype = of_get_property(np, "phy-connection-type", NULL);
|
|
|
|
|
|
@@ -772,6 +782,38 @@ err_grp_init:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int gfar_hwtstamp_ioctl(struct net_device *netdev,
|
|
|
|
+ struct ifreq *ifr, int cmd)
|
|
|
|
+{
|
|
|
|
+ struct hwtstamp_config config;
|
|
|
|
+ struct gfar_private *priv = netdev_priv(netdev);
|
|
|
|
+
|
|
|
|
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ /* reserved for future extensions */
|
|
|
|
+ if (config.flags)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (config.tx_type)
|
|
|
|
+ return -ERANGE;
|
|
|
|
+
|
|
|
|
+ switch (config.rx_filter) {
|
|
|
|
+ case HWTSTAMP_FILTER_NONE:
|
|
|
|
+ priv->hwts_rx_en = 0;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
|
|
|
|
+ return -ERANGE;
|
|
|
|
+ priv->hwts_rx_en = 1;
|
|
|
|
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
|
|
|
+ -EFAULT : 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Ioctl MII Interface */
|
|
/* Ioctl MII Interface */
|
|
static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
{
|
|
{
|
|
@@ -780,6 +822,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
if (!netif_running(dev))
|
|
if (!netif_running(dev))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
+ if (cmd == SIOCSHWTSTAMP)
|
|
|
|
+ return gfar_hwtstamp_ioctl(dev, rq, cmd);
|
|
|
|
+
|
|
if (!priv->phydev)
|
|
if (!priv->phydev)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
@@ -982,7 +1027,8 @@ static int gfar_probe(struct of_device *ofdev,
|
|
else
|
|
else
|
|
priv->padding = 0;
|
|
priv->padding = 0;
|
|
|
|
|
|
- if (dev->features & NETIF_F_IP_CSUM)
|
|
|
|
|
|
+ if (dev->features & NETIF_F_IP_CSUM ||
|
|
|
|
+ priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
|
|
dev->hard_header_len += GMAC_FCB_LEN;
|
|
dev->hard_header_len += GMAC_FCB_LEN;
|
|
|
|
|
|
/* Program the isrg regs only if number of grps > 1 */
|
|
/* Program the isrg regs only if number of grps > 1 */
|
|
@@ -2474,6 +2520,17 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
|
|
skb_pull(skb, amount_pull);
|
|
skb_pull(skb, amount_pull);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Get receive timestamp from the skb */
|
|
|
|
+ if (priv->hwts_rx_en) {
|
|
|
|
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
|
|
|
|
+ u64 *ns = (u64 *) skb->data;
|
|
|
|
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
|
|
|
|
+ shhwtstamps->hwtstamp = ns_to_ktime(*ns);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (priv->padding)
|
|
|
|
+ skb_pull(skb, priv->padding);
|
|
|
|
+
|
|
if (priv->rx_csum_enable)
|
|
if (priv->rx_csum_enable)
|
|
gfar_rx_checksum(skb, fcb);
|
|
gfar_rx_checksum(skb, fcb);
|
|
|
|
|
|
@@ -2510,8 +2567,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
|
|
bdp = rx_queue->cur_rx;
|
|
bdp = rx_queue->cur_rx;
|
|
base = rx_queue->rx_bd_base;
|
|
base = rx_queue->rx_bd_base;
|
|
|
|
|
|
- amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
|
|
|
|
- priv->padding;
|
|
|
|
|
|
+ amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0);
|
|
|
|
|
|
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
|
|
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
|
|
struct sk_buff *newskb;
|
|
struct sk_buff *newskb;
|