aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-03-13 04:38:27 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-13 04:38:27 -0400
commit99eee14a14ec8bf36c0705a038fa8d00917fb679 (patch)
tree2c18692aae9f239b5748e5e973d0d71815e5286b
parentc1ad32af5ec281bf30d2ca4fa20415bd2edef181 (diff)
parent11f2c988382b880e602a005c26436043c5d2c274 (diff)
Merge branch 'cpsw'
Mugunthan V N says: ==================== This patch serires implements the following features in CPSW driver * get/set phy link settings * interrupt pacing * get phy id via ioctl cmd SIOCGMIIPHY Changes from initial version * Made active-slave common for cpts, ethtool and SIOCGMIIPHY ioctl * Cleaned CPSW DT binding documentation by seperating slave nodes under sub-section * implemented get phy id via ioctl cmd SIOCGMIIPHY ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt16
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi2
-rw-r--r--drivers/net/ethernet/ti/cpsw.c159
-rw-r--r--include/linux/platform_data/cpsw.h2
4 files changed, 165 insertions, 14 deletions
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index ecfdf756d10f..4f2ca6b4a182 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -15,16 +15,22 @@ Required properties:
15- mac_control : Specifies Default MAC control register content 15- mac_control : Specifies Default MAC control register content
16 for the specific platform 16 for the specific platform
17- slaves : Specifies number for slaves 17- slaves : Specifies number for slaves
18- cpts_active_slave : Specifies the slave to use for time stamping 18- active_slave : Specifies the slave to use for time stamping,
19 ethtool and SIOCGMIIPHY
19- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds 20- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds
20- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds 21- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
21- phy_id : Specifies slave phy id
22- mac-address : Specifies slave MAC address
23 22
24Optional properties: 23Optional properties:
25- ti,hwmods : Must be "cpgmac0" 24- ti,hwmods : Must be "cpgmac0"
26- no_bd_ram : Must be 0 or 1 25- no_bd_ram : Must be 0 or 1
27- dual_emac : Specifies Switch to act as Dual EMAC 26- dual_emac : Specifies Switch to act as Dual EMAC
27
28Slave Properties:
29Required properties:
30- phy_id : Specifies slave phy id
31- mac-address : Specifies slave MAC address
32
33Optional properties:
28- dual_emac_res_vlan : Specifies VID to be used to segregate the ports 34- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
29 35
30Note: "ti,hwmods" field is used to fetch the base address and irq 36Note: "ti,hwmods" field is used to fetch the base address and irq
@@ -47,7 +53,7 @@ Examples:
47 rx_descs = <64>; 53 rx_descs = <64>;
48 mac_control = <0x20>; 54 mac_control = <0x20>;
49 slaves = <2>; 55 slaves = <2>;
50 cpts_active_slave = <0>; 56 active_slave = <0>;
51 cpts_clock_mult = <0x80000000>; 57 cpts_clock_mult = <0x80000000>;
52 cpts_clock_shift = <29>; 58 cpts_clock_shift = <29>;
53 cpsw_emac0: slave@0 { 59 cpsw_emac0: slave@0 {
@@ -73,7 +79,7 @@ Examples:
73 rx_descs = <64>; 79 rx_descs = <64>;
74 mac_control = <0x20>; 80 mac_control = <0x20>;
75 slaves = <2>; 81 slaves = <2>;
76 cpts_active_slave = <0>; 82 active_slave = <0>;
77 cpts_clock_mult = <0x80000000>; 83 cpts_clock_mult = <0x80000000>;
78 cpts_clock_shift = <29>; 84 cpts_clock_shift = <29>;
79 cpsw_emac0: slave@0 { 85 cpsw_emac0: slave@0 {
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 0957645b73af..91fe4f148f80 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -349,7 +349,7 @@
349 rx_descs = <64>; 349 rx_descs = <64>;
350 mac_control = <0x20>; 350 mac_control = <0x20>;
351 slaves = <2>; 351 slaves = <2>;
352 cpts_active_slave = <0>; 352 active_slave = <0>;
353 cpts_clock_mult = <0x80000000>; 353 cpts_clock_mult = <0x80000000>;
354 cpts_clock_shift = <29>; 354 cpts_clock_shift = <29>;
355 reg = <0x4a100000 0x800 355 reg = <0x4a100000 0x800
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 01ffbc486982..8ff1d3dde778 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -126,6 +126,13 @@ do { \
126#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15) 126#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
127#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15) 127#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
128 128
129#define CPSW_INTPACEEN (0x3f << 16)
130#define CPSW_INTPRESCALE_MASK (0x7FF << 0)
131#define CPSW_CMINTMAX_CNT 63
132#define CPSW_CMINTMIN_CNT 2
133#define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT)
134#define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1)
135
129#define cpsw_enable_irq(priv) \ 136#define cpsw_enable_irq(priv) \
130 do { \ 137 do { \
131 u32 i; \ 138 u32 i; \
@@ -139,6 +146,10 @@ do { \
139 disable_irq_nosync(priv->irqs_table[i]); \ 146 disable_irq_nosync(priv->irqs_table[i]); \
140 } while (0); 147 } while (0);
141 148
149#define cpsw_slave_index(priv) \
150 ((priv->data.dual_emac) ? priv->emac_port : \
151 priv->data.active_slave)
152
142static int debug_level; 153static int debug_level;
143module_param(debug_level, int, 0); 154module_param(debug_level, int, 0);
144MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)"); 155MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)");
@@ -160,6 +171,15 @@ struct cpsw_wr_regs {
160 u32 rx_en; 171 u32 rx_en;
161 u32 tx_en; 172 u32 tx_en;
162 u32 misc_en; 173 u32 misc_en;
174 u32 mem_allign1[8];
175 u32 rx_thresh_stat;
176 u32 rx_stat;
177 u32 tx_stat;
178 u32 misc_stat;
179 u32 mem_allign2[8];
180 u32 rx_imax;
181 u32 tx_imax;
182
163}; 183};
164 184
165struct cpsw_ss_regs { 185struct cpsw_ss_regs {
@@ -314,6 +334,8 @@ struct cpsw_priv {
314 struct cpsw_host_regs __iomem *host_port_regs; 334 struct cpsw_host_regs __iomem *host_port_regs;
315 u32 msg_enable; 335 u32 msg_enable;
316 u32 version; 336 u32 version;
337 u32 coal_intvl;
338 u32 bus_freq_mhz;
317 struct net_device_stats stats; 339 struct net_device_stats stats;
318 int rx_packet_max; 340 int rx_packet_max;
319 int host_port; 341 int host_port;
@@ -612,6 +634,77 @@ static void cpsw_adjust_link(struct net_device *ndev)
612 } 634 }
613} 635}
614 636
637static int cpsw_get_coalesce(struct net_device *ndev,
638 struct ethtool_coalesce *coal)
639{
640 struct cpsw_priv *priv = netdev_priv(ndev);
641
642 coal->rx_coalesce_usecs = priv->coal_intvl;
643 return 0;
644}
645
646static int cpsw_set_coalesce(struct net_device *ndev,
647 struct ethtool_coalesce *coal)
648{
649 struct cpsw_priv *priv = netdev_priv(ndev);
650 u32 int_ctrl;
651 u32 num_interrupts = 0;
652 u32 prescale = 0;
653 u32 addnl_dvdr = 1;
654 u32 coal_intvl = 0;
655
656 if (!coal->rx_coalesce_usecs)
657 return -EINVAL;
658
659 coal_intvl = coal->rx_coalesce_usecs;
660
661 int_ctrl = readl(&priv->wr_regs->int_control);
662 prescale = priv->bus_freq_mhz * 4;
663
664 if (coal_intvl < CPSW_CMINTMIN_INTVL)
665 coal_intvl = CPSW_CMINTMIN_INTVL;
666
667 if (coal_intvl > CPSW_CMINTMAX_INTVL) {
668 /* Interrupt pacer works with 4us Pulse, we can
669 * throttle further by dilating the 4us pulse.
670 */
671 addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale;
672
673 if (addnl_dvdr > 1) {
674 prescale *= addnl_dvdr;
675 if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr))
676 coal_intvl = (CPSW_CMINTMAX_INTVL
677 * addnl_dvdr);
678 } else {
679 addnl_dvdr = 1;
680 coal_intvl = CPSW_CMINTMAX_INTVL;
681 }
682 }
683
684 num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
685 writel(num_interrupts, &priv->wr_regs->rx_imax);
686 writel(num_interrupts, &priv->wr_regs->tx_imax);
687
688 int_ctrl |= CPSW_INTPACEEN;
689 int_ctrl &= (~CPSW_INTPRESCALE_MASK);
690 int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK);
691 writel(int_ctrl, &priv->wr_regs->int_control);
692
693 cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl);
694 if (priv->data.dual_emac) {
695 int i;
696
697 for (i = 0; i < priv->data.slaves; i++) {
698 priv = netdev_priv(priv->slaves[i].ndev);
699 priv->coal_intvl = coal_intvl;
700 }
701 } else {
702 priv->coal_intvl = coal_intvl;
703 }
704
705 return 0;
706}
707
615static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) 708static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
616{ 709{
617 static char *leader = "........................................"; 710 static char *leader = "........................................";
@@ -834,6 +927,14 @@ static int cpsw_ndo_open(struct net_device *ndev)
834 cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); 927 cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
835 } 928 }
836 929
930 /* Enable Interrupt pacing if configured */
931 if (priv->coal_intvl != 0) {
932 struct ethtool_coalesce coal;
933
934 coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
935 cpsw_set_coalesce(ndev, &coal);
936 }
937
837 cpdma_ctlr_start(priv->dma); 938 cpdma_ctlr_start(priv->dma);
838 cpsw_intr_enable(priv); 939 cpsw_intr_enable(priv);
839 napi_enable(&priv->napi); 940 napi_enable(&priv->napi);
@@ -942,7 +1043,7 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)
942 1043
943static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) 1044static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
944{ 1045{
945 struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave]; 1046 struct cpsw_slave *slave = &priv->slaves[priv->data.active_slave];
946 u32 ts_en, seq_id; 1047 u32 ts_en, seq_id;
947 1048
948 if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) { 1049 if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) {
@@ -971,7 +1072,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
971 if (priv->data.dual_emac) 1072 if (priv->data.dual_emac)
972 slave = &priv->slaves[priv->emac_port]; 1073 slave = &priv->slaves[priv->emac_port];
973 else 1074 else
974 slave = &priv->slaves[priv->data.cpts_active_slave]; 1075 slave = &priv->slaves[priv->data.active_slave];
975 1076
976 ctrl = slave_read(slave, CPSW2_CONTROL); 1077 ctrl = slave_read(slave, CPSW2_CONTROL);
977 ctrl &= ~CTRL_ALL_TS_MASK; 1078 ctrl &= ~CTRL_ALL_TS_MASK;
@@ -1056,14 +1157,26 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
1056 1157
1057static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) 1158static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
1058{ 1159{
1160 struct cpsw_priv *priv = netdev_priv(dev);
1161 struct mii_ioctl_data *data = if_mii(req);
1162 int slave_no = cpsw_slave_index(priv);
1163
1059 if (!netif_running(dev)) 1164 if (!netif_running(dev))
1060 return -EINVAL; 1165 return -EINVAL;
1061 1166
1167 switch (cmd) {
1062#ifdef CONFIG_TI_CPTS 1168#ifdef CONFIG_TI_CPTS
1063 if (cmd == SIOCSHWTSTAMP) 1169 case SIOCSHWTSTAMP:
1064 return cpsw_hwtstamp_ioctl(dev, req); 1170 return cpsw_hwtstamp_ioctl(dev, req);
1065#endif 1171#endif
1066 return -ENOTSUPP; 1172 case SIOCGMIIPHY:
1173 data->phy_id = priv->slaves[slave_no].phy->addr;
1174 break;
1175 default:
1176 return -ENOTSUPP;
1177 }
1178
1179 return 0;
1067} 1180}
1068 1181
1069static void cpsw_ndo_tx_timeout(struct net_device *ndev) 1182static void cpsw_ndo_tx_timeout(struct net_device *ndev)
@@ -1244,12 +1357,39 @@ static int cpsw_get_ts_info(struct net_device *ndev,
1244 return 0; 1357 return 0;
1245} 1358}
1246 1359
1360static int cpsw_get_settings(struct net_device *ndev,
1361 struct ethtool_cmd *ecmd)
1362{
1363 struct cpsw_priv *priv = netdev_priv(ndev);
1364 int slave_no = cpsw_slave_index(priv);
1365
1366 if (priv->slaves[slave_no].phy)
1367 return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd);
1368 else
1369 return -EOPNOTSUPP;
1370}
1371
1372static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
1373{
1374 struct cpsw_priv *priv = netdev_priv(ndev);
1375 int slave_no = cpsw_slave_index(priv);
1376
1377 if (priv->slaves[slave_no].phy)
1378 return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd);
1379 else
1380 return -EOPNOTSUPP;
1381}
1382
1247static const struct ethtool_ops cpsw_ethtool_ops = { 1383static const struct ethtool_ops cpsw_ethtool_ops = {
1248 .get_drvinfo = cpsw_get_drvinfo, 1384 .get_drvinfo = cpsw_get_drvinfo,
1249 .get_msglevel = cpsw_get_msglevel, 1385 .get_msglevel = cpsw_get_msglevel,
1250 .set_msglevel = cpsw_set_msglevel, 1386 .set_msglevel = cpsw_set_msglevel,
1251 .get_link = ethtool_op_get_link, 1387 .get_link = ethtool_op_get_link,
1252 .get_ts_info = cpsw_get_ts_info, 1388 .get_ts_info = cpsw_get_ts_info,
1389 .get_settings = cpsw_get_settings,
1390 .set_settings = cpsw_set_settings,
1391 .get_coalesce = cpsw_get_coalesce,
1392 .set_coalesce = cpsw_set_coalesce,
1253}; 1393};
1254 1394
1255static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, 1395static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1282,12 +1422,12 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
1282 } 1422 }
1283 data->slaves = prop; 1423 data->slaves = prop;
1284 1424
1285 if (of_property_read_u32(node, "cpts_active_slave", &prop)) { 1425 if (of_property_read_u32(node, "active_slave", &prop)) {
1286 pr_err("Missing cpts_active_slave property in the DT.\n"); 1426 pr_err("Missing active_slave property in the DT.\n");
1287 ret = -EINVAL; 1427 ret = -EINVAL;
1288 goto error_ret; 1428 goto error_ret;
1289 } 1429 }
1290 data->cpts_active_slave = prop; 1430 data->active_slave = prop;
1291 1431
1292 if (of_property_read_u32(node, "cpts_clock_mult", &prop)) { 1432 if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {
1293 pr_err("Missing cpts_clock_mult property in the DT.\n"); 1433 pr_err("Missing cpts_clock_mult property in the DT.\n");
@@ -1437,6 +1577,9 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
1437 priv_sl2->slaves = priv->slaves; 1577 priv_sl2->slaves = priv->slaves;
1438 priv_sl2->clk = priv->clk; 1578 priv_sl2->clk = priv->clk;
1439 1579
1580 priv_sl2->coal_intvl = 0;
1581 priv_sl2->bus_freq_mhz = priv->bus_freq_mhz;
1582
1440 priv_sl2->cpsw_res = priv->cpsw_res; 1583 priv_sl2->cpsw_res = priv->cpsw_res;
1441 priv_sl2->regs = priv->regs; 1584 priv_sl2->regs = priv->regs;
1442 priv_sl2->host_port = priv->host_port; 1585 priv_sl2->host_port = priv->host_port;
@@ -1546,6 +1689,8 @@ static int cpsw_probe(struct platform_device *pdev)
1546 ret = -ENODEV; 1689 ret = -ENODEV;
1547 goto clean_slave_ret; 1690 goto clean_slave_ret;
1548 } 1691 }
1692 priv->coal_intvl = 0;
1693 priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000;
1549 1694
1550 priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1695 priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1551 if (!priv->cpsw_res) { 1696 if (!priv->cpsw_res) {
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 798fb80b024b..bb3cd58d71e3 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -30,7 +30,7 @@ struct cpsw_platform_data {
30 u32 channels; /* number of cpdma channels (symmetric) */ 30 u32 channels; /* number of cpdma channels (symmetric) */
31 u32 slaves; /* number of slave cpgmac ports */ 31 u32 slaves; /* number of slave cpgmac ports */
32 struct cpsw_slave_data *slave_data; 32 struct cpsw_slave_data *slave_data;
33 u32 cpts_active_slave; /* time stamping slave */ 33 u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */
34 u32 cpts_clock_mult; /* convert input clock ticks to nanoseconds */ 34 u32 cpts_clock_mult; /* convert input clock ticks to nanoseconds */
35 u32 cpts_clock_shift; /* convert input clock ticks to nanoseconds */ 35 u32 cpts_clock_shift; /* convert input clock ticks to nanoseconds */
36 u32 ale_entries; /* ale table size */ 36 u32 ale_entries; /* ale table size */