Enable promiscuous mode support for CPSW.
Signed-off-by: Mugunthan V N mugunthan...@ti.com
---
drivers/net/ethernet/ti/cpsw.c | 101 -
drivers/net/ethernet/ti/cpsw_ale.c | 16 ++
drivers/net/ethernet/ti/cpsw_ale.h | 2 +
3 files changed, 94 insertions(+), 25 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index e8bb77d..21bbdcb 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -541,14 +541,89 @@ static inline int cpsw_get_slave_port(struct cpsw_priv
*priv, u32 slave_num)
return slave_num;
}
+static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ struct cpsw_ale *ale = priv-ale;
+
+ if (priv-data.dual_emac) {
+ /* Enabling promiscuous mode for one interface will be
+* common for both the interface as the interface shares
+* the same hardware resource.
+*/
+ if (!enable ((priv-slaves[0].ndev-flags IFF_PROMISC) ||
+ (priv-slaves[1].ndev-flags IFF_PROMISC))) {
+ enable = true;
+ dev_err(ndev-dev, promiscuity not disabled as the
other interface is still in promiscuity mode\n);
+ }
+
+ if (enable) {
+ /* Enable Bypass */
+ cpsw_ale_control_set(ale, 0, ALE_BYPASS, 1);
+
+ dev_dbg(ndev-dev, promiscuity enabled\n);
+ } else {
+ /* Disable Bypass */
+ cpsw_ale_control_set(ale, 0, ALE_BYPASS, 0);
+ dev_dbg(ndev-dev, promiscuity disabled\n);
+ }
+ } else {
+ int i;
+
+ if (enable) {
+ unsigned long timeout = jiffies + HZ;
+
+ /* Disable Learn for all ports */
+ for (i = 0; i = priv-data.slaves; i++) {
+ cpsw_ale_control_set(ale, i,
+ALE_PORT_NOLEARN, 1);
+ cpsw_ale_control_set(ale, i,
+ALE_PORT_NO_SA_UPDATE, 1);
+ }
+
+ /* Clear All Untouched entries */
+ cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1);
+ do {
+ cpu_relax();
+ if (cpsw_ale_control_get(ale, 0, ALE_AGEOUT))
+ break;
+ } while (time_after(timeout, jiffies));
+ cpsw_ale_control_set(ale, 0, ALE_AGEOUT, 1);
+
+ /* Clear all mcast from ALE */
+ cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS
+priv-host_port);
+
+ /* Flood All Unicast Packets to Host port */
+ cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1);
+ dev_dbg(ndev-dev, promiscuity enabled\n);
+ } else {
+ /* Flood All Unicast Packets to Host port */
+ cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0);
+
+ /* Enable Learn for all ports */
+ for (i = 0; i = priv-data.slaves; i++) {
+ cpsw_ale_control_set(ale, i,
+ALE_PORT_NOLEARN, 0);
+ cpsw_ale_control_set(ale, i,
+ALE_PORT_NO_SA_UPDATE, 0);
+ }
+ dev_dbg(ndev-dev, promiscuity disabled\n);
+ }
+ }
+}
+
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
if (ndev-flags IFF_PROMISC) {
/* Enable promiscuous mode */
- dev_err(priv-dev, Ignoring Promiscuous mode\n);
+ cpsw_set_promiscious(ndev, true);
return;
+ } else {
+ /* Disable promiscuous mode */
+ cpsw_set_promiscious(ndev, false);
}
/* Clear all mcast from ALE */
@@ -1257,29 +1332,6 @@ fail:
return NETDEV_TX_BUSY;
}
-static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)
-{
- /*
-* The switch cannot operate in promiscuous mode without substantial
-* headache. For promiscuous mode to work, we would need to put the
-* ALE in bypass mode and route all traffic to the host port.
-* Subsequently, the host will need to operate as a bridge, learn,
-* and flood as needed. For now, we simply complain here and
-* do nothing