]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: xilinx: axienet: Support IFF_ALLMULTI
authorSean Anderson <sean.anderson@linux.dev>
Thu, 22 Aug 2024 15:40:59 +0000 (11:40 -0400)
committerJakub Kicinski <kuba@kernel.org>
Mon, 26 Aug 2024 16:52:03 +0000 (09:52 -0700)
Add support for IFF_ALLMULTI by configuring a single filter to match the
multicast address bit. This allows us to keep promiscuous mode disabled,
even when we have more than four multicast addresses. An even better
solution would be to "pack" addresses into the available CAM registers,
but that can wait for a future series.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20240822154059.1066595-6-sean.anderson@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/xilinx/xilinx_axienet.h
drivers/net/ethernet/xilinx/xilinx_axienet_main.c

index 5a7d6b872f5da8062ba70d38fad92bae763e2505..c301dd2ee083966e9058038c1e1a28a79df18c64 100644 (file)
 #define XAE_FFE_OFFSET         0x0000070C /* Frame Filter Enable */
 #define XAE_AF0_OFFSET         0x00000710 /* Address Filter 0 */
 #define XAE_AF1_OFFSET         0x00000714 /* Address Filter 1 */
+#define XAE_AM0_OFFSET         0x00000750 /* Frame Filter Mask Value Bytes 3-0 */
+#define XAE_AM1_OFFSET         0x00000754 /* Frame Filter Mask Value Bytes 7-4 */
 
 #define XAE_TX_VLAN_DATA_OFFSET 0x00004000 /* TX VLAN data table address */
 #define XAE_RX_VLAN_DATA_OFFSET 0x00008000 /* RX VLAN data table address */
index 5c4a5949a021306a6d4ddf35187e659235edc4b2..fe6a0e2e463f8039b1f510bf8b33c6c3c3ae2603 100644 (file)
@@ -437,18 +437,27 @@ static void axienet_set_multicast_list(struct net_device *ndev)
        u32 reg, af0reg, af1reg;
        struct axienet_local *lp = netdev_priv(ndev);
 
-       if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) ||
-           netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) {
-               reg = axienet_ior(lp, XAE_FMI_OFFSET);
+       reg = axienet_ior(lp, XAE_FMI_OFFSET);
+       reg &= ~XAE_FMI_PM_MASK;
+       if (ndev->flags & IFF_PROMISC)
                reg |= XAE_FMI_PM_MASK;
+       else
+               reg &= ~XAE_FMI_PM_MASK;
+       axienet_iow(lp, XAE_FMI_OFFSET, reg);
+
+       if (ndev->flags & IFF_ALLMULTI ||
+           netdev_mc_count(ndev) > XAE_MULTICAST_CAM_TABLE_NUM) {
+               reg &= 0xFFFFFF00;
                axienet_iow(lp, XAE_FMI_OFFSET, reg);
+               axienet_iow(lp, XAE_AF0_OFFSET, 1); /* Multicast bit */
+               axienet_iow(lp, XAE_AF1_OFFSET, 0);
+               axienet_iow(lp, XAE_AM0_OFFSET, 1); /* ditto */
+               axienet_iow(lp, XAE_AM1_OFFSET, 0);
+               axienet_iow(lp, XAE_FFE_OFFSET, 1);
+               i = 1;
        } else if (!netdev_mc_empty(ndev)) {
                struct netdev_hw_addr *ha;
 
-               reg = axienet_ior(lp, XAE_FMI_OFFSET);
-               reg &= ~XAE_FMI_PM_MASK;
-               axienet_iow(lp, XAE_FMI_OFFSET, reg);
-
                netdev_for_each_mc_addr(ha, ndev) {
                        if (i >= XAE_MULTICAST_CAM_TABLE_NUM)
                                break;
@@ -461,24 +470,21 @@ static void axienet_set_multicast_list(struct net_device *ndev)
                        af1reg = (ha->addr[4]);
                        af1reg |= (ha->addr[5] << 8);
 
-                       reg = axienet_ior(lp, XAE_FMI_OFFSET) & 0xFFFFFF00;
+                       reg &= 0xFFFFFF00;
                        reg |= i;
 
                        axienet_iow(lp, XAE_FMI_OFFSET, reg);
                        axienet_iow(lp, XAE_AF0_OFFSET, af0reg);
                        axienet_iow(lp, XAE_AF1_OFFSET, af1reg);
+                       axienet_iow(lp, XAE_AM0_OFFSET, 0xffffffff);
+                       axienet_iow(lp, XAE_AM1_OFFSET, 0x0000ffff);
                        axienet_iow(lp, XAE_FFE_OFFSET, 1);
                        i++;
                }
-       } else {
-               reg = axienet_ior(lp, XAE_FMI_OFFSET);
-               reg &= ~XAE_FMI_PM_MASK;
-
-               axienet_iow(lp, XAE_FMI_OFFSET, reg);
        }
 
        for (; i < XAE_MULTICAST_CAM_TABLE_NUM; i++) {
-               reg = axienet_ior(lp, XAE_FMI_OFFSET) & 0xFFFFFF00;
+               reg &= 0xFFFFFF00;
                reg |= i;
                axienet_iow(lp, XAE_FMI_OFFSET, reg);
                axienet_iow(lp, XAE_FFE_OFFSET, 0);