Skip to content

Commit 0cd8f9c

Browse files
mugunthanvnmdavem330
authored andcommitted
drivers: net: cpsw: enable promiscuous mode support
Enable promiscuous mode support for CPSW. Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 6ef7b8a commit 0cd8f9c

File tree

3 files changed

+98
-25
lines changed

3 files changed

+98
-25
lines changed

drivers/net/ethernet/ti/cpsw.c

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,93 @@ static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
541541
return slave_num;
542542
}
543543

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+
544620
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
545621
{
546622
struct cpsw_priv *priv = netdev_priv(ndev);
547623

548624
if (ndev->flags & IFF_PROMISC) {
549625
/* Enable promiscuous mode */
550-
dev_err(priv->dev, "Ignoring Promiscuous mode\n");
626+
cpsw_set_promiscious(ndev, true);
551627
return;
628+
} else {
629+
/* Disable promiscuous mode */
630+
cpsw_set_promiscious(ndev, false);
552631
}
553632

554633
/* Clear all mcast from ALE */
@@ -1257,29 +1336,6 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
12571336
return NETDEV_TX_BUSY;
12581337
}
12591338

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-
12831339
#ifdef CONFIG_TI_CPTS
12841340

12851341
static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
@@ -1575,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = {
15751631
.ndo_open = cpsw_ndo_open,
15761632
.ndo_stop = cpsw_ndo_stop,
15771633
.ndo_start_xmit = cpsw_ndo_start_xmit,
1578-
.ndo_change_rx_flags = cpsw_ndo_change_rx_flags,
15791634
.ndo_set_mac_address = cpsw_ndo_set_mac_address,
15801635
.ndo_do_ioctl = cpsw_ndo_ioctl,
15811636
.ndo_validate_addr = eth_validate_addr,

drivers/net/ethernet/ti/cpsw_ale.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,14 @@ static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
477477
.port_shift = 0,
478478
.bits = 1,
479479
},
480+
[ALE_P0_UNI_FLOOD] = {
481+
.name = "port0_unicast_flood",
482+
.offset = ALE_CONTROL,
483+
.port_offset = 0,
484+
.shift = 8,
485+
.port_shift = 0,
486+
.bits = 1,
487+
},
480488
[ALE_VLAN_NOLEARN] = {
481489
.name = "vlan_nolearn",
482490
.offset = ALE_CONTROL,
@@ -573,6 +581,14 @@ static const struct ale_control_info ale_controls[ALE_NUM_CONTROLS] = {
573581
.port_shift = 0,
574582
.bits = 1,
575583
},
584+
[ALE_PORT_NO_SA_UPDATE] = {
585+
.name = "no_source_update",
586+
.offset = ALE_PORTCTL,
587+
.port_offset = 4,
588+
.shift = 5,
589+
.port_shift = 0,
590+
.bits = 1,
591+
},
576592
[ALE_PORT_MCAST_LIMIT] = {
577593
.name = "mcast_limit",
578594
.offset = ALE_PORTCTL,

drivers/net/ethernet/ti/cpsw_ale.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ enum cpsw_ale_control {
3434
ALE_ENABLE,
3535
ALE_CLEAR,
3636
ALE_AGEOUT,
37+
ALE_P0_UNI_FLOOD,
3738
ALE_VLAN_NOLEARN,
3839
ALE_NO_PORT_VLAN,
3940
ALE_OUI_DENY,
@@ -47,6 +48,7 @@ enum cpsw_ale_control {
4748
ALE_PORT_DROP_UNTAGGED,
4849
ALE_PORT_DROP_UNKNOWN_VLAN,
4950
ALE_PORT_NOLEARN,
51+
ALE_PORT_NO_SA_UPDATE,
5052
ALE_PORT_UNKNOWN_VLAN_MEMBER,
5153
ALE_PORT_UNKNOWN_MCAST_FLOOD,
5254
ALE_PORT_UNKNOWN_REG_MCAST_FLOOD,

0 commit comments

Comments
 (0)