diff options
Diffstat (limited to 'drivers/net/ethernet/ti/cpsw.c')
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 162 |
1 files changed, 129 insertions, 33 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 5330fd298705..ffd4d12acf6d 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -541,14 +541,93 @@ static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) | |||
541 | return slave_num; | 541 | return slave_num; |
542 | } | 542 | } |
543 | 543 | ||
544 | static void cpsw_set_promiscious(struct net_device *ndev, bool enable) | ||
545 | { | ||
546 | struct cpsw_priv *priv = netdev_priv(ndev); | ||
547 | struct cpsw_ale *ale = priv->ale; | ||
548 | int i; | ||
549 | |||
550 | if (priv->data.dual_emac) { | ||
551 | bool flag = false; | ||
552 | |||
553 | /* Enabling promiscuous mode for one interface will be | ||
554 | * common for both the interface as the interface shares | ||
555 | * the same hardware resource. | ||
556 | */ | ||
557 | for (i = 0; i < priv->data.slaves; i++) | ||
558 | if (priv->slaves[i].ndev->flags & IFF_PROMISC) | ||
559 | flag = true; | ||
560 | |||
561 | if (!enable && flag) { | ||
562 | enable = true; | ||
563 | dev_err(&ndev->dev, "promiscuity not disabled as the other interface is still in promiscuity mode\n"); | ||
564 | } | ||
565 | |||
566 | if (enable) { | ||
567 | /* Enable Bypass */ | ||
568 | cpsw_ale_control_set(ale, 0, ALE_BYPASS, 1); | ||
569 | |||
570 | dev_dbg(&ndev->dev, "promiscuity enabled\n"); | ||
571 | } else { | ||
572 | /* Disable Bypass */ | ||
573 | cpsw_ale_control_set(ale, 0, ALE_BYPASS, 0); | ||
574 | dev_dbg(&ndev->dev, "promiscuity disabled\n"); | ||
575 | } | ||
576 | } else { | ||
577 | if (enable) { | ||
578 | unsigned long timeout = jiffies + HZ; | ||
579 | |||
580 | /* Disable Learn for all ports */ | ||
581 | for (i = 0; i < priv->data.slaves; i++) { | ||
582 | cpsw_ale_control_set(ale, i, | ||
583 | ALE_PORT_NOLEARN, 1); | ||
584 | cpsw_ale_control_set(ale, i, | ||
585 | ALE_PORT_NO_SA_UPDATE, 1); | ||
586 | } | ||
587 | |||
588 | /* Clear All Untouched entries */ | ||
589 | cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); | ||
590 | do { | ||
591 | cpu_relax(); | ||
592 | if (cpsw_ale_control_get(ale, 0, ALE_AGEOUT)) | ||
593 | break; | ||
594 | } while (time_after(timeout, jiffies)); | ||
595 | cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1); | ||
596 | |||
597 | /* Clear all mcast from ALE */ | ||
598 | cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS << | ||
599 | priv->host_port); | ||
600 | |||
601 | /* Flood All Unicast Packets to Host port */ | ||
602 | cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1); | ||
603 | dev_dbg(&ndev->dev, "promiscuity enabled\n"); | ||
604 | } else { | ||
605 | /* Flood All Unicast Packets to Host port */ | ||
606 | cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0); | ||
607 | |||
608 | /* Enable Learn for all ports */ | ||
609 | for (i = 0; i < priv->data.slaves; i++) { | ||
610 | cpsw_ale_control_set(ale, i, | ||
611 | ALE_PORT_NOLEARN, 0); | ||
612 | cpsw_ale_control_set(ale, i, | ||
613 | ALE_PORT_NO_SA_UPDATE, 0); | ||
614 | } | ||
615 | dev_dbg(&ndev->dev, "promiscuity disabled\n"); | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | |||
544 | static void cpsw_ndo_set_rx_mode(struct net_device *ndev) | 620 | static void cpsw_ndo_set_rx_mode(struct net_device *ndev) |
545 | { | 621 | { |
546 | struct cpsw_priv *priv = netdev_priv(ndev); | 622 | struct cpsw_priv *priv = netdev_priv(ndev); |
547 | 623 | ||
548 | if (ndev->flags & IFF_PROMISC) { | 624 | if (ndev->flags & IFF_PROMISC) { |
549 | /* Enable promiscuous mode */ | 625 | /* Enable promiscuous mode */ |
550 | dev_err(priv->dev, "Ignoring Promiscuous mode\n"); | 626 | cpsw_set_promiscious(ndev, true); |
551 | return; | 627 | return; |
628 | } else { | ||
629 | /* Disable promiscuous mode */ | ||
630 | cpsw_set_promiscious(ndev, false); | ||
552 | } | 631 | } |
553 | 632 | ||
554 | /* Clear all mcast from ALE */ | 633 | /* Clear all mcast from ALE */ |
@@ -582,7 +661,7 @@ static void cpsw_intr_disable(struct cpsw_priv *priv) | |||
582 | return; | 661 | return; |
583 | } | 662 | } |
584 | 663 | ||
585 | void cpsw_tx_handler(void *token, int len, int status) | 664 | static void cpsw_tx_handler(void *token, int len, int status) |
586 | { | 665 | { |
587 | struct sk_buff *skb = token; | 666 | struct sk_buff *skb = token; |
588 | struct net_device *ndev = skb->dev; | 667 | struct net_device *ndev = skb->dev; |
@@ -599,7 +678,7 @@ void cpsw_tx_handler(void *token, int len, int status) | |||
599 | dev_kfree_skb_any(skb); | 678 | dev_kfree_skb_any(skb); |
600 | } | 679 | } |
601 | 680 | ||
602 | void cpsw_rx_handler(void *token, int len, int status) | 681 | static void cpsw_rx_handler(void *token, int len, int status) |
603 | { | 682 | { |
604 | struct sk_buff *skb = token; | 683 | struct sk_buff *skb = token; |
605 | struct sk_buff *new_skb; | 684 | struct sk_buff *new_skb; |
@@ -1085,11 +1164,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) | |||
1085 | 1164 | ||
1086 | static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) | 1165 | static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) |
1087 | { | 1166 | { |
1167 | u32 slave_port; | ||
1168 | |||
1169 | slave_port = cpsw_get_slave_port(priv, slave->slave_num); | ||
1170 | |||
1088 | if (!slave->phy) | 1171 | if (!slave->phy) |
1089 | return; | 1172 | return; |
1090 | phy_stop(slave->phy); | 1173 | phy_stop(slave->phy); |
1091 | phy_disconnect(slave->phy); | 1174 | phy_disconnect(slave->phy); |
1092 | slave->phy = NULL; | 1175 | slave->phy = NULL; |
1176 | cpsw_ale_control_set(priv->ale, slave_port, | ||
1177 | ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); | ||
1093 | } | 1178 | } |
1094 | 1179 | ||
1095 | static int cpsw_ndo_open(struct net_device *ndev) | 1180 | static int cpsw_ndo_open(struct net_device *ndev) |
@@ -1257,29 +1342,6 @@ fail: | |||
1257 | return NETDEV_TX_BUSY; | 1342 | return NETDEV_TX_BUSY; |
1258 | } | 1343 | } |
1259 | 1344 | ||
1260 | static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags) | ||
1261 | { | ||
1262 | /* | ||
1263 | * The switch cannot operate in promiscuous mode without substantial | ||
1264 | * headache. For promiscuous mode to work, we would need to put the | ||
1265 | * ALE in bypass mode and route all traffic to the host port. | ||
1266 | * Subsequently, the host will need to operate as a "bridge", learn, | ||
1267 | * and flood as needed. For now, we simply complain here and | ||
1268 | * do nothing about it :-) | ||
1269 | */ | ||
1270 | if ((flags & IFF_PROMISC) && (ndev->flags & IFF_PROMISC)) | ||
1271 | dev_err(&ndev->dev, "promiscuity ignored!\n"); | ||
1272 | |||
1273 | /* | ||
1274 | * The switch cannot filter multicast traffic unless it is configured | ||
1275 | * in "VLAN Aware" mode. Unfortunately, VLAN awareness requires a | ||
1276 | * whole bunch of additional logic that this driver does not implement | ||
1277 | * at present. | ||
1278 | */ | ||
1279 | if ((flags & IFF_ALLMULTI) && !(ndev->flags & IFF_ALLMULTI)) | ||
1280 | dev_err(&ndev->dev, "multicast traffic cannot be filtered!\n"); | ||
1281 | } | ||
1282 | |||
1283 | #ifdef CONFIG_TI_CPTS | 1345 | #ifdef CONFIG_TI_CPTS |
1284 | 1346 | ||
1285 | static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) | 1347 | static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) |
@@ -1331,7 +1393,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) | |||
1331 | __raw_writel(ETH_P_1588, &priv->regs->ts_ltype); | 1393 | __raw_writel(ETH_P_1588, &priv->regs->ts_ltype); |
1332 | } | 1394 | } |
1333 | 1395 | ||
1334 | static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) | 1396 | static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) |
1335 | { | 1397 | { |
1336 | struct cpsw_priv *priv = netdev_priv(dev); | 1398 | struct cpsw_priv *priv = netdev_priv(dev); |
1337 | struct cpts *cpts = priv->cpts; | 1399 | struct cpts *cpts = priv->cpts; |
@@ -1392,6 +1454,24 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) | |||
1392 | return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; | 1454 | return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; |
1393 | } | 1455 | } |
1394 | 1456 | ||
1457 | static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) | ||
1458 | { | ||
1459 | struct cpsw_priv *priv = netdev_priv(dev); | ||
1460 | struct cpts *cpts = priv->cpts; | ||
1461 | struct hwtstamp_config cfg; | ||
1462 | |||
1463 | if (priv->version != CPSW_VERSION_1 && | ||
1464 | priv->version != CPSW_VERSION_2) | ||
1465 | return -EOPNOTSUPP; | ||
1466 | |||
1467 | cfg.flags = 0; | ||
1468 | cfg.tx_type = cpts->tx_enable ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; | ||
1469 | cfg.rx_filter = (cpts->rx_enable ? | ||
1470 | HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE); | ||
1471 | |||
1472 | return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; | ||
1473 | } | ||
1474 | |||
1395 | #endif /*CONFIG_TI_CPTS*/ | 1475 | #endif /*CONFIG_TI_CPTS*/ |
1396 | 1476 | ||
1397 | static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) | 1477 | static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) |
@@ -1406,7 +1486,9 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) | |||
1406 | switch (cmd) { | 1486 | switch (cmd) { |
1407 | #ifdef CONFIG_TI_CPTS | 1487 | #ifdef CONFIG_TI_CPTS |
1408 | case SIOCSHWTSTAMP: | 1488 | case SIOCSHWTSTAMP: |
1409 | return cpsw_hwtstamp_ioctl(dev, req); | 1489 | return cpsw_hwtstamp_set(dev, req); |
1490 | case SIOCGHWTSTAMP: | ||
1491 | return cpsw_hwtstamp_get(dev, req); | ||
1410 | #endif | 1492 | #endif |
1411 | case SIOCGMIIPHY: | 1493 | case SIOCGMIIPHY: |
1412 | data->phy_id = priv->slaves[slave_no].phy->addr; | 1494 | data->phy_id = priv->slaves[slave_no].phy->addr; |
@@ -1555,7 +1637,6 @@ static const struct net_device_ops cpsw_netdev_ops = { | |||
1555 | .ndo_open = cpsw_ndo_open, | 1637 | .ndo_open = cpsw_ndo_open, |
1556 | .ndo_stop = cpsw_ndo_stop, | 1638 | .ndo_stop = cpsw_ndo_stop, |
1557 | .ndo_start_xmit = cpsw_ndo_start_xmit, | 1639 | .ndo_start_xmit = cpsw_ndo_start_xmit, |
1558 | .ndo_change_rx_flags = cpsw_ndo_change_rx_flags, | ||
1559 | .ndo_set_mac_address = cpsw_ndo_set_mac_address, | 1640 | .ndo_set_mac_address = cpsw_ndo_set_mac_address, |
1560 | .ndo_do_ioctl = cpsw_ndo_ioctl, | 1641 | .ndo_do_ioctl = cpsw_ndo_ioctl, |
1561 | .ndo_validate_addr = eth_validate_addr, | 1642 | .ndo_validate_addr = eth_validate_addr, |
@@ -1803,14 +1884,29 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, | |||
1803 | mdio_node = of_find_node_by_phandle(be32_to_cpup(parp)); | 1884 | mdio_node = of_find_node_by_phandle(be32_to_cpup(parp)); |
1804 | phyid = be32_to_cpup(parp+1); | 1885 | phyid = be32_to_cpup(parp+1); |
1805 | mdio = of_find_device_by_node(mdio_node); | 1886 | mdio = of_find_device_by_node(mdio_node); |
1806 | snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), | 1887 | |
1807 | PHY_ID_FMT, mdio->name, phyid); | 1888 | if (strncmp(mdio->name, "gpio", 4) == 0) { |
1889 | /* GPIO bitbang MDIO driver attached */ | ||
1890 | struct mii_bus *bus = dev_get_drvdata(&mdio->dev); | ||
1891 | |||
1892 | snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), | ||
1893 | PHY_ID_FMT, bus->id, phyid); | ||
1894 | } else { | ||
1895 | /* davinci MDIO driver attached */ | ||
1896 | snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), | ||
1897 | PHY_ID_FMT, mdio->name, phyid); | ||
1898 | } | ||
1808 | 1899 | ||
1809 | mac_addr = of_get_mac_address(slave_node); | 1900 | mac_addr = of_get_mac_address(slave_node); |
1810 | if (mac_addr) | 1901 | if (mac_addr) |
1811 | memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); | 1902 | memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); |
1812 | 1903 | ||
1813 | slave_data->phy_if = of_get_phy_mode(slave_node); | 1904 | slave_data->phy_if = of_get_phy_mode(slave_node); |
1905 | if (slave_data->phy_if < 0) { | ||
1906 | pr_err("Missing or malformed slave[%d] phy-mode property\n", | ||
1907 | i); | ||
1908 | return slave_data->phy_if; | ||
1909 | } | ||
1814 | 1910 | ||
1815 | if (data->dual_emac) { | 1911 | if (data->dual_emac) { |
1816 | if (of_property_read_u32(slave_node, "dual_emac_res_vlan", | 1912 | if (of_property_read_u32(slave_node, "dual_emac_res_vlan", |
@@ -2137,8 +2233,8 @@ static int cpsw_probe(struct platform_device *pdev) | |||
2137 | data->cpts_clock_mult, data->cpts_clock_shift)) | 2233 | data->cpts_clock_mult, data->cpts_clock_shift)) |
2138 | dev_err(priv->dev, "error registering cpts device\n"); | 2234 | dev_err(priv->dev, "error registering cpts device\n"); |
2139 | 2235 | ||
2140 | cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", | 2236 | cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n", |
2141 | ss_res->start, ndev->irq); | 2237 | &ss_res->start, ndev->irq); |
2142 | 2238 | ||
2143 | if (priv->data.dual_emac) { | 2239 | if (priv->data.dual_emac) { |
2144 | ret = cpsw_probe_dual_emac(pdev, priv); | 2240 | ret = cpsw_probe_dual_emac(pdev, priv); |