diff options
author | Beniamino Galvani <b.galvani@gmail.com> | 2014-05-11 12:11:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-13 18:02:24 -0400 |
commit | 775dd682e2b0ec79fa346152c00870d4a3832a47 (patch) | |
tree | 23a7ad244374a73b6b97d7c9f6750bbef1961b07 /drivers/net/ethernet/arc | |
parent | ae8b42c6fc37ca1b7eb30898f5a65196bbb47291 (diff) |
arc_emac: implement promiscuous mode and multicast filtering
This patch implements the set_rx_mode function to enable/disable
promiscuous or all-multicast modes and to update the multicast
filtering list of the device.
Signed-off-by: Beniamino Galvani <b.galvani@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/arc')
-rw-r--r-- | drivers/net/ethernet/arc/emac_main.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index d647a7d115ac..be090e68e1d1 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c | |||
@@ -13,6 +13,7 @@ | |||
13 | * Vineet Gupta | 13 | * Vineet Gupta |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/crc32.h> | ||
16 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
17 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
18 | #include <linux/io.h> | 19 | #include <linux/io.h> |
@@ -451,6 +452,41 @@ static int arc_emac_open(struct net_device *ndev) | |||
451 | } | 452 | } |
452 | 453 | ||
453 | /** | 454 | /** |
455 | * arc_emac_set_rx_mode - Change the receive filtering mode. | ||
456 | * @ndev: Pointer to the network device. | ||
457 | * | ||
458 | * This function enables/disables promiscuous or all-multicast mode | ||
459 | * and updates the multicast filtering list of the network device. | ||
460 | */ | ||
461 | static void arc_emac_set_rx_mode(struct net_device *ndev) | ||
462 | { | ||
463 | struct arc_emac_priv *priv = netdev_priv(ndev); | ||
464 | |||
465 | if (ndev->flags & IFF_PROMISC) { | ||
466 | arc_reg_or(priv, R_CTRL, PROM_MASK); | ||
467 | } else { | ||
468 | arc_reg_clr(priv, R_CTRL, PROM_MASK); | ||
469 | |||
470 | if (ndev->flags & IFF_ALLMULTI) { | ||
471 | arc_reg_set(priv, R_LAFL, ~0); | ||
472 | arc_reg_set(priv, R_LAFH, ~0); | ||
473 | } else { | ||
474 | struct netdev_hw_addr *ha; | ||
475 | unsigned int filter[2] = { 0, 0 }; | ||
476 | int bit; | ||
477 | |||
478 | netdev_for_each_mc_addr(ha, ndev) { | ||
479 | bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26; | ||
480 | filter[bit >> 5] |= 1 << (bit & 31); | ||
481 | } | ||
482 | |||
483 | arc_reg_set(priv, R_LAFL, filter[0]); | ||
484 | arc_reg_set(priv, R_LAFH, filter[1]); | ||
485 | } | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /** | ||
454 | * arc_emac_stop - Close the network device. | 490 | * arc_emac_stop - Close the network device. |
455 | * @ndev: Pointer to the network device. | 491 | * @ndev: Pointer to the network device. |
456 | * | 492 | * |
@@ -620,6 +656,7 @@ static const struct net_device_ops arc_emac_netdev_ops = { | |||
620 | .ndo_start_xmit = arc_emac_tx, | 656 | .ndo_start_xmit = arc_emac_tx, |
621 | .ndo_set_mac_address = arc_emac_set_address, | 657 | .ndo_set_mac_address = arc_emac_set_address, |
622 | .ndo_get_stats = arc_emac_stats, | 658 | .ndo_get_stats = arc_emac_stats, |
659 | .ndo_set_rx_mode = arc_emac_set_rx_mode, | ||
623 | }; | 660 | }; |
624 | 661 | ||
625 | static int arc_emac_probe(struct platform_device *pdev) | 662 | static int arc_emac_probe(struct platform_device *pdev) |