aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/ti/cpsw.c
diff options
context:
space:
mode:
authorRichard Cochran <richardcochran@gmail.com>2012-10-29 04:45:20 -0400
committerDavid S. Miller <davem@davemloft.net>2012-11-01 12:21:32 -0400
commit2e5b38abcfad3049608a051826a5aaec2122cdac (patch)
tree63ae6352df958a7e7c74b003e577949a7cafedae /drivers/net/ethernet/ti/cpsw.c
parent00ab94eeaf6c1ad38ad7368c5148fed31403c8a2 (diff)
cpsw: support the HWTSTAMP ioctl and the CPTS
This patch hooks into the CPTS code and adds support for the HWTSTAMP ioctl. The patch includes code for the CPSW version found in the dm814x even though the background device tree support for this board is still missing. Signed-off-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw.c')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index c04627cd60dd..023d439ef10f 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -24,6 +24,7 @@
24#include <linux/if_ether.h> 24#include <linux/if_ether.h>
25#include <linux/etherdevice.h> 25#include <linux/etherdevice.h>
26#include <linux/netdevice.h> 26#include <linux/netdevice.h>
27#include <linux/net_tstamp.h>
27#include <linux/phy.h> 28#include <linux/phy.h>
28#include <linux/workqueue.h> 29#include <linux/workqueue.h>
29#include <linux/delay.h> 30#include <linux/delay.h>
@@ -35,6 +36,7 @@
35#include <linux/platform_data/cpsw.h> 36#include <linux/platform_data/cpsw.h>
36 37
37#include "cpsw_ale.h" 38#include "cpsw_ale.h"
39#include "cpts.h"
38#include "davinci_cpdma.h" 40#include "davinci_cpdma.h"
39 41
40#define CPSW_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \ 42#define CPSW_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \
@@ -229,6 +231,14 @@ struct cpsw_ss_regs {
229/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */ 231/* The PTP event messages - Sync, Delay_Req, Pdelay_Req, and Pdelay_Resp. */
230#define EVENT_MSG_BITS ((1<<0) | (1<<1) | (1<<2) | (1<<3)) 232#define EVENT_MSG_BITS ((1<<0) | (1<<1) | (1<<2) | (1<<3))
231 233
234/* Bit definitions for the CPSW1_TS_CTL register */
235#define CPSW_V1_TS_RX_EN BIT(0)
236#define CPSW_V1_TS_TX_EN BIT(4)
237#define CPSW_V1_MSG_TYPE_OFS 16
238
239/* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */
240#define CPSW_V1_SEQ_ID_OFS_SHIFT 16
241
232struct cpsw_host_regs { 242struct cpsw_host_regs {
233 u32 max_blks; 243 u32 max_blks;
234 u32 blk_cnt; 244 u32 blk_cnt;
@@ -297,6 +307,7 @@ struct cpsw_priv {
297 /* snapshot of IRQ numbers */ 307 /* snapshot of IRQ numbers */
298 u32 irqs_table[4]; 308 u32 irqs_table[4];
299 u32 num_irqs; 309 u32 num_irqs;
310 struct cpts cpts;
300}; 311};
301 312
302#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) 313#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
@@ -357,6 +368,7 @@ void cpsw_tx_handler(void *token, int len, int status)
357 368
358 if (unlikely(netif_queue_stopped(ndev))) 369 if (unlikely(netif_queue_stopped(ndev)))
359 netif_start_queue(ndev); 370 netif_start_queue(ndev);
371 cpts_tx_timestamp(&priv->cpts, skb);
360 priv->stats.tx_packets++; 372 priv->stats.tx_packets++;
361 priv->stats.tx_bytes += len; 373 priv->stats.tx_bytes += len;
362 dev_kfree_skb_any(skb); 374 dev_kfree_skb_any(skb);
@@ -377,6 +389,7 @@ void cpsw_rx_handler(void *token, int len, int status)
377 } 389 }
378 if (likely(status >= 0)) { 390 if (likely(status >= 0)) {
379 skb_put(skb, len); 391 skb_put(skb, len);
392 cpts_rx_timestamp(&priv->cpts, skb);
380 skb->protocol = eth_type_trans(skb, ndev); 393 skb->protocol = eth_type_trans(skb, ndev);
381 netif_receive_skb(skb); 394 netif_receive_skb(skb);
382 priv->stats.rx_bytes += len; 395 priv->stats.rx_bytes += len;
@@ -704,6 +717,11 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
704 return NETDEV_TX_OK; 717 return NETDEV_TX_OK;
705 } 718 }
706 719
720 if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && priv->cpts.tx_enable)
721 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
722
723 skb_tx_timestamp(skb);
724
707 ret = cpdma_chan_submit(priv->txch, skb, skb->data, 725 ret = cpdma_chan_submit(priv->txch, skb, skb->data,
708 skb->len, GFP_KERNEL); 726 skb->len, GFP_KERNEL);
709 if (unlikely(ret != 0)) { 727 if (unlikely(ret != 0)) {
@@ -741,6 +759,130 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)
741 dev_err(&ndev->dev, "multicast traffic cannot be filtered!\n"); 759 dev_err(&ndev->dev, "multicast traffic cannot be filtered!\n");
742} 760}
743 761
762#ifdef CONFIG_TI_CPTS
763
764static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
765{
766 struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
767 u32 ts_en, seq_id;
768
769 if (!priv->cpts.tx_enable && !priv->cpts.rx_enable) {
770 slave_write(slave, 0, CPSW1_TS_CTL);
771 return;
772 }
773
774 seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588;
775 ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS;
776
777 if (priv->cpts.tx_enable)
778 ts_en |= CPSW_V1_TS_TX_EN;
779
780 if (priv->cpts.rx_enable)
781 ts_en |= CPSW_V1_TS_RX_EN;
782
783 slave_write(slave, ts_en, CPSW1_TS_CTL);
784 slave_write(slave, seq_id, CPSW1_TS_SEQ_LTYPE);
785}
786
787static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
788{
789 struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
790 u32 ctrl, mtype;
791
792 ctrl = slave_read(slave, CPSW2_CONTROL);
793 ctrl &= ~CTRL_ALL_TS_MASK;
794
795 if (priv->cpts.tx_enable)
796 ctrl |= CTRL_TX_TS_BITS;
797
798 if (priv->cpts.rx_enable)
799 ctrl |= CTRL_RX_TS_BITS;
800
801 mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS;
802
803 slave_write(slave, mtype, CPSW2_TS_SEQ_MTYPE);
804 slave_write(slave, ctrl, CPSW2_CONTROL);
805 __raw_writel(ETH_P_1588, &priv->regs->ts_ltype);
806}
807
808static int cpsw_hwtstamp_ioctl(struct cpsw_priv *priv, struct ifreq *ifr)
809{
810 struct cpts *cpts = &priv->cpts;
811 struct hwtstamp_config cfg;
812
813 if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
814 return -EFAULT;
815
816 /* reserved for future extensions */
817 if (cfg.flags)
818 return -EINVAL;
819
820 switch (cfg.tx_type) {
821 case HWTSTAMP_TX_OFF:
822 cpts->tx_enable = 0;
823 break;
824 case HWTSTAMP_TX_ON:
825 cpts->tx_enable = 1;
826 break;
827 default:
828 return -ERANGE;
829 }
830
831 switch (cfg.rx_filter) {
832 case HWTSTAMP_FILTER_NONE:
833 cpts->rx_enable = 0;
834 break;
835 case HWTSTAMP_FILTER_ALL:
836 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
837 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
838 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
839 return -ERANGE;
840 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
841 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
842 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
843 case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
844 case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
845 case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
846 case HWTSTAMP_FILTER_PTP_V2_EVENT:
847 case HWTSTAMP_FILTER_PTP_V2_SYNC:
848 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
849 cpts->rx_enable = 1;
850 cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
851 break;
852 default:
853 return -ERANGE;
854 }
855
856 switch (priv->version) {
857 case CPSW_VERSION_1:
858 cpsw_hwtstamp_v1(priv);
859 break;
860 case CPSW_VERSION_2:
861 cpsw_hwtstamp_v2(priv);
862 break;
863 default:
864 return -ENOTSUPP;
865 }
866
867 return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
868}
869
870#endif /*CONFIG_TI_CPTS*/
871
872static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
873{
874 struct cpsw_priv *priv = netdev_priv(dev);
875
876 if (!netif_running(dev))
877 return -EINVAL;
878
879#ifdef CONFIG_TI_CPTS
880 if (cmd == SIOCSHWTSTAMP)
881 return cpsw_hwtstamp_ioctl(priv, req);
882#endif
883 return -ENOTSUPP;
884}
885
744static void cpsw_ndo_tx_timeout(struct net_device *ndev) 886static void cpsw_ndo_tx_timeout(struct net_device *ndev)
745{ 887{
746 struct cpsw_priv *priv = netdev_priv(ndev); 888 struct cpsw_priv *priv = netdev_priv(ndev);
@@ -781,6 +923,7 @@ static const struct net_device_ops cpsw_netdev_ops = {
781 .ndo_stop = cpsw_ndo_stop, 923 .ndo_stop = cpsw_ndo_stop,
782 .ndo_start_xmit = cpsw_ndo_start_xmit, 924 .ndo_start_xmit = cpsw_ndo_start_xmit,
783 .ndo_change_rx_flags = cpsw_ndo_change_rx_flags, 925 .ndo_change_rx_flags = cpsw_ndo_change_rx_flags,
926 .ndo_do_ioctl = cpsw_ndo_ioctl,
784 .ndo_validate_addr = eth_validate_addr, 927 .ndo_validate_addr = eth_validate_addr,
785 .ndo_change_mtu = eth_change_mtu, 928 .ndo_change_mtu = eth_change_mtu,
786 .ndo_tx_timeout = cpsw_ndo_tx_timeout, 929 .ndo_tx_timeout = cpsw_ndo_tx_timeout,
@@ -812,11 +955,44 @@ static void cpsw_set_msglevel(struct net_device *ndev, u32 value)
812 priv->msg_enable = value; 955 priv->msg_enable = value;
813} 956}
814 957
958static int cpsw_get_ts_info(struct net_device *ndev,
959 struct ethtool_ts_info *info)
960{
961#ifdef CONFIG_TI_CPTS
962 struct cpsw_priv *priv = netdev_priv(ndev);
963
964 info->so_timestamping =
965 SOF_TIMESTAMPING_TX_HARDWARE |
966 SOF_TIMESTAMPING_TX_SOFTWARE |
967 SOF_TIMESTAMPING_RX_HARDWARE |
968 SOF_TIMESTAMPING_RX_SOFTWARE |
969 SOF_TIMESTAMPING_SOFTWARE |
970 SOF_TIMESTAMPING_RAW_HARDWARE;
971 info->phc_index = priv->cpts.phc_index;
972 info->tx_types =
973 (1 << HWTSTAMP_TX_OFF) |
974 (1 << HWTSTAMP_TX_ON);
975 info->rx_filters =
976 (1 << HWTSTAMP_FILTER_NONE) |
977 (1 << HWTSTAMP_FILTER_PTP_V2_EVENT);
978#else
979 info->so_timestamping =
980 SOF_TIMESTAMPING_TX_SOFTWARE |
981 SOF_TIMESTAMPING_RX_SOFTWARE |
982 SOF_TIMESTAMPING_SOFTWARE;
983 info->phc_index = -1;
984 info->tx_types = 0;
985 info->rx_filters = 0;
986#endif
987 return 0;
988}
989
815static const struct ethtool_ops cpsw_ethtool_ops = { 990static const struct ethtool_ops cpsw_ethtool_ops = {
816 .get_drvinfo = cpsw_get_drvinfo, 991 .get_drvinfo = cpsw_get_drvinfo,
817 .get_msglevel = cpsw_get_msglevel, 992 .get_msglevel = cpsw_get_msglevel,
818 .set_msglevel = cpsw_set_msglevel, 993 .set_msglevel = cpsw_set_msglevel,
819 .get_link = ethtool_op_get_link, 994 .get_link = ethtool_op_get_link,
995 .get_ts_info = cpsw_get_ts_info,
820}; 996};
821 997
822static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) 998static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
@@ -1092,6 +1268,7 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
1092 priv->regs = regs; 1268 priv->regs = regs;
1093 priv->host_port = data->host_port_num; 1269 priv->host_port = data->host_port_num;
1094 priv->host_port_regs = regs + data->host_port_reg_ofs; 1270 priv->host_port_regs = regs + data->host_port_reg_ofs;
1271 priv->cpts.reg = regs + data->cpts_reg_ofs;
1095 1272
1096 priv->cpsw_ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1273 priv->cpsw_ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1097 if (!priv->cpsw_ss_res) { 1274 if (!priv->cpsw_ss_res) {
@@ -1213,6 +1390,10 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
1213 goto clean_irq_ret; 1390 goto clean_irq_ret;
1214 } 1391 }
1215 1392
1393 if (cpts_register(&pdev->dev, &priv->cpts,
1394 data->cpts_clock_mult, data->cpts_clock_shift))
1395 dev_err(priv->dev, "error registering cpts device\n");
1396
1216 cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", 1397 cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n",
1217 priv->cpsw_res->start, ndev->irq); 1398 priv->cpsw_res->start, ndev->irq);
1218 1399
@@ -1252,6 +1433,7 @@ static int __devexit cpsw_remove(struct platform_device *pdev)
1252 pr_info("removing device"); 1433 pr_info("removing device");
1253 platform_set_drvdata(pdev, NULL); 1434 platform_set_drvdata(pdev, NULL);
1254 1435
1436 cpts_unregister(&priv->cpts);
1255 free_irq(ndev->irq, priv); 1437 free_irq(ndev->irq, priv);
1256 cpsw_ale_destroy(priv->ale); 1438 cpsw_ale_destroy(priv->ale);
1257 cpdma_chan_destroy(priv->txch); 1439 cpdma_chan_destroy(priv->txch);