Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: stmmac: Add support for VLAN promiscuous mode

For dwmac4, enable VLAN promiscuity when MAC controller is requested to
enter promiscuous mode.

Signed-off-by: Chuah, Kim Tatt <kim.tatt.chuah@intel.com>
Signed-off-by: Ong Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: Tan, Tee Min <tee.min.tan@intel.com>
Signed-off-by: Wong Vee Khee <vee.khee.wong@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Chuah, Kim Tatt and committed by
David S. Miller
c89f44ff 58e64a31

+69
+1
drivers/net/ethernet/stmicro/stmmac/common.h
··· 473 473 unsigned int xlgmac; 474 474 unsigned int num_vlan; 475 475 u32 vlan_filter[32]; 476 + unsigned int promisc; 476 477 }; 477 478 478 479 struct stmmac_rx_routing {
+1
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
··· 90 90 #define GMAC_VLAN_CSVL BIT(19) 91 91 #define GMAC_VLAN_VLC GENMASK(17, 16) 92 92 #define GMAC_VLAN_VLC_SHIFT 16 93 + #define GMAC_VLAN_VLHT GENMASK(15, 0) 93 94 94 95 /* MAC VLAN Tag */ 95 96 #define GMAC_VLAN_TAG_VID GENMASK(15, 0)
+67
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
··· 450 450 if (vid > 4095) 451 451 return -EINVAL; 452 452 453 + if (hw->promisc) { 454 + netdev_err(dev, 455 + "Adding VLAN in promisc mode not supported\n"); 456 + return -EPERM; 457 + } 458 + 453 459 /* Single Rx VLAN Filter */ 454 460 if (hw->num_vlan == 1) { 455 461 /* For single VLAN filter, VID 0 means VLAN promiscuous */ ··· 505 499 { 506 500 int i, ret = 0; 507 501 502 + if (hw->promisc) { 503 + netdev_err(dev, 504 + "Deleting VLAN in promisc mode not supported\n"); 505 + return -EPERM; 506 + } 507 + 508 508 /* Single Rx VLAN Filter */ 509 509 if (hw->num_vlan == 1) { 510 510 if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) { ··· 535 523 return ret; 536 524 } 537 525 526 + static void dwmac4_vlan_promisc_enable(struct net_device *dev, 527 + struct mac_device_info *hw) 528 + { 529 + void __iomem *ioaddr = hw->pcsr; 530 + u32 value; 531 + u32 hash; 532 + u32 val; 533 + int i; 534 + 535 + /* Single Rx VLAN Filter */ 536 + if (hw->num_vlan == 1) { 537 + dwmac4_write_single_vlan(dev, 0); 538 + return; 539 + } 540 + 541 + /* Extended Rx VLAN Filter Enable */ 542 + for (i = 0; i < hw->num_vlan; i++) { 543 + if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) { 544 + val = hw->vlan_filter[i] & ~GMAC_VLAN_TAG_DATA_VEN; 545 + dwmac4_write_vlan_filter(dev, hw, i, val); 546 + } 547 + } 548 + 549 + hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); 550 + if (hash & GMAC_VLAN_VLHT) { 551 + value = readl(ioaddr + GMAC_VLAN_TAG); 552 + if (value & GMAC_VLAN_VTHM) { 553 + value &= ~GMAC_VLAN_VTHM; 554 + writel(value, ioaddr + GMAC_VLAN_TAG); 555 + } 556 + } 557 + } 558 + 538 559 static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, 539 560 struct mac_device_info *hw) 540 561 { 562 + void __iomem *ioaddr = hw->pcsr; 563 + u32 value; 564 + u32 hash; 541 565 u32 val; 542 566 int i; 543 567 ··· 589 541 val = hw->vlan_filter[i]; 590 542 dwmac4_write_vlan_filter(dev, hw, i, val); 591 543 } 544 + } 545 + 546 + hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); 547 + if (hash & GMAC_VLAN_VLHT) { 548 + value = readl(ioaddr + GMAC_VLAN_TAG); 549 + value |= GMAC_VLAN_VTHM; 550 + writel(value, ioaddr + GMAC_VLAN_TAG); 592 551 } 593 552 } 594 553 ··· 679 624 value |= GMAC_PACKET_FILTER_VTFE; 680 625 681 626 writel(value, ioaddr + GMAC_PACKET_FILTER); 627 + 628 + if (dev->flags & IFF_PROMISC) { 629 + if (!hw->promisc) { 630 + hw->promisc = 1; 631 + dwmac4_vlan_promisc_enable(dev, hw); 632 + } 633 + } else { 634 + if (hw->promisc) { 635 + hw->promisc = 0; 636 + dwmac4_restore_hw_vlan_rx_fltr(dev, hw); 637 + } 638 + } 682 639 } 683 640 684 641 static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,