* [PATCH net 2/6] net/mlx4_core: Turn off device-managed FS bit in dev-cap wrapper if DMFS is not enabled
From: Or Gerlitz @ 2013-03-07 13:46 UTC (permalink / raw)
To: davem; +Cc: netdev, amirv, Jack Morgenstein, Or Gerlitz
In-Reply-To: <1362664017-30275-1-git-send-email-ogerlitz@mellanox.com>
From: Jack Morgenstein <jackm@dev.mellanox.co.il>
Older kernels detect DMFS (device-managed flow steering) from the HCA
device capability directly, regardless of whether the capability was
enabled in INIT_HCA, this is fixed by commit 7b8157bed "mlx4_core: Adjustments
to Flow Steering activation logic for SR-IOV"
To protect against guests running kernels without this fix, the host driver
should turn off the DMFS capability bit in mlx4_QUERY_DEV_CAP_wrapper.
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/fw.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 50917eb..f624557 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -787,6 +787,14 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+ /* turn off device-managed steering capability if not enabled */
+ if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
+ MLX4_GET(field, outbox->buf,
+ QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
+ field &= 0x7f;
+ MLX4_PUT(outbox->buf, field,
+ QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET);
+ }
return 0;
}
--
1.7.1
^ permalink raw reply related
* [PATCH net 1/6] net/mlx4_core: Disable mlx4_QP_ATTACH calls from guests if the host uses flow steering
From: Or Gerlitz @ 2013-03-07 13:46 UTC (permalink / raw)
To: davem; +Cc: netdev, amirv, Jack Morgenstein, Or Gerlitz
In-Reply-To: <1362664017-30275-1-git-send-email-ogerlitz@mellanox.com>
From: Jack Morgenstein <jackm@dev.mellanox.co.il>
Guests kernels may not correctly detect if DMFS (device-enabled flow steering) is
activated by the host. If DMFS is activated, the master should return error to guests
which try to use the B0-steering flow calls (mlx4_QP_ATTACH).
Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
.../net/ethernet/mellanox/mlx4/resource_tracker.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 083fb48..2995687 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -2990,6 +2990,9 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
u8 steer_type_mask = 2;
enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;
+ if (dev->caps.steering_mode != MLX4_STEERING_MODE_B0)
+ return -EINVAL;
+
qpn = vhcr->in_modifier & 0xffffff;
err = get_res(dev, slave, qpn, RES_QP, &rqp);
if (err)
--
1.7.1
^ permalink raw reply related
* [PATCH net 5/6] net/mlx4_en: Cleanup MAC resources on module unload or port stop
From: Or Gerlitz @ 2013-03-07 13:46 UTC (permalink / raw)
To: davem; +Cc: netdev, amirv, Yan Burman, Or Gerlitz
In-Reply-To: <1362664017-30275-1-git-send-email-ogerlitz@mellanox.com>
From: Yan Burman <yanb@mellanox.com>
Make sure we cleanup all MAC related resources (entries in the port MAC
table and steering rules) when stopping a port or when the driver is unloaded.
The leak was introduced by commit 07cb4b0a "net/mlx4_en: Manage hash of MAC
addresses per port".
Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 38 +++++++++++++----------
1 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 217e618..7fd0936 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -565,34 +565,38 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_dev *dev = mdev->dev;
int qpn = priv->base_qpn;
- u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
-
- en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
- priv->dev->dev_addr);
- mlx4_unregister_mac(dev, priv->port, mac);
+ u64 mac;
- if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
+ if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
+ mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+ en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
+ priv->dev->dev_addr);
+ mlx4_unregister_mac(dev, priv->port, mac);
+ } else {
struct mlx4_mac_entry *entry;
struct hlist_node *tmp;
struct hlist_head *bucket;
- unsigned int mac_hash;
+ unsigned int i;
- mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX];
- bucket = &priv->mac_hash[mac_hash];
- hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
- if (ether_addr_equal_64bits(entry->mac,
- priv->dev->dev_addr)) {
- en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
- priv->port, priv->dev->dev_addr, qpn);
+ for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
+ bucket = &priv->mac_hash[i];
+ hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
+ mac = mlx4_en_mac_to_u64(entry->mac);
+ en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
+ entry->mac);
mlx4_en_uc_steer_release(priv, entry->mac,
qpn, entry->reg_id);
- mlx4_qp_release_range(dev, qpn, 1);
+ mlx4_unregister_mac(dev, priv->port, mac);
hlist_del_rcu(&entry->hlist);
kfree_rcu(entry, rcu);
- break;
}
}
+
+ en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n",
+ priv->port, qpn);
+ mlx4_qp_release_range(dev, qpn, 1);
+ priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
}
}
--
1.7.1
^ permalink raw reply related
* [PATCH net 4/6] net/mlx4_en: Fix race when setting the device MAC address
From: Or Gerlitz @ 2013-03-07 13:46 UTC (permalink / raw)
To: davem; +Cc: netdev, amirv, Yan Burman, Or Gerlitz
In-Reply-To: <1362664017-30275-1-git-send-email-ogerlitz@mellanox.com>
From: Yan Burman <yanb@mellanox.com>
Remove unnecessary use of workqueue for the device MAC address setting
flow, and fix a race when setting MAC address which was introduced by
commit c07cb4b0a "net/mlx4_en: Manage hash of MAC addresses per port"
The race happened when mlx4_en_replace_mac was being executed in parallel
with a successive call to ndo_set_mac_address, e.g witn an A/B/A MAC
setting configuration test, the third set fails.
With this change we also properly report an error if set MAC fails.
Signed-off-by: Yan Burman <yanb@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 42 ++++++++++++------------
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 -
2 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index bb4d8d9..217e618 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -650,28 +650,10 @@ u64 mlx4_en_mac_to_u64(u8 *addr)
return mac;
}
-static int mlx4_en_set_mac(struct net_device *dev, void *addr)
+static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_en_dev *mdev = priv->mdev;
- struct sockaddr *saddr = addr;
-
- if (!is_valid_ether_addr(saddr->sa_data))
- return -EADDRNOTAVAIL;
-
- memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
- queue_work(mdev->workqueue, &priv->mac_task);
- return 0;
-}
-
-static void mlx4_en_do_set_mac(struct work_struct *work)
-{
- struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
- mac_task);
- struct mlx4_en_dev *mdev = priv->mdev;
int err = 0;
- mutex_lock(&mdev->state_lock);
if (priv->port_up) {
/* Remove old MAC and insert the new one */
err = mlx4_en_replace_mac(priv, priv->base_qpn,
@@ -683,7 +665,26 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
} else
en_dbg(HW, priv, "Port is down while registering mac, exiting...\n");
+ return err;
+}
+
+static int mlx4_en_set_mac(struct net_device *dev, void *addr)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct sockaddr *saddr = addr;
+ int err;
+
+ if (!is_valid_ether_addr(saddr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
+
+ mutex_lock(&mdev->state_lock);
+ err = mlx4_en_do_set_mac(priv);
mutex_unlock(&mdev->state_lock);
+
+ return err;
}
static void mlx4_en_clear_list(struct net_device *dev)
@@ -1348,7 +1349,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
}
if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
- queue_work(mdev->workqueue, &priv->mac_task);
+ mlx4_en_do_set_mac(priv);
mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
}
mutex_unlock(&mdev->state_lock);
@@ -2078,7 +2079,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->msg_enable = MLX4_EN_MSG_LEVEL;
spin_lock_init(&priv->stats_lock);
INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode);
- INIT_WORK(&priv->mac_task, mlx4_en_do_set_mac);
INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index c313d7e..f710b7c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -509,7 +509,6 @@ struct mlx4_en_priv {
struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
struct mlx4_qp drop_qp;
struct work_struct rx_mode_task;
- struct work_struct mac_task;
struct work_struct watchdog_task;
struct work_struct linkstate_task;
struct delayed_work stats_task;
--
1.7.1
^ permalink raw reply related
* Re: BUG: IPv4: Attempt to release TCP socket in state 1
From: Eric Dumazet @ 2013-03-07 13:46 UTC (permalink / raw)
To: dormando; +Cc: Cong Wang, linux-kernel, netdev
In-Reply-To: <alpine.DEB.2.02.1303061631290.6723@dflat>
On Wed, 2013-03-06 at 16:41 -0800, dormando wrote:
> Ok... bridge module is loaded but nothing seems to be using it. No
> bond/tunnels/anything enabled. I couldn't quickly figure out what was
> causing it to load.
>
> We removed the need for macvlan, started machines with a fresh boot, and
> they still crashed without it, after a few hours.
>
> Unfortunately I just saw a machine crash in the same way on 3.6.6 and
> 3.6.9. I'm working on getting a completely pristine 3.6.6 and 3.6.9
> tested. Our patches are minor but there were a few, so I'm backing it all
> out just to be sure.
>
> Is there anything in particular which is most interesting? I can post lots
> and lots and lots of information. Sadly bridge/macvlan weren't part of the
> problem. .config, sysctls are easiest I guess? When this "hang" happens
> the machine is still up somewhat, but we lose access to it. Syslog is
> still writing entries to disk occasionally, so it's possible we could set
> something up to dump more information.
>
> It takes a day or two to cycle this, so it might take a while to get
> information and test crashes.
Thanks !
Please add a stack trace, it might help :
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 68f6a94..1d4d97e 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -141,8 +141,9 @@ void inet_sock_destruct(struct sock *sk)
sk_mem_reclaim(sk);
if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {
- pr_err("Attempt to release TCP socket in state %d %p\n",
- sk->sk_state, sk);
+ pr_err("Attempt to release TCP socket family %d in state %d %p\n",
+ sk->sk_family, sk->sk_state, sk);
+ WARN_ON_ONCE(1);
return;
}
if (!sock_flag(sk, SOCK_DEAD)) {
^ permalink raw reply related
* Re: [PATCH 1/3] driver: net: ethernet: cpsw: implement ethtool get/set phy setting
From: Peter Korsgaard @ 2013-03-07 13:24 UTC (permalink / raw)
To: Mugunthan V N
Cc: netdev, davem, devicetree-discuss, linux-omap, b-cousson, paul
In-Reply-To: <1362659421-11884-2-git-send-email-mugunthanvnm@ti.com>
>>>>> "M" == Mugunthan V N <mugunthanvnm@ti.com> writes:
M> This patch implements get/set of the phy settings via ethtool apis
M> Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
M> ---
M> Documentation/devicetree/bindings/net/cpsw.txt | 3 +++
M> drivers/net/ethernet/ti/cpsw.c | 32 ++++++++++++++++++++++++
M> include/linux/platform_data/cpsw.h | 1 +
M> 3 files changed, 36 insertions(+)
M> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
M> index ecfdf75..8d61300 100644
M> --- a/Documentation/devicetree/bindings/net/cpsw.txt
M> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
M> @@ -20,6 +20,7 @@ Required properties:
M> - cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
M> - phy_id : Specifies slave phy id
M> - mac-address : Specifies slave MAC address
M> +- ethtool-active-slave : Specifies the slave to use for ethtool command
That again sounds like something Linux specific rather than a hardware
property.
It would be good if all these special things (dual emac mode, vlan
handling, switching) could be handled using the existing kernel
(bridging/vlan) infrastructure, and the driver always just exposing 2
network interfaces instead of these configuration properties.
--
Bye, Peter Korsgaard
^ permalink raw reply
* [Patch net] bridge: add missing vid to br_mdb_get()
From: Cong Wang @ 2013-03-07 13:05 UTC (permalink / raw)
To: netdev; +Cc: Vlad Yasevich, Stephen Hemminger, David S. Miller, Cong Wang
From: Cong Wang <amwang@redhat.com>
Obviously, vid should be considered when searching for multicast
group.
Cc: Vlad Yasevich <vyasevic@redhat.com>
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index d5f1d3f..314c73e 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -66,7 +66,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
}
- mdst = br_mdb_get(br, skb);
+ mdst = br_mdb_get(br, skb, vid);
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
br_multicast_deliver(mdst, skb);
else
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 4803301..828e2bc 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -97,7 +97,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
if (is_broadcast_ether_addr(dest))
skb2 = skb;
else if (is_multicast_ether_addr(dest)) {
- mdst = br_mdb_get(br, skb);
+ mdst = br_mdb_get(br, skb, vid);
if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
if ((mdst && mdst->mglist) ||
br_multicast_is_router(br))
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 10e6fce..923fbea 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -132,7 +132,7 @@ static struct net_bridge_mdb_entry *br_mdb_ip6_get(
#endif
struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
- struct sk_buff *skb)
+ struct sk_buff *skb, u16 vid)
{
struct net_bridge_mdb_htable *mdb = rcu_dereference(br->mdb);
struct br_ip ip;
@@ -144,6 +144,7 @@ struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
return NULL;
ip.proto = skb->protocol;
+ ip.vid = vid;
switch (skb->protocol) {
case htons(ETH_P_IP):
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 6d314c4..3cbf5be 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -442,7 +442,7 @@ extern int br_multicast_rcv(struct net_bridge *br,
struct net_bridge_port *port,
struct sk_buff *skb);
extern struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
- struct sk_buff *skb);
+ struct sk_buff *skb, u16 vid);
extern void br_multicast_add_port(struct net_bridge_port *port);
extern void br_multicast_del_port(struct net_bridge_port *port);
extern void br_multicast_enable_port(struct net_bridge_port *port);
@@ -504,7 +504,7 @@ static inline int br_multicast_rcv(struct net_bridge *br,
}
static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
- struct sk_buff *skb)
+ struct sk_buff *skb, u16 vid)
{
return NULL;
}
^ permalink raw reply related
* [PATCH] Fix: sparse warning in inet_csk_prepare_forced_close
From: Christoph Paasch @ 2013-03-07 12:34 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In e337e24d66 (inet: Fix kmemleak in tcp_v4/6_syn_recv_sock and
dccp_v4/6_request_recv_sock) I introduced the function
inet_csk_prepare_forced_close, which does a call to bh_unlock_sock().
This produces a sparse-warning.
This patch adds the missing __releases.
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
---
net/ipv4/inet_connection_sock.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 7d1874b..804c98f 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -735,6 +735,7 @@ EXPORT_SYMBOL(inet_csk_destroy_sock);
* tcp/dccp_create_openreq_child().
*/
void inet_csk_prepare_forced_close(struct sock *sk)
+__releases(&sk->sk_lock.slock)
{
/* sk_clone_lock locked the socket and set refcnt to 2 */
bh_unlock_sock(sk);
--
1.8.1.227.g44fe835
^ permalink raw reply related
* [Patch net-next] bridge: use ipv4_is_local_multicast() helper
From: Cong Wang @ 2013-03-07 12:32 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David S. Miller, Cong Wang
Cc: Stephen Hemminger <stephen@networkplumber.org>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 10e6fce..81d51b8 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1368,7 +1368,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
return -EINVAL;
if (iph->protocol != IPPROTO_IGMP) {
- if ((iph->daddr & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP)
+ if (!ipv4_is_local_multicast(iph->daddr))
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
return 0;
}
^ permalink raw reply related
* [PATCH 3/3] driver: net: ethernet: cpsw: implement interrupt pacing via ethtool
From: Mugunthan V N @ 2013-03-07 12:30 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Mugunthan V N, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-omap-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1362659421-11884-1-git-send-email-mugunthanvnm-l0cyMroinI0@public.gmane.org>
This patch implements support for interrupt pacing block of CPSW via ethtool
Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
---
drivers/net/ethernet/ti/cpsw.c | 95 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index fa91eec..da7276d 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -126,6 +126,13 @@ do { \
#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
+#define CPSW_INTPACEEN (0x3f << 16)
+#define CPSW_INTPRESCALE_MASK (0x7FF << 0)
+#define CPSW_CMINTMAX_CNT 63
+#define CPSW_CMINTMIN_CNT 2
+#define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT)
+#define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1)
+
#define cpsw_enable_irq(priv) \
do { \
u32 i; \
@@ -160,6 +167,15 @@ struct cpsw_wr_regs {
u32 rx_en;
u32 tx_en;
u32 misc_en;
+ u32 mem_allign1[8];
+ u32 rx_thresh_stat;
+ u32 rx_stat;
+ u32 tx_stat;
+ u32 misc_stat;
+ u32 mem_allign2[8];
+ u32 rx_imax;
+ u32 tx_imax;
+
};
struct cpsw_ss_regs {
@@ -314,6 +330,8 @@ struct cpsw_priv {
struct cpsw_host_regs __iomem *host_port_regs;
u32 msg_enable;
u32 version;
+ u32 coal_intvl;
+ u32 bus_freq_mhz;
struct net_device_stats stats;
int rx_packet_max;
int host_port;
@@ -612,6 +630,68 @@ static void cpsw_adjust_link(struct net_device *ndev)
}
}
+static int cpsw_get_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ coal->rx_coalesce_usecs = priv->coal_intvl;
+ return 0;
+}
+
+static int cpsw_set_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ u32 int_ctrl;
+ u32 num_interrupts = 0;
+ u32 prescale = 0;
+ u32 addnl_dvdr = 1;
+ u32 coal_intvl = 0;
+
+ if (!coal->rx_coalesce_usecs)
+ return -EINVAL;
+
+ coal_intvl = coal->rx_coalesce_usecs;
+
+ int_ctrl = readl(&priv->wr_regs->int_control);
+ prescale = priv->bus_freq_mhz * 4;
+
+ if (coal_intvl < CPSW_CMINTMIN_INTVL)
+ coal_intvl = CPSW_CMINTMIN_INTVL;
+
+ if (coal_intvl > CPSW_CMINTMAX_INTVL) {
+ /* Interrupt pacer works with 4us Pulse, we can
+ * throttle further by dilating the 4us pulse.
+ */
+ addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale;
+
+ if (addnl_dvdr > 1) {
+ prescale *= addnl_dvdr;
+ if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr))
+ coal_intvl = (CPSW_CMINTMAX_INTVL
+ * addnl_dvdr);
+ } else {
+ addnl_dvdr = 1;
+ coal_intvl = CPSW_CMINTMAX_INTVL;
+ }
+ }
+
+ num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
+ writel(num_interrupts, &priv->wr_regs->rx_imax);
+ writel(num_interrupts, &priv->wr_regs->tx_imax);
+
+ int_ctrl |= CPSW_INTPACEEN;
+ int_ctrl &= (~CPSW_INTPRESCALE_MASK);
+ int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK);
+ writel(int_ctrl, &priv->wr_regs->int_control);
+
+ cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl);
+ priv->coal_intvl = coal_intvl;
+
+ return 0;
+}
+
static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
{
static char *leader = "........................................";
@@ -834,6 +914,14 @@ static int cpsw_ndo_open(struct net_device *ndev)
cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
}
+ /* Enable Interrupt pacing if configured */
+ if (priv->coal_intvl != 0) {
+ struct ethtool_coalesce coal;
+
+ coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
+ cpsw_set_coalesce(ndev, &coal);
+ }
+
cpdma_ctlr_start(priv->dma);
cpsw_intr_enable(priv);
napi_enable(&priv->napi);
@@ -1279,6 +1367,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
.get_ts_info = cpsw_get_ts_info,
.get_settings = cpsw_get_settings,
.set_settings = cpsw_set_settings,
+ .get_coalesce = cpsw_get_coalesce,
+ .set_coalesce = cpsw_set_coalesce,
};
static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1469,6 +1559,9 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
priv_sl2->slaves = priv->slaves;
priv_sl2->clk = priv->clk;
+ priv_sl2->coal_intvl = 0;
+ priv_sl2->bus_freq_mhz = clk_get_rate(priv_sl2->clk) / 1000000;
+
priv_sl2->cpsw_res = priv->cpsw_res;
priv_sl2->regs = priv->regs;
priv_sl2->host_port = priv->host_port;
@@ -1578,6 +1671,8 @@ static int cpsw_probe(struct platform_device *pdev)
ret = -ENODEV;
goto clean_slave_ret;
}
+ priv->coal_intvl = 0;
+ priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000;
priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!priv->cpsw_res) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/3] arm: dts: am33xx: add default ethtool slave to cpsw node
From: Mugunthan V N @ 2013-03-07 12:30 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Mugunthan V N, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-omap-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1362659421-11884-1-git-send-email-mugunthanvnm-l0cyMroinI0@public.gmane.org>
Signed-off-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org>
---
arch/arm/boot/dts/am33xx.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 0957645..f8c83a1 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -352,6 +352,7 @@
cpts_active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
+ ethtool-active-slave = <0>;
reg = <0x4a100000 0x800
0x4a101200 0x100>;
#address-cells = <1>;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/3] driver: net: ethernet: cpsw: implement ethtool get/set phy setting
From: Mugunthan V N @ 2013-03-07 12:30 UTC (permalink / raw)
To: netdev
Cc: davem, devicetree-discuss, linux-omap, b-cousson, paul,
Mugunthan V N
In-Reply-To: <1362659421-11884-1-git-send-email-mugunthanvnm@ti.com>
This patch implements get/set of the phy settings via ethtool apis
Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
Documentation/devicetree/bindings/net/cpsw.txt | 3 +++
drivers/net/ethernet/ti/cpsw.c | 32 ++++++++++++++++++++++++
include/linux/platform_data/cpsw.h | 1 +
3 files changed, 36 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index ecfdf75..8d61300 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -20,6 +20,7 @@ Required properties:
- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
- phy_id : Specifies slave phy id
- mac-address : Specifies slave MAC address
+- ethtool-active-slave : Specifies the slave to use for ethtool command
Optional properties:
- ti,hwmods : Must be "cpgmac0"
@@ -50,6 +51,7 @@ Examples:
cpts_active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
+ ethtool-active-slave = <0>;
cpsw_emac0: slave@0 {
phy_id = <&davinci_mdio>, <0>;
/* Filled in by U-Boot */
@@ -76,6 +78,7 @@ Examples:
cpts_active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
+ ethtool-active-slave = <0>;
cpsw_emac0: slave@0 {
phy_id = <&davinci_mdio>, <0>;
/* Filled in by U-Boot */
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 01ffbc4..fa91eec 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1244,12 +1244,41 @@ static int cpsw_get_ts_info(struct net_device *ndev,
return 0;
}
+#define cpsw_slave_phy_index(priv) \
+ ((priv->data.dual_emac) ? priv->emac_port : \
+ priv->data.ethtool_active_slave)
+
+static int cpsw_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *ecmd)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int slave_no = cpsw_slave_phy_index(priv);
+
+ if (priv->slaves[slave_no].phy)
+ return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int slave_no = cpsw_slave_phy_index(priv);
+
+ if (priv->slaves[slave_no].phy)
+ return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd);
+ else
+ return -EOPNOTSUPP;
+}
+
static const struct ethtool_ops cpsw_ethtool_ops = {
.get_drvinfo = cpsw_get_drvinfo,
.get_msglevel = cpsw_get_msglevel,
.set_msglevel = cpsw_set_msglevel,
.get_link = ethtool_op_get_link,
.get_ts_info = cpsw_get_ts_info,
+ .get_settings = cpsw_get_settings,
+ .set_settings = cpsw_set_settings,
};
static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1346,6 +1375,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (!of_property_read_u32(node, "dual_emac", &prop))
data->dual_emac = prop;
+ if (!of_property_read_u32(node, "ethtool-active-slave", &prop))
+ data->ethtool_active_slave = prop;
+
/*
* Populate all the child nodes here...
*/
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 798fb80..e87e5cb 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -39,6 +39,7 @@ struct cpsw_platform_data {
u32 mac_control; /* Mac control register */
u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/
bool dual_emac; /* Enable Dual EMAC mode */
+ u32 ethtool_active_slave; /* ethtool slave */
};
#endif /* __CPSW_H__ */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/3] cpsw interrupt pacing and get/set phy setting implementation
From: Mugunthan V N @ 2013-03-07 12:30 UTC (permalink / raw)
To: netdev
Cc: davem, devicetree-discuss, linux-omap, b-cousson, paul,
Mugunthan V N
This patch serires implements the following features in CPSW driver
* get/set phy link settings
* interrupt pacing
Mugunthan V N (3):
driver: net: ethernet: cpsw: implement ethtool get/set phy setting
arm: dts: am33xx: add default ethtool slave to cpsw node
driver: net: ethernet: cpsw: implement interrupt pacing via ethtool
Documentation/devicetree/bindings/net/cpsw.txt | 3 +
arch/arm/boot/dts/am33xx.dtsi | 1 +
drivers/net/ethernet/ti/cpsw.c | 127 ++++++++++++++++++++++++
include/linux/platform_data/cpsw.h | 1 +
4 files changed, 132 insertions(+)
--
1.7.9.5
^ permalink raw reply
* Re: BCM5709 hang and state dump...
From: Daniel J Blueman @ 2013-03-07 12:18 UTC (permalink / raw)
To: Michael Chan; +Cc: Eilon Greenstein, Steffen Persvold, netdev
In-Reply-To: <1362654030.8980.62.camel@LTIRV-MCHAN1.corp.ad.broadcom.com>
On 03/07/2013 07:00 PM, Michael Chan wrote:
> On Thu, 2013-03-07 at 18:27 +0800, Daniel J Blueman wrote:
>> We've hit this again [1], with 3.8.0 this time. Any success on the debug
>> patches?
>
> I have 2 suggestions at this point:
>
> 1. Some users who report similar issues say that upgrading the BIOS has
> fixed the issue. So please try upgarding the BIOS if possible.
>
> 2. You can also disable MSIX and see if it runs any better. Use sysfs
> to do that or simply use bnx2 parameter disable_msi=1.
>
> I suspect that some MSIX IRQ messages are not delivered to the CPU for
> some reason. Please try one or both suggestions and let me know.
Yes, we're on the current of each available BIOS/firmware.
We'll move to APIC interrupts for the NIC and see how it goes over a few
weeks, since it takes a while to occur.
Thanks again Michael!
Daniel
--
Daniel J Blueman
Principal Software Engineer, Numascale Asia
^ permalink raw reply
* Re: [PATCH net-next] bond: add support to read speed and duplex via ethtool
From: Glen Turner @ 2013-03-07 12:11 UTC (permalink / raw)
To: Andy Gospodarek; +Cc: netdev
In-Reply-To: <27035.1362606373@death.nxdomain>
Hi Andy,
How does this relate to the bandwidth metric for an interface as seen by routing daemons?
An interface bandwidth as seen by routing daemons cannot change once carrier is up. Otherwise flaps of a link within a bond will cause routing protocol flaps; which they do not do at the moment, and which would be deeply, deeply undesirable.
I'd just add the maximum possible bandwidth of the interfaces, rather than the negotiated value. That's enough to get SNMP graphs working reasonably. It's not clear that a SNMP grapher will have reasonable behaviour with a changing bandwidth -- you'll end up with graphs where absolute throughput appears to fall, but what has happened is that a link has come online and utilisation has fallen. That's not a useful graph, as it's very much the "shape" of the traffic which is useful.
Checked IOS and JUNOS. In the absence of nerd knobs, both report the sum of the maximum possible interface bandwidths. So that's probably the behaviour SNMP graphing tools expect in any case.
Cheers, glen
^ permalink raw reply
* Re: [PATCH V2] bgmac: register MII bus
From: Rafał Miłecki @ 2013-03-07 11:55 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: Rafał Miłecki
In-Reply-To: <1362657208-6790-1-git-send-email-zajec5@gmail.com>
2013/3/7 Rafał Miłecki <zajec5@gmail.com>:
>
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
> V2: use kmalloc_array
Whoop, sorry for lack of --in-reply-to
--
Rafał
^ permalink raw reply
* [PATCH V2] bgmac: register MII bus
From: Rafał Miłecki @ 2013-03-07 11:53 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: Rafał Miłecki
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
---
V2: use kmalloc_array
---
drivers/net/ethernet/broadcom/bgmac.c | 80 ++++++++++++++++++++++++++++++++-
drivers/net/ethernet/broadcom/bgmac.h | 1 +
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index da5f439..d6cb376 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <bcm47xx_nvram.h>
@@ -1313,6 +1314,73 @@ static const struct ethtool_ops bgmac_ethtool_ops = {
};
/**************************************************
+ * MII
+ **************************************************/
+
+static int bgmac_mii_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ return bgmac_phy_read(bus->priv, mii_id, regnum);
+}
+
+static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ return bgmac_phy_write(bus->priv, mii_id, regnum, value);
+}
+
+static int bgmac_mii_register(struct bgmac *bgmac)
+{
+ struct mii_bus *mii_bus;
+ int i, err = 0;
+
+ mii_bus = mdiobus_alloc();
+ if (!mii_bus)
+ return -ENOMEM;
+
+ mii_bus->name = "bgmac mii bus";
+ sprintf(mii_bus->id, "%s-%d-%d", "bgmac", bgmac->core->bus->num,
+ bgmac->core->core_unit);
+ mii_bus->priv = bgmac;
+ mii_bus->read = bgmac_mii_read;
+ mii_bus->write = bgmac_mii_write;
+ mii_bus->parent = &bgmac->core->dev;
+ mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
+
+ mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+ if (!mii_bus->irq) {
+ err = -ENOMEM;
+ goto err_free_bus;
+ }
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mii_bus->irq[i] = PHY_POLL;
+
+ err = mdiobus_register(mii_bus);
+ if (err) {
+ bgmac_err(bgmac, "Registration of mii bus failed\n");
+ goto err_free_irq;
+ }
+
+ bgmac->mii_bus = mii_bus;
+
+ return err;
+
+err_free_irq:
+ kfree(mii_bus->irq);
+err_free_bus:
+ mdiobus_free(mii_bus);
+ return err;
+}
+
+static void bgmac_mii_unregister(struct bgmac *bgmac)
+{
+ struct mii_bus *mii_bus = bgmac->mii_bus;
+
+ mdiobus_unregister(mii_bus);
+ kfree(mii_bus->irq);
+ mdiobus_free(mii_bus);
+}
+
+/**************************************************
* BCMA bus ops
**************************************************/
@@ -1404,11 +1472,18 @@ static int bgmac_probe(struct bcma_device *core)
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+ err = bgmac_mii_register(bgmac);
+ if (err) {
+ bgmac_err(bgmac, "Cannot register MDIO\n");
+ err = -ENOTSUPP;
+ goto err_dma_free;
+ }
+
err = register_netdev(bgmac->net_dev);
if (err) {
bgmac_err(bgmac, "Cannot register net device\n");
err = -ENOTSUPP;
- goto err_dma_free;
+ goto err_mii_unregister;
}
netif_carrier_off(net_dev);
@@ -1417,6 +1492,8 @@ static int bgmac_probe(struct bcma_device *core)
return 0;
+err_mii_unregister:
+ bgmac_mii_unregister(bgmac);
err_dma_free:
bgmac_dma_free(bgmac);
@@ -1433,6 +1510,7 @@ static void bgmac_remove(struct bcma_device *core)
netif_napi_del(&bgmac->napi);
unregister_netdev(bgmac->net_dev);
+ bgmac_mii_unregister(bgmac);
bgmac_dma_free(bgmac);
bcma_set_drvdata(core, NULL);
free_netdev(bgmac->net_dev);
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
index 4ede614..98d4b5f 100644
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -399,6 +399,7 @@ struct bgmac {
struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
struct net_device *net_dev;
struct napi_struct napi;
+ struct mii_bus *mii_bus;
/* DMA */
struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
--
1.7.10.4
^ permalink raw reply related
* re L4 conntracking netns conversion
From: Alexey Dobriyan @ 2013-03-07 11:50 UTC (permalink / raw)
To: Gao feng, Eric W. Biederman, Pablo Neira Ayuso; +Cc: netdev, netfilter-devel
Lots of netns changes!
I can't verify right now, but unless I'm not mistaken,
every L4 protocol conversion is buggy/oopsable/remotely ddosable
because per-netns stuff is initialized after protocol is hooked into
master dispatcher.
See c296bb4d5d417d466c9bcc8afef68a3db5449a64.
^ permalink raw reply
* Re: [PATCH] bgmac: register MII bus
From: Florian Fainelli @ 2013-03-07 11:45 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: netdev, David S. Miller
In-Reply-To: <1362656523-23081-1-git-send-email-zajec5@gmail.com>
Hello Rafal,
On 03/07/2013 12:42 PM, Rafał Miłecki wrote:
>
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
> ---
This looking good, just one nitpick.
[snip]
> +
> + mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
You can use kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL) here
--
Florian
^ permalink raw reply
* [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
These patches enhance the driver adding the PTP support
and the initial code for RGMII/SGMII/TBI/RTBI modes.
Thx goes to Rayagond that wrote and tested the PTP and
to Byungho for SGMII/RGMII.
Concerning the PTP, I have hacked/reviewed and tested many
part of these patches also verifying the back compatibility on
several HW and chips.
The PTP support is quite intrusive because it needs to support the extended
descriptors used for saving the HW timestamps.
These are available in new chip generations, only.
So we have actually found useful to use some Kconfig options to
surround PTP and extended descriptor support. This approach helped on
old platform (embeeded system) where PTP is not supported and where we
do not want to pay extra code and check in critical rx/tx paths.
Concerning the SGMII/RGMII we have already discussed about the support
in the net.dev Mailing list with Byungho where these patchs were partially
analysed.
So I have only ported them against the latest net-next (and on
top of PTP). I have added some missing things: e.g. some parts of the
ethtool for ANE. As we clarified with Byungho, we will add further
enhancements on top of these patches if needed.
I have also built all against ARM/SH/X68 platforms and no issues on
ST-Boxes (built-in & dyn modules).
Welcome feedback.
Peppe
Giuseppe Cavallaro (5):
stmmac: support extend descriptors
stmmac: add missing supported filters to get_ts_info
stmmac: start adding pcs and rgmii core irq
stmmac: initial support to manage pcs modes
stmmac: update the Doc and Version (PTP+SGMII)
Rayagond Kokatanur (4):
stmmac: add tx_skbuff_dma to save descriptors used by PTP
stmmac: add IEEE 1588-2002 PTP support
stmmac: add the support for PTP hw clock driver
stmmac: add IEEE 1588-2008 PTP V2 support
Documentation/networking/stmmac.txt | 39 ++-
drivers/net/ethernet/stmicro/stmmac/Kconfig | 40 ++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 30 +-
drivers/net/ethernet/stmicro/stmmac/common.h | 106 ++++-
drivers/net/ethernet/stmicro/stmmac/descs.h | 47 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 40 ++-
.../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 104 ++++-
.../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 8 +-
.../net/ethernet/stmicro/stmmac/dwmac100_core.c | 3 +-
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 1 -
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 110 ++++-
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 40 ++-
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 16 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 27 +-
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 159 ++++++-
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 183 +++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 543 +++++++++++++++++--
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 209 ++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 74 +++
21 files changed, 1669 insertions(+), 115 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
--
1.7.4.4
^ permalink raw reply
* [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
In-Reply-To: <1362653419-1047-1-git-send-email-peppe.cavallaro@st.com>
This patch updates the filters for ethtool's get_ts_info to return support for
all filters which can be supported after having added the PTP support.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 37 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 -
3 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 2d6e2e1..a9a10dd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -34,6 +34,7 @@
#ifdef CONFIG_STMMAC_USE_HWSTAMP
#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
#endif
struct stmmac_priv {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 5698bf3..88d2d25 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -629,6 +629,41 @@ static int stmmac_set_coalesce(struct net_device *dev,
return 0;
}
+static int stmmac_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (priv->dma_cap.atime_stamp) {
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ if (priv->ptp_clock)
+ info->phc_index = ptp_clock_index(priv->ptp_clock);
+
+ 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_V1_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_ALL));
+ }
+ return 0;
+#else
+ return ethtool_op_get_ts_info(dev, info);
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+}
+
static const struct ethtool_ops stmmac_ethtool_ops = {
.begin = stmmac_check_if_running,
.get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -648,7 +683,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_eee = stmmac_ethtool_op_get_eee,
.set_eee = stmmac_ethtool_op_set_eee,
.get_sset_count = stmmac_get_sset_count,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = stmmac_get_ts_info,
.get_coalesce = stmmac_get_coalesce,
.set_coalesce = stmmac_set_coalesce,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ae92191..8786939 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -48,7 +48,6 @@
#include <linux/seq_file.h>
#endif
#ifdef CONFIG_STMMAC_USE_HWSTAMP
-#include <linux/net_tstamp.h>
#include "stmmac_ptp.h"
#endif
#include "stmmac.h"
--
1.7.4.4
^ permalink raw reply related
* [net-next.git 3/9] stmmac: support extend descriptors
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro, Rayagond Kokatanur
In-Reply-To: <1362653419-1047-1-git-send-email-peppe.cavallaro@st.com>
This patch adds a new driver Koption to support the
extend descriptors available in the chips newer than
the 3.50. In case of the extend descriptors cannot be
supported, at runtime, the probe function will fail.
This support extends the descriptor structure adding
the desc 4, 5, 6, 7 and give us extra information about
the received ethernet payload when it is carrying PTP
packets or TCP/UDP/ICMP over IP packets.
This introduce a small overhead in the receive process
so actually useful to debug and tack some important
fields in the descriptors.
Moreover, this support will be mandatory to have the
PTP version 2 where the extra descriptors 6 and 7
will be used to save the timestamp on enhanced
descriptor structure.
Thanks to Rayagond Kokatanur that sent me some parts
of this code inside the PTPv2 patches.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Rayagond Kokatanur <rayagond@vayavyalabs.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 13 +++++
drivers/net/ethernet/stmicro/stmmac/common.h | 29 +++++++++-
drivers/net/ethernet/stmicro/stmmac/descs.h | 47 +++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 1 +
.../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 8 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 58 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 25 +++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 38 ++++++++++---
11 files changed, 206 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index ef703b3..4fa974c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -83,4 +83,17 @@ config STMMAC_USE_HWSTAMP
register will be used to verify if either the IEEE 1588-2008 Advanced
Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
+config STMMAC_EXTENDED_DESC
+ bool "Enable Extended descriptors (DES4-5-6-7)"
+ depends on STMMAC_ETH
+ default n
+ ---help---
+ This option enhances the descriptors to support the extended status
+ that gives some information about the receive Ethernet payload when
+ it is carrying PTP packets or TCP/UDP/ICMP over IP.
+ This option cannot be used on GMAC Synopsys older than the 3.50
+ so the driver's probe will fail in this scenario.
+ This option also is mandatory for PTPv2 because the extra descriptors
+ are used for saving timestamps.
+
endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index fa8ff9b..df7123a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -117,6 +117,31 @@ struct stmmac_extra_stats {
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* Extended RDES status */
+ unsigned long ip_hdr_err;
+ unsigned long ip_payload_err;
+ unsigned long ip_csum_bypassed;
+ unsigned long ipv4_pkt_rcvd;
+ unsigned long ipv6_pkt_rcvd;
+ unsigned long rx_msg_type_ext_no_ptp;
+ unsigned long rx_msg_type_sync;
+ unsigned long rx_msg_type_follow_up;
+ unsigned long rx_msg_type_delay_req;
+ unsigned long rx_msg_type_delay_resp;
+ unsigned long rx_msg_type_pdelay_req;
+ unsigned long rx_msg_type_pdelay_resp;
+ unsigned long rx_msg_type_pdelay_follow_up;
+ unsigned long ptp_frame_type;
+ unsigned long ptp_ver;
+ unsigned long timestamp_dropped;
+ unsigned long av_pkt_rcvd;
+ unsigned long av_tagged_pkt_rcvd;
+ unsigned long vlan_tag_priority_val;
+ unsigned long l3_filter_match;
+ unsigned long l4_filter_match;
+ unsigned long l3_l4_filter_no_match;
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
/* CSR Frequency Access Defines*/
@@ -289,7 +314,7 @@ struct stmmac_desc_ops {
int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p);
+ struct dma_desc *p, int atds);
/* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p);
/* get tx timestamp status */
@@ -305,7 +330,7 @@ struct stmmac_desc_ops {
struct stmmac_dma_ops {
/* DMA core initialization */
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
- int burst_len, u32 dma_tx, u32 dma_rx);
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds);
/* Dump DMA registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Set tx/rx threshold in the csr6 register
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 223adf9..c3e8fe4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -60,7 +60,7 @@ struct dma_desc {
} rx;
struct {
/* RDES0 */
- u32 payload_csum_error:1;
+ u32 rx_mac_addr:1;
u32 crc_error:1;
u32 dribbling:1;
u32 error_gmii:1;
@@ -160,15 +160,56 @@ struct dma_desc {
} des01;
unsigned int des2;
unsigned int des3;
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ union {
+ struct {
+ u32 ip_payload_type:3;
+ u32 ip_hdr_err:1;
+ u32 ip_payload_err:1;
+ u32 ip_csum_bypassed:1;
+ u32 ipv4_pkt_rcvd:1;
+ u32 ipv6_pkt_rcvd:1;
+ u32 msg_type:4;
+ u32 ptp_frame_type:1;
+ u32 ptp_ver:1;
+ u32 timestamp_dropped:1;
+ u32 reserved:1;
+ u32 av_pkt_rcvd:1;
+ u32 av_tagged_pkt_rcvd:1;
+ u32 vlan_tag_priority_val:3;
+ u32 reserved3:3;
+ u32 l3_filter_match:1;
+ u32 l4_filter_match:1;
+ u32 l3_l4_filter_no_match:2;
+ u32 reserved4:4;
+ } erx;
+ struct {
+ u32 reserved;
+ } etx;
+ } des4;
+ unsigned int des5; /* Reserved */
+ unsigned int des6; /* Tx/Rx Timestamp Low */
+ unsigned int des7; /* Tx/Rx Timestamp High */
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
/* Transmit checksum insertion control */
enum tdes_csum_insertion {
cic_disabled = 0, /* Checksum Insertion Control */
cic_only_ip = 1, /* Only IP header */
- cic_no_pseudoheader = 2, /* IP header but pseudoheader
- * is not calculated */
+ /* IP header but pseudoheader is not calculated */
+ cic_no_pseudoheader = 2,
cic_full = 3, /* IP header and pseudoheader */
};
+/* Extended RDES4 definitions */
+#define RDES_EXT_NO_PTP 0
+#define RDES_EXT_SYNC 0x1
+#define RDES_EXT_FOLLOW_UP 0x2
+#define RDES_EXT_DELAY_REQ 0x3
+#define RDES_EXT_DELAY_RESP 0x4
+#define RDES_EXT_PDELAY_REQ 0x5
+#define RDES_EXT_PDELAY_RESP 0x6
+#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
+
#endif /* __DESCS_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 7ad56af..85466e5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -155,6 +155,7 @@ enum inter_frame_gap {
/* Programmable burst length (passed thorugh platform)*/
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
#define DMA_BUS_MODE_PBL_SHIFT 8
+#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
enum rx_tx_priority_ratio {
double_ratio = 0x00004000, /*2:1 */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index bf83c03..f1c4b2c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -30,8 +30,8 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
-static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
@@ -73,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
#ifdef CONFIG_STMMAC_DA
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
#endif
+
+ if (atds)
+ value |= DMA_BUS_MODE_ATDS;
+
writel(value, ioaddr + DMA_BUS_MODE);
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index c2b4d55..e979a8b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -32,8 +32,8 @@
#include "dwmac100.h"
#include "dwmac_dma.h"
-static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 4d635d5..50707c5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -150,8 +150,9 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
+
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p)
+ struct dma_desc *p, int atds)
{
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -198,7 +199,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
* At any rate, we need to understand if the CSUM hw computation is ok
* and report this info to the upper layers. */
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
- p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
+ p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
if (unlikely(p->des01.erx.dribbling)) {
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
@@ -225,6 +226,59 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->rx_vlan++;
}
#endif
+
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* On new chips the RDES0[0] is used for looking at the RDES4;
+ * note that atds won't be set for ID older than 3.50.
+ */
+ if (unlikely((atds) && (p->des01.erx.rx_mac_addr))) {
+ if (p->des4.erx.ip_hdr_err)
+ x->ip_hdr_err++;
+ if (p->des4.erx.ip_payload_err)
+ x->ip_payload_err++;
+ if (p->des4.erx.ip_csum_bypassed)
+ x->ip_csum_bypassed++;
+ if (p->des4.erx.ipv4_pkt_rcvd)
+ x->ipv4_pkt_rcvd++;
+ if (p->des4.erx.ipv6_pkt_rcvd)
+ x->ipv6_pkt_rcvd++;
+ if (p->des4.erx.msg_type == RDES_EXT_SYNC)
+ x->rx_msg_type_sync++;
+ else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
+ x->rx_msg_type_follow_up++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_delay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
+ x->rx_msg_type_delay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_pdelay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
+ x->rx_msg_type_pdelay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
+ x->rx_msg_type_pdelay_follow_up++;
+ else
+ x->rx_msg_type_ext_no_ptp++;
+ if (p->des4.erx.ptp_frame_type)
+ x->ptp_frame_type++;
+ if (p->des4.erx.ptp_ver)
+ x->ptp_ver++;
+ if (p->des4.erx.timestamp_dropped)
+ x->timestamp_dropped++;
+ if (p->des4.erx.av_pkt_rcvd)
+ x->av_pkt_rcvd++;
+ if (p->des4.erx.av_tagged_pkt_rcvd)
+ x->av_tagged_pkt_rcvd++;
+ if (p->des4.erx.vlan_tag_priority_val)
+ x->vlan_tag_priority_val++;
+ if (p->des4.erx.l3_filter_match)
+ x->l3_filter_match++;
+ if (p->des4.erx.l4_filter_match)
+ x->l4_filter_match++;
+ if (p->des4.erx.l3_l4_filter_no_match)
+ x->l3_l4_filter_no_match++;
+ }
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
+
return ret;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index edb5e88..9eefb6c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -73,7 +73,7 @@ static int ndesc_get_tx_len(struct dma_desc *p)
* In case of success, it returns good_frame because the GMAC device
* is supposed to be able to compute the csum in HW. */
static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p)
+ struct dma_desc *p, int atds)
{
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 665f2a2..50b5f26 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -99,6 +99,7 @@ struct stmmac_priv {
int hwts_rx_en;
unsigned int default_addend;
#endif
+ int atds;
};
extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index d1ac39c..5698bf3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -108,6 +108,31 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* Extended RDES status */
+ STMMAC_STAT(ip_hdr_err),
+ STMMAC_STAT(ip_payload_err),
+ STMMAC_STAT(ip_csum_bypassed),
+ STMMAC_STAT(ipv4_pkt_rcvd),
+ STMMAC_STAT(ipv6_pkt_rcvd),
+ STMMAC_STAT(rx_msg_type_ext_no_ptp),
+ STMMAC_STAT(rx_msg_type_sync),
+ STMMAC_STAT(rx_msg_type_follow_up),
+ STMMAC_STAT(rx_msg_type_delay_req),
+ STMMAC_STAT(rx_msg_type_delay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_req),
+ STMMAC_STAT(rx_msg_type_pdelay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_follow_up),
+ STMMAC_STAT(ptp_frame_type),
+ STMMAC_STAT(ptp_ver),
+ STMMAC_STAT(timestamp_dropped),
+ STMMAC_STAT(av_pkt_rcvd),
+ STMMAC_STAT(av_tagged_pkt_rcvd),
+ STMMAC_STAT(vlan_tag_priority_val),
+ STMMAC_STAT(l3_filter_match),
+ STMMAC_STAT(l4_filter_match),
+ STMMAC_STAT(l3_l4_filter_no_match),
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3bbd554..6174f34 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1058,15 +1058,29 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
* @priv : private structure
* Description: select the Enhanced/Alternate or Normal descriptors
*/
-static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
+static int stmmac_selec_desc_mode(struct stmmac_priv *priv)
{
+ int ret = 0;
+
if (priv->plat->enh_desc) {
pr_info(" Enhanced/Alternate descriptors\n");
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* GMAC older than 3.50 has no extended descriptors */
+ if (priv->synopsys_id >= DWMAC_CORE_3_50) {
+ pr_info("\tEnabled extended descriptors\n");
+ priv->atds = 1;
+ } else {
+ pr_err("ERROR: cannot support extended descriptors\n");
+ ret = -EOPNOTSUPP;
+ }
+#endif
priv->hw->desc = &enh_desc_ops;
} else {
pr_info(" Normal descriptors\n");
priv->hw->desc = &ndesc_ops;
}
+
+ return ret;
}
/**
@@ -1161,7 +1175,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
burst_len, priv->dma_tx_phy,
- priv->dma_rx_phy);
+ priv->dma_rx_phy, priv->atds);
}
/**
@@ -1602,7 +1616,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
/* read the status of the incoming frame */
status = (priv->hw->desc->rx_status(&priv->dev->stats,
- &priv->xstats, p));
+ &priv->xstats, p,
+ priv->atds));
if (unlikely(status == discard_frame)) {
priv->dev->stats.rx_errors++;
#ifdef CONFIG_STMMAC_USE_HWSTAMP
@@ -2117,7 +2132,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
*/
static int stmmac_hw_init(struct stmmac_priv *priv)
{
- int ret = 0;
+ int ret;
struct mac_device_info *mac;
/* Identify the MAC HW device */
@@ -2161,8 +2176,12 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
} else
pr_info(" No HW DMA feature register supported");
- /* Select the enhnaced/normal descriptor structures */
- stmmac_selec_desc_mode(priv);
+ /* Select the enhnaced/normal descriptor structures and return
+ * EOPNOTSUPP in case of failing.
+ */
+ ret = stmmac_selec_desc_mode(priv);
+ if (ret)
+ return ret;
/* Enable the IPC (Checksum Offload) and check if the feature has been
* enabled during the core configuration. */
@@ -2183,7 +2202,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
device_set_wakeup_capable(priv->device, 1);
}
- return ret;
+ return 0;
}
/**
@@ -2229,7 +2248,9 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
priv->plat->phy_addr = phyaddr;
/* Init MAC and get the capabilities */
- stmmac_hw_init(priv);
+ ret = stmmac_hw_init(priv);
+ if (ret)
+ goto error_free_netdev;
ndev->netdev_ops = &stmmac_netdev_ops;
@@ -2300,6 +2321,7 @@ error_clk_get:
unregister_netdev(ndev);
error_netdev_register:
netif_napi_del(&priv->napi);
+error_free_netdev:
free_netdev(ndev);
return NULL;
--
1.7.4.4
^ permalink raw reply related
* [net-next.git 4/9] stmmac: add the support for PTP hw clock driver
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
In-Reply-To: <1362653419-1047-1-git-send-email-peppe.cavallaro@st.com>
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch implements PHC (ptp hardware clock) driver for stmmac
driver to support 1588 PTP.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +-
drivers/net/ethernet/stmicro/stmmac/common.h | 4 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 13 ++
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 50 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +++-
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 209 ++++++++++++++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 2 +
7 files changed, 303 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index cc97c07..40ee3df 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -3,7 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
+stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o stmmac_ptp.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7123a..a10974c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -387,6 +387,10 @@ struct stmmac_hwtimestamp {
void (*config_sub_second_increment) (void __iomem *ioaddr);
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
int (*config_addend)(void __iomem *ioaddr, u32 addend);
+ int (*adjust_systime)(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub);
+ u32 (*get_systime_sec)(void __iomem *ioaddr);
+ u32 (*get_systime_nsec)(void __iomem *ioaddr);
};
#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 50b5f26..2d6e2e1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -32,6 +32,10 @@
#include <linux/pci.h>
#include "common.h"
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+#include <linux/ptp_clock_kernel.h>
+#endif
+
struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
struct dma_desc *dma_tx ____cacheline_aligned;
@@ -98,6 +102,9 @@ struct stmmac_priv {
int hwts_tx_en;
int hwts_rx_en;
unsigned int default_addend;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_ops;
+ spinlock_t ptp_lock;
#endif
int atds;
};
@@ -111,6 +118,12 @@ extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
#ifdef CONFIG_STMMAC_USE_HWSTAMP
extern const struct stmmac_hwtimestamp stmmac_ptp;
+extern int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub);
+extern u32 stmmac_get_systime_sec(void __iomem *ioaddr);
+extern u32 stmmac_get_systime_nsec(void __iomem *ioaddr);
+extern int stmmac_ptp_register(struct stmmac_priv *priv);
+extern void stmmac_ptp_unregister(struct stmmac_priv *priv);
#endif
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
index be9e399..bec2278 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
@@ -121,9 +121,59 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
return 0;
}
+static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub)
+{
+ u32 value;
+ int limit;
+
+ /* wait for previous(if any) system time adjust/update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
+ ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSUPDT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time adjust/update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static u32 stmmac_get_systime_sec(void __iomem *ioaddr)
+{
+ return readl(ioaddr + PTP_STSR);
+}
+
+static u32 stmmac_get_systime_nsec(void __iomem *ioaddr)
+{
+ return readl(ioaddr + PTP_STNSR);
+}
+
const struct stmmac_hwtimestamp stmmac_ptp = {
.config_hw_tstamping = stmmac_config_hw_tstamping,
.init_systime = stmmac_init_systime,
.config_sub_second_increment = stmmac_config_sub_second_increment,
.config_addend = stmmac_config_addend,
+ .adjust_systime = stmmac_adjust_systime,
+ .get_systime_sec = stmmac_get_systime_sec,
+ .get_systime_nsec = stmmac_get_systime_nsec,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6174f34..009abf8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -474,24 +474,37 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
}
-static void stmmac_init_ptp(struct stmmac_priv *priv)
+static int stmmac_init_ptp(struct stmmac_priv *priv)
{
- if (priv->dma_cap.time_stamp)
- pr_debug("IEEE 1588-2002 Time Stamp supported\n");
- if (priv->dma_cap.atime_stamp)
- pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+ if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+ return -EOPNOTSUPP;
+
+ if (netif_msg_hw(priv)) {
+ if (priv->dma_cap.time_stamp)
+ pr_debug("IEEE 1588-2002 Time Stamp supported\n");
+ if (priv->dma_cap.atime_stamp)
+ pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+ }
priv->hw->ptp = &stmmac_ptp;
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
+ return stmmac_ptp_register(priv);
+}
+
+static void stmmac_release_ptp(struct stmmac_priv *priv)
+{
+ stmmac_ptp_unregister(priv);
}
+
#else
#define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
#define stmmac_get_rx_hwtstamp(priv, p, skb)
#define stmmac_get_tx_hwtstamp(priv, p, skb) 0
-#define stmmac_init_ptp(priv)
+#define stmmac_init_ptp(priv) 0
+#define stmmac_release_ptp(priv)
#endif /* CONFIG_STMMAC_USE_HWSTAMP */
/**
@@ -1301,7 +1314,9 @@ static int stmmac_open(struct net_device *dev)
stmmac_mmc_setup(priv);
- stmmac_init_ptp(priv);
+ ret = stmmac_init_ptp(priv);
+ if (ret)
+ pr_warn("%s: failed PTP initialisation\n", __func__);
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
@@ -1403,6 +1418,8 @@ static int stmmac_release(struct net_device *dev)
#endif
clk_disable_unprepare(priv->stmmac_clk);
+ stmmac_release_ptp(priv);
+
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
new file mode 100644
index 0000000..53680bf
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ PTP 1588 clock using the STMMAC.
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+*******************************************************************************/
+#include "stmmac.h"
+#include "stmmac_ptp.h"
+
+/**
+ * stmmac_adjust_freq
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ppb: desired period change in parts ber billion
+ *
+ * Description: this function will adjust the frequency of hardware clock.
+ */
+static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ u32 diff, addend;
+ int neg_adj = 0;
+ u64 adj;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+
+ addend = priv->default_addend;
+ adj = addend;
+ adj *= ppb;
+ /* div_u64 will divided the "adj" by "1000000000ULL"
+ * and return the quotient
+ */
+ diff = div_u64(adj, 1000000000ULL);
+
+ addend = neg_adj ? (addend - diff) : (addend + diff);
+
+ priv->hw->ptp->config_addend(priv->ioaddr, addend);
+
+ return 0;
+}
+
+/**
+ * stmmac_adjust_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @delta: desired change in nanoseconds
+ *
+ * Description: this function will shift/adjust the hardware clock time.
+ */
+static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+ u32 sec, nsec;
+ u32 quotient, reminder;
+ int neg_adj = 0;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ if (delta < 0) {
+ neg_adj = 1;
+ delta = -delta;
+ }
+
+ quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
+ sec = quotient;
+ nsec = reminder;
+ priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_get_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: pointer to hold time/result
+ *
+ * Description: this function will read the current time from the
+ * hardware clock and store it in @ts.
+ */
+static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ ts->tv_sec = priv->hw->ptp->get_systime_sec(priv->ioaddr);
+ ts->tv_nsec = priv->hw->ptp->get_systime_nsec(priv->ioaddr);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_set_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: time value to set
+ *
+ * Description: this function will set the current time on the
+ * hardware clock.
+ */
+static int stmmac_set_time(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ return 0;
+}
+
+static int stmmac_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+/* structure describing a PTP hardware clock */
+static struct ptp_clock_info stmmac_ptp_clock_ops = {
+ .owner = THIS_MODULE,
+ .name = "stmmac_ptp_clock",
+ .max_adj = STMMAC_SYSCLOCK,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjfreq = stmmac_adjust_freq,
+ .adjtime = stmmac_adjust_time,
+ .gettime = stmmac_get_time,
+ .settime = stmmac_set_time,
+ .enable = stmmac_enable,
+};
+
+/**
+ * stmmac_ptp_register
+ *
+ * @ndev: net device pointer
+ *
+ * Description: this function will register the ptp clock driver
+ * to kernel. It also does some house keeping work.
+ */
+int stmmac_ptp_register(struct stmmac_priv *priv)
+{
+ spin_lock_init(&priv->ptp_lock);
+ priv->ptp_clock_ops = stmmac_ptp_clock_ops;
+
+ priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
+ priv->device);
+ if (IS_ERR(priv->ptp_clock)) {
+ priv->ptp_clock = NULL;
+ pr_err("ptp_clock_register() failed on %s\n", priv->dev->name);
+ } else
+ pr_debug("Added PTP HW clock successfully on %s\n",
+ priv->dev->name);
+
+ return 0;
+}
+
+/**
+ * stmmac_ptp_unregister
+ *
+ * @ndev: net device pointer
+ *
+ * Description: this function will remove/unregister the ptp clock driver
+ * from the kernel.
+ */
+void stmmac_ptp_unregister(struct stmmac_priv *priv)
+{
+ if (priv->ptp_clock) {
+ ptp_clock_unregister(priv->ptp_clock);
+ pr_debug("Removed PTP HW clock successfully on %s\n",
+ priv->dev->name);
+ }
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index d557696..3dbc047 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -40,6 +40,8 @@
#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
#define PTP_TSR 0x0728 /* Timestamp Status */
+#define PTP_STNSUR_ADDSUB_SHIFT 31
+
/* PTP TCR defines */
#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
--
1.7.4.4
^ permalink raw reply related
* [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
In-Reply-To: <1362653419-1047-1-git-send-email-peppe.cavallaro@st.com>
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch adds a new pointer variable called "tx_skbuff_dma" to private
data structure. This variable will holds the physical address of packet
to be transmitted & same will be used to free/unmap the memory once the
corresponding packet is transmitted by device.
Prior to this patch the descriptor buffer pointer(ie des2) itself was
being used for freeing/unmapping the buffer memory. But in case PTP v1
with normal descriptor the field(des2) will be overwritten by device
with timestamp value, hence driver will loose the buffer pointer to be
freed/unmapped.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Reviewed-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 3 +++
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 3 +++
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 21 ++++++++++++++++-----
4 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 0668659..ad3d75f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -47,6 +47,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
while (len != 0) {
@@ -57,6 +58,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
csum);
priv->hw->desc->set_tx_owner(desc);
@@ -67,6 +69,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 0, len,
csum);
priv->hw->desc->set_tx_owner(desc);
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 4b785e1..839e349 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -48,6 +48,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
csum);
@@ -57,6 +58,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
wmb();
@@ -65,6 +67,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b05df89..013a7d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -37,6 +37,7 @@ struct stmmac_priv {
struct dma_desc *dma_tx ____cacheline_aligned;
dma_addr_t dma_tx_phy;
struct sk_buff **tx_skbuff;
+ dma_addr_t *tx_skbuff_dma;
unsigned int cur_tx;
unsigned int dirty_tx;
unsigned int dma_tx_size;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 39c6c55..260af93 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -540,6 +540,8 @@ static void init_dma_desc_rings(struct net_device *dev)
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
+ priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
+ GFP_KERNEL);
priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
GFP_KERNEL);
priv->dma_tx =
@@ -591,6 +593,7 @@ static void init_dma_desc_rings(struct net_device *dev)
/* TX INITIALIZATION */
for (i = 0; i < txsize; i++) {
+ priv->tx_skbuff_dma[i] = 0;
priv->tx_skbuff[i] = NULL;
priv->dma_tx[i].des2 = 0;
}
@@ -638,12 +641,14 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
for (i = 0; i < priv->dma_tx_size; i++) {
if (priv->tx_skbuff[i] != NULL) {
struct dma_desc *p = priv->dma_tx + i;
- if (p->des2)
- dma_unmap_single(priv->device, p->des2,
+ if (priv->tx_skbuff_dma[i])
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[i],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
+ priv->tx_skbuff_dma[i] = 0;
}
}
}
@@ -664,6 +669,7 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
priv->dma_rx, priv->dma_rx_phy);
kfree(priv->rx_skbuff_dma);
kfree(priv->rx_skbuff);
+ kfree(priv->tx_skbuff_dma);
kfree(priv->tx_skbuff);
}
@@ -730,10 +736,13 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
- if (likely(p->des2))
- dma_unmap_single(priv->device, p->des2,
+ if (likely(priv->tx_skbuff_dma[entry])) {
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[entry],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = 0;
+ }
priv->hw->ring->clean_desc3(p);
if (likely(skb != NULL)) {
@@ -1249,7 +1258,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
desc = priv->dma_tx + entry;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
- nopaged_len, DMA_TO_DEVICE);
+ nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
csum_insertion);
}
@@ -1264,6 +1274,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->tx_skbuff[entry] = NULL;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
wmb();
--
1.7.4.4
^ permalink raw reply related
* [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
In-Reply-To: <1362653419-1047-1-git-send-email-peppe.cavallaro@st.com>
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch enhances the stmmac driver to support IEEE 1588-2002
PTP (Precision Time Protocol) version 1.
IEEE 1588-2002 standard defines a protocol, Precision Time
Protocol(PTP),
which enables precise synchronization of clocks in measurement and
control systems implemented with technologies such as network
communication,local computing, & distributed objects.
HW Timestamp support can be enabled while configuring the Kernel and
the Koption is: STMMAC_USE_HWSTAMP
At runtime, the support is verified by looking at the HW capability
register.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 +
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 23 ++-
drivers/net/ethernet/stmicro/stmmac/common.h | 27 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 1 -
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 37 +++
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 34 +++
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 14 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 8 +
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 129 ++++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 255 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 72 ++++++
12 files changed, 588 insertions(+), 24 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index c0ea838..ef703b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -71,5 +71,16 @@ config STMMAC_CHAINED
endchoice
+config STMMAC_USE_HWSTAMP
+ bool "Use IEEE 1588 Precision Time Protocol"
+ depends on STMMAC_ETH
+ select PTP_1588_CLOCK
+ default n
+ ---help---
+ Enable this option to support the IEEE 1588 Precision Time Protocol
+ (PTP) and HW Timestamps.
+ At runtime, on new chip generations, the hardware capability
+ register will be used to verify if either the IEEE 1588-2008 Advanced
+ Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c8e8ea6..cc97c07 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
+stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index ad3d75f..dd60f6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -92,16 +92,35 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (priv->hwts_rx_en)
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_rx +
+ ((priv->dirty_rx) + 1) % priv->dma_rx_size);
}
static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
{
}
-static void stmmac_clean_desc3(struct dma_desc *p)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
+ int tstamp_taken)
{
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (tstamp_taken && priv->hw->desc->get_tx_ls(p))
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_tx +
+ ((priv->dirty_tx + 1) % priv->dma_tx_size));
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 186d148..fa8ff9b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -290,6 +290,16 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
+ /* Set tx timestamp enable bit */
+ void (*enable_tx_timestamp) (struct dma_desc *p);
+ /* get tx timestamp status */
+ int (*get_tx_timestamp_status) (struct dma_desc *p);
+ /* get tx/rx timestamp low value */
+ u32 (*get_timestamp_low) (struct dma_desc *p);
+ /* get tx/rx timestamp high value */
+ u32 (*get_timestamp_high) (struct dma_desc *p);
+ /* get rx timestamp status */
+ int (*get_rx_timestamp_status) (struct dma_desc *p);
};
struct stmmac_dma_ops {
@@ -346,6 +356,15 @@ struct stmmac_ops {
void (*set_eee_pls) (void __iomem *ioaddr, int link);
};
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+struct stmmac_hwtimestamp {
+ void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
+ void (*config_sub_second_increment) (void __iomem *ioaddr);
+ int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
+ int (*config_addend)(void __iomem *ioaddr, u32 addend);
+};
+#endif
+
struct mac_link {
int port;
int duplex;
@@ -360,11 +379,11 @@ struct mii_regs {
struct stmmac_ring_mode_ops {
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
- void (*refill_desc3) (int bfsize, struct dma_desc *p);
+ void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size);
- void (*clean_desc3) (struct dma_desc *p);
+ void (*clean_desc3) (void *priv, struct dma_desc *p, int tstamp_taken);
int (*set_16kib_bfsize) (int mtu);
};
@@ -373,6 +392,9 @@ struct mac_device_info {
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_ring_mode_ops *ring;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ const struct stmmac_hwtimestamp *ptp;
+#endif
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
unsigned int synopsys_uid;
@@ -390,5 +412,4 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
extern const struct stmmac_ring_mode_ops ring_mode_ops;
-
#endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 491d7e9..8c4ea93 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -286,4 +286,3 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
addr[4] = hi_addr & 0xff;
addr[5] = (hi_addr >> 8) & 0xff;
}
-
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 2fc8ef9..4d635d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -323,6 +323,38 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.erx.frame_length;
}
+static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.etx.time_stamp_enable = 1;
+}
+
+static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.etx.time_stamp_status;
+}
+
+static u32 enh_desc_get_timestamp_low(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ return p->des2;
+}
+
+static u32 enh_desc_get_timestamp_high(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ return p->des3;
+}
+
+static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is currupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+}
+
const struct stmmac_desc_ops enh_desc_ops = {
.tx_status = enh_desc_get_tx_status,
.rx_status = enh_desc_get_rx_status,
@@ -339,4 +371,9 @@ const struct stmmac_desc_ops enh_desc_ops = {
.set_tx_owner = enh_desc_set_tx_owner,
.set_rx_owner = enh_desc_set_rx_owner,
.get_rx_frame_len = enh_desc_get_rx_frame_len,
+ .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
+ .get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
+ .get_timestamp_low = enh_desc_get_timestamp_low,
+ .get_timestamp_high = enh_desc_get_timestamp_high,
+ .get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 68962c5..edb5e88 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -215,6 +215,35 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.rx.frame_length;
}
+static void ndesc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.tx.time_stamp_enable = 1;
+}
+
+static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.tx.time_stamp_status;
+}
+
+static u32 ndesc_get_timestamp_low(struct dma_desc *p)
+{
+ return p->des2;
+}
+
+static u32 ndesc_get_timestamp_high(struct dma_desc *p)
+{
+ return p->des3;
+}
+
+static int ndesc_get_rx_timestamp_status(struct dma_desc *p)
+{
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is currupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+}
+
const struct stmmac_desc_ops ndesc_ops = {
.tx_status = ndesc_get_tx_status,
.rx_status = ndesc_get_rx_status,
@@ -231,4 +260,9 @@ const struct stmmac_desc_ops ndesc_ops = {
.set_tx_owner = ndesc_set_tx_owner,
.set_rx_owner = ndesc_set_rx_owner,
.get_rx_frame_len = ndesc_get_rx_frame_len,
+ .enable_tx_timestamp = ndesc_enable_tx_timestamp,
+ .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
+ .get_timestamp_low = ndesc_get_timestamp_low,
+ .get_timestamp_high = ndesc_get_timestamp_high,
+ .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 839e349..94a1c2f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -85,11 +85,14 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
- /* Fill DES3 in case of RING mode */
- if (bfsize >= BUF_SIZE_8KiB)
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (unlikely(priv->plat->has_gmac))
+ /* Fill DES3 in case of RING mode */
+ if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
/* In ring mode we need to fill the desc3 because it is used
@@ -105,7 +108,8 @@ static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
{
}
-static void stmmac_clean_desc3(struct dma_desc *p)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
+ int tstamp_taken)
{
if (unlikely(p->des3))
p->des3 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 013a7d5..665f2a2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -94,6 +94,11 @@ struct stmmac_priv {
u32 tx_coal_timer;
int use_riwt;
u32 rx_riwt;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ int hwts_tx_en;
+ int hwts_rx_en;
+ unsigned int default_addend;
+#endif
};
extern int phyaddr;
@@ -103,6 +108,9 @@ extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+extern const struct stmmac_hwtimestamp stmmac_ptp;
+#endif
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
int stmmac_resume(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
new file mode 100644
index 0000000..be9e399
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This implements all the API for managing HW timestamp & PTP.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include "common.h"
+#include "stmmac_ptp.h"
+
+static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
+{
+ writel(data, ioaddr + PTP_TCR);
+}
+
+static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr + PTP_TCR);
+ unsigned long data;
+
+ /* Convert the ptp_clock to nano second
+ * formula = (1/ptp_clock) * 1000000000
+ * where, ptp_clock = 50MHz for FINE correction method &
+ * ptp_clock = STMMAC_SYSCLOCK for COARSE correction method
+ */
+ if (value & PTP_TCR_TSCFUPDT)
+ data = (1000000000ULL / 50000000);
+ else
+ data = (1000000000ULL / STMMAC_SYSCLOCK);
+
+ writel(data, ioaddr + PTP_SSIR);
+}
+
+static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
+{
+ int limit;
+ u32 value;
+
+ /* wait for previous(if any) system time initialize to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
+ break;
+ mdelay(10);
+ }
+
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(nsec, ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSINIT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time initialize to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
+{
+ u32 value;
+ int limit;
+
+ /* wait for previous (if any) addend update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(addend, ioaddr + PTP_TAR);
+ /* issue command to update the addend value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSADDREG;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present addend update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+const struct stmmac_hwtimestamp stmmac_ptp = {
+ .config_hw_tstamping = stmmac_config_hw_tstamping,
+ .init_systime = stmmac_init_systime,
+ .config_sub_second_increment = stmmac_config_sub_second_increment,
+ .config_addend = stmmac_config_addend,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 260af93..3bbd554 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -47,6 +47,10 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#endif
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+#include <linux/net_tstamp.h>
+#include "stmmac_ptp.h"
+#endif
#include "stmmac.h"
#undef STMMAC_DEBUG
@@ -304,6 +308,192 @@ static void stmmac_eee_adjust(struct stmmac_priv *priv)
priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
}
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+/* stmmac_get_tx_hwtstamp:
+ * @priv : pointer to private device structure.
+ * @p : pointer to desc structure.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read timestamp from the descriptor & pass it to stack.
+ * and also perform some sanity checks.
+ * Return value :
+ * 1 if time stamp is taken & 0 if time stamp is not taken.
+ */
+static unsigned int stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
+ struct dma_desc *p,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps shhwtstamp;
+ u64 ns;
+
+ if (!priv->hwts_tx_en)
+ return 0;
+
+ /* if skb doesn't support hw tstamp */
+ if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
+ return 0;
+
+ /* check tx tstamp status */
+ if (!priv->hw->desc->get_tx_timestamp_status(p))
+ return 0;
+
+ /* get the valid tstamp */
+ ns = priv->hw->desc->get_timestamp_low(p);
+ /* convert high/sec time stamp value to nanosecond */
+ ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+
+ memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp.hwtstamp = ns_to_ktime(ns);
+ /* pass tstamp to stack */
+ skb_tstamp_tx(skb, &shhwtstamp);
+
+ return 1;
+}
+
+/* stmmac_get_rx_hwtstamp:
+ * @priv : pointer to private device structure.
+ * @p : pointer to desc structure.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read received packet's timestamp from the descriptor
+ * and pass it to stack. It also perform some sanity checks.
+ */
+static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamp = NULL;
+ u64 ns;
+
+ if (!priv->hwts_rx_en)
+ return;
+
+ /* if rx tstamp is not valid */
+ if (!priv->hw->desc->get_rx_timestamp_status(p))
+ return;
+
+ /* get valid tstamp */
+ ns = priv->hw->desc->get_timestamp_low(p);
+ /* convert high/sec time stamp value to nanosecond */
+ ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+ shhwtstamp = skb_hwtstamps(skb);
+ memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * stmmac_hwtstamp_ioctl - control hardware timestamping.
+ * @dev: device pointer.
+ * @ifr: An IOCTL specefic structure, that can contain a pointer to
+ * a proprietary structure used to pass information to the driver.
+ * Description:
+ * This function configures the MAC to enable/disable both outgoing(TX)
+ * and incoming(RX) packets time stamping based on user input.
+ * Return Value:
+ * 0 on success and an appropriate -ve integer on failure.
+ */
+static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct hwtstamp_config config;
+ struct timespec now;
+ u64 temp = 0;
+
+ if (!priv->dma_cap.time_stamp) {
+ netdev_alert(priv->dev, "No HW time stamping supported\n");
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_from_user(&config, ifr->ifr_data,
+ sizeof(struct hwtstamp_config)))
+ return -EFAULT;
+
+ pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
+ __func__, config.flags, config.tx_type, config.rx_filter);
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+ default:
+ /* PTP v1, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
+ }
+ priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
+
+ if (!priv->hwts_tx_en && !priv->hwts_rx_en)
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
+ else {
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr,
+ (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT));
+
+ /* program Sub Second Increment reg */
+ priv->hw->ptp->config_sub_second_increment(priv->ioaddr);
+
+ /* calculate default added value:
+ * formula is :
+ * addend = (2^32)/freq_div_ratio;
+ * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
+ * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
+ * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
+ * achive 20ns accuracy.
+ *
+ * 2^x * y == (y << x), hence
+ * 2^32 * 50000000 ==> (50000000 << 32)
+ */
+ temp = (u64)(50000000ULL << 32);
+ priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK);
+ priv->hw->ptp->config_addend(priv->ioaddr,
+ priv->default_addend);
+
+ /* initialize system time */
+ getnstimeofday(&now);
+ priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec,
+ now.tv_nsec);
+ }
+
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
+}
+
+static void stmmac_init_ptp(struct stmmac_priv *priv)
+{
+ if (priv->dma_cap.time_stamp)
+ pr_debug("IEEE 1588-2002 Time Stamp supported\n");
+ if (priv->dma_cap.atime_stamp)
+ pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+
+ priv->hw->ptp = &stmmac_ptp;
+
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+}
+#else
+#define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
+#define stmmac_get_rx_hwtstamp(priv, p, skb)
+#define stmmac_get_tx_hwtstamp(priv, p, skb) 0
+#define stmmac_init_ptp(priv)
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+
/**
* stmmac_adjust_link
* @dev: net device structure
@@ -712,6 +902,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
while (priv->dirty_tx != priv->cur_tx) {
int last;
+ unsigned int ts = 0;
unsigned int entry = priv->dirty_tx % txsize;
struct sk_buff *skb = priv->tx_skbuff[entry];
struct dma_desc *p = priv->dma_tx + entry;
@@ -732,6 +923,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->xstats.tx_pkt_n++;
} else
priv->dev->stats.tx_errors++;
+
+ ts = stmmac_get_tx_hwtstamp(priv, p, skb);
}
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
@@ -743,7 +936,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = 0;
}
- priv->hw->ring->clean_desc3(p);
+ priv->hw->ring->clean_desc3(priv, p, ts);
if (likely(skb != NULL)) {
dev_kfree_skb(skb);
@@ -1027,6 +1220,7 @@ static int stmmac_open(struct net_device *dev)
goto open_error;
}
+
/* Create and initialize the TX/RX descriptors chains. */
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
@@ -1093,6 +1287,8 @@ static int stmmac_open(struct net_device *dev)
stmmac_mmc_setup(priv);
+ stmmac_init_ptp(priv);
+
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
if (ret < 0)
@@ -1325,7 +1521,17 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
- skb_tx_timestamp(skb);
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ /* declare that device is doing timestamping */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ priv->hw->desc->enable_tx_timestamp(first);
+ }
+
+ if (!priv->hwts_tx_en)
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+ skb_tx_timestamp(skb);
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
@@ -1357,8 +1563,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
(p + entry)->des2 = priv->rx_skbuff_dma[entry];
- if (unlikely(priv->plat->has_gmac))
- priv->hw->ring->refill_desc3(bfsize, p + entry);
+ priv->hw->ring->refill_desc3(priv, p + entry);
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
@@ -1398,9 +1603,22 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
/* read the status of the incoming frame */
status = (priv->hw->desc->rx_status(&priv->dev->stats,
&priv->xstats, p));
- if (unlikely(status == discard_frame))
+ if (unlikely(status == discard_frame)) {
priv->dev->stats.rx_errors++;
- else {
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ if (priv->hwts_rx_en) {
+ /* DESC2 & DESC3 will be overwitten by device
+ * with timestamp value, hence reinitialize
+ * them in stmmac_rx_refill() function so that
+ * device can reuse it.
+ */
+ priv->rx_skbuff[entry] = NULL;
+ dma_unmap_single(priv->device,
+ priv->rx_skbuff_dma[entry],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+ }
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+ } else {
struct sk_buff *skb;
int frame_len;
@@ -1429,6 +1647,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;
+ stmmac_get_rx_hwtstamp(priv, p, skb);
+
skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
@@ -1666,21 +1886,30 @@ static void stmmac_poll_controller(struct net_device *dev)
* a proprietary structure used to pass information to the driver.
* @cmd: IOCTL command
* Description:
- * Currently there are no special functionality supported in IOCTL, just the
- * phy_mii_ioctl(...) can be invoked.
+ * Currently it supports just the phy_mii_ioctl(...) and HW time stamping.
*/
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- int ret;
+ int ret = -EOPNOTSUPP;
if (!netif_running(dev))
return -EINVAL;
- if (!priv->phydev)
- return -EINVAL;
-
- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ return -EINVAL;
+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ break;
+ case SIOCSHWTSTAMP:
+ ret = stmmac_hwtstamp_ioctl(dev, rq);
+ break;
+ default:
+ break;
+ }
return ret;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
new file mode 100644
index 0000000..d557696
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ PTP Header file
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+******************************************************************************/
+
+#ifndef __STMMAC_PTP_H__
+#define __STMMAC_PTP_H__
+
+#define STMMAC_SYSCLOCK 62500000
+
+/* IEEE 1588 PTP register offsets */
+#define PTP_TCR 0x0700 /* Timestamp Control Reg */
+#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
+#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
+#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
+#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
+#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
+#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
+#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
+#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
+#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
+#define PTP_TSR 0x0728 /* Timestamp Status */
+
+/* PTP TCR defines */
+#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
+#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
+#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
+#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
+/* Timestamp Interrupt Trigger Enable */
+#define PTP_TCR_TSTRIG 0x00000010
+#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
+#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
+/* Timestamp Digital or Binary Rollover Control */
+#define PTP_TCR_TSCTRLSSR 0x00000200
+
+/* Enable PTP packet Processing for Version 2 Format */
+#define PTP_TCR_TSVER2ENA 0x00000400
+/* Enable Processing of PTP over Ethernet Frames */
+#define PTP_TCR_TSIPENA 0x00000800
+/* Enable Processing of PTP Frames Sent over IPv6-UDP */
+#define PTP_TCR_TSIPV6ENA 0x00001000
+/* Enable Processing of PTP Frames Sent over IPv4-UDP */
+#define PTP_TCR_TSIPV4ENA 0x00002000
+/* Enable Timestamp Snapshot for Event Messages */
+#define PTP_TCR_TSEVNTENA 0x00004000
+/* Enable Snapshot for Messages Relevant to Master */
+#define PTP_TCR_TSMSTRENA 0x00008000
+/* Select PTP packets for Taking Snapshots */
+#define PTP_TCR_SNAPTYPSEL_1 0x00010000
+/* Enable MAC address for PTP Frame Filtering */
+#define PTP_TCR_TSENMACADDR 0x00040000
+
+#endif /* __STMMAC_PTP_H__ */
--
1.7.4.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox