239 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip Sparx5 Switch driver3 *4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.5 */6 7#include "sparx5_main_regs.h"8#include "sparx5_main.h"9 10static int sparx5_vlant_set_mask(struct sparx5 *sparx5, u16 vid)11{12 u32 mask[3];13 14 /* Divide up mask in 32 bit words */15 bitmap_to_arr32(mask, sparx5->vlan_mask[vid], SPX5_PORTS);16 17 /* Output mask to respective registers */18 spx5_wr(mask[0], sparx5, ANA_L3_VLAN_MASK_CFG(vid));19 spx5_wr(mask[1], sparx5, ANA_L3_VLAN_MASK_CFG1(vid));20 spx5_wr(mask[2], sparx5, ANA_L3_VLAN_MASK_CFG2(vid));21 22 return 0;23}24 25void sparx5_vlan_init(struct sparx5 *sparx5)26{27 u16 vid;28 29 spx5_rmw(ANA_L3_VLAN_CTRL_VLAN_ENA_SET(1),30 ANA_L3_VLAN_CTRL_VLAN_ENA,31 sparx5,32 ANA_L3_VLAN_CTRL);33 34 /* Map VLAN = FID */35 for (vid = NULL_VID; vid < VLAN_N_VID; vid++)36 spx5_rmw(ANA_L3_VLAN_CFG_VLAN_FID_SET(vid),37 ANA_L3_VLAN_CFG_VLAN_FID,38 sparx5,39 ANA_L3_VLAN_CFG(vid));40}41 42void sparx5_vlan_port_setup(struct sparx5 *sparx5, int portno)43{44 struct sparx5_port *port = sparx5->ports[portno];45 46 /* Configure PVID */47 spx5_rmw(ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(0) |48 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid),49 ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA |50 ANA_CL_VLAN_CTRL_PORT_VID,51 sparx5,52 ANA_CL_VLAN_CTRL(port->portno));53}54 55int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,56 bool untagged)57{58 struct sparx5 *sparx5 = port->sparx5;59 int ret;60 61 /* Untagged egress vlan classification */62 if (untagged && port->vid != vid) {63 if (port->vid) {64 netdev_err(port->ndev,65 "Port already has a native VLAN: %d\n",66 port->vid);67 return -EBUSY;68 }69 port->vid = vid;70 }71 72 /* Make the port a member of the VLAN */73 set_bit(port->portno, sparx5->vlan_mask[vid]);74 ret = sparx5_vlant_set_mask(sparx5, vid);75 if (ret)76 return ret;77 78 /* Default ingress vlan classification */79 if (pvid)80 port->pvid = vid;81 82 sparx5_vlan_port_apply(sparx5, port);83 84 return 0;85}86 87int sparx5_vlan_vid_del(struct sparx5_port *port, u16 vid)88{89 struct sparx5 *sparx5 = port->sparx5;90 int ret;91 92 /* 8021q removes VID 0 on module unload for all interfaces93 * with VLAN filtering feature. We need to keep it to receive94 * untagged traffic.95 */96 if (vid == 0)97 return 0;98 99 /* Stop the port from being a member of the vlan */100 clear_bit(port->portno, sparx5->vlan_mask[vid]);101 ret = sparx5_vlant_set_mask(sparx5, vid);102 if (ret)103 return ret;104 105 /* Ingress */106 if (port->pvid == vid)107 port->pvid = 0;108 109 /* Egress */110 if (port->vid == vid)111 port->vid = 0;112 113 sparx5_vlan_port_apply(sparx5, port);114 115 return 0;116}117 118void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable)119{120 struct sparx5 *sparx5 = port->sparx5;121 u32 val, mask;122 123 /* mask is spread across 3 registers x 32 bit */124 if (port->portno < 32) {125 mask = BIT(port->portno);126 val = enable ? mask : 0;127 spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG(pgid));128 } else if (port->portno < 64) {129 mask = BIT(port->portno - 32);130 val = enable ? mask : 0;131 spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG1(pgid));132 } else if (port->portno < SPX5_PORTS) {133 mask = BIT(port->portno - 64);134 val = enable ? mask : 0;135 spx5_rmw(val, mask, sparx5, ANA_AC_PGID_CFG2(pgid));136 } else {137 netdev_err(port->ndev, "Invalid port no: %d\n", port->portno);138 }139}140 141void sparx5_pgid_clear(struct sparx5 *spx5, int pgid)142{143 spx5_wr(0, spx5, ANA_AC_PGID_CFG(pgid));144 spx5_wr(0, spx5, ANA_AC_PGID_CFG1(pgid));145 spx5_wr(0, spx5, ANA_AC_PGID_CFG2(pgid));146}147 148void sparx5_pgid_read_mask(struct sparx5 *spx5, int pgid, u32 portmask[3])149{150 portmask[0] = spx5_rd(spx5, ANA_AC_PGID_CFG(pgid));151 portmask[1] = spx5_rd(spx5, ANA_AC_PGID_CFG1(pgid));152 portmask[2] = spx5_rd(spx5, ANA_AC_PGID_CFG2(pgid));153}154 155void sparx5_update_fwd(struct sparx5 *sparx5)156{157 DECLARE_BITMAP(workmask, SPX5_PORTS);158 u32 mask[3];159 int port;160 161 /* Divide up fwd mask in 32 bit words */162 bitmap_to_arr32(mask, sparx5->bridge_fwd_mask, SPX5_PORTS);163 164 /* Update flood masks */165 for (port = PGID_UC_FLOOD; port <= PGID_BCAST; port++) {166 spx5_wr(mask[0], sparx5, ANA_AC_PGID_CFG(port));167 spx5_wr(mask[1], sparx5, ANA_AC_PGID_CFG1(port));168 spx5_wr(mask[2], sparx5, ANA_AC_PGID_CFG2(port));169 }170 171 /* Update SRC masks */172 for (port = 0; port < SPX5_PORTS; port++) {173 if (test_bit(port, sparx5->bridge_fwd_mask)) {174 /* Allow to send to all bridged but self */175 bitmap_copy(workmask, sparx5->bridge_fwd_mask, SPX5_PORTS);176 clear_bit(port, workmask);177 bitmap_to_arr32(mask, workmask, SPX5_PORTS);178 spx5_wr(mask[0], sparx5, ANA_AC_SRC_CFG(port));179 spx5_wr(mask[1], sparx5, ANA_AC_SRC_CFG1(port));180 spx5_wr(mask[2], sparx5, ANA_AC_SRC_CFG2(port));181 } else {182 spx5_wr(0, sparx5, ANA_AC_SRC_CFG(port));183 spx5_wr(0, sparx5, ANA_AC_SRC_CFG1(port));184 spx5_wr(0, sparx5, ANA_AC_SRC_CFG2(port));185 }186 }187 188 /* Learning enabled only for bridged ports */189 bitmap_and(workmask, sparx5->bridge_fwd_mask,190 sparx5->bridge_lrn_mask, SPX5_PORTS);191 bitmap_to_arr32(mask, workmask, SPX5_PORTS);192 193 /* Apply learning mask */194 spx5_wr(mask[0], sparx5, ANA_L2_AUTO_LRN_CFG);195 spx5_wr(mask[1], sparx5, ANA_L2_AUTO_LRN_CFG1);196 spx5_wr(mask[2], sparx5, ANA_L2_AUTO_LRN_CFG2);197}198 199void sparx5_vlan_port_apply(struct sparx5 *sparx5,200 struct sparx5_port *port)201 202{203 u32 val;204 205 /* Configure PVID, vlan aware */206 val = ANA_CL_VLAN_CTRL_VLAN_AWARE_ENA_SET(port->vlan_aware) |207 ANA_CL_VLAN_CTRL_VLAN_POP_CNT_SET(port->vlan_aware) |208 ANA_CL_VLAN_CTRL_PORT_VID_SET(port->pvid);209 spx5_wr(val, sparx5, ANA_CL_VLAN_CTRL(port->portno));210 211 val = 0;212 if (port->vlan_aware && !port->pvid)213 /* If port is vlan-aware and tagged, drop untagged and214 * priority tagged frames.215 */216 val = ANA_CL_VLAN_FILTER_CTRL_TAG_REQUIRED_ENA_SET(1) |217 ANA_CL_VLAN_FILTER_CTRL_PRIO_CTAG_DIS_SET(1) |218 ANA_CL_VLAN_FILTER_CTRL_PRIO_STAG_DIS_SET(1);219 spx5_wr(val, sparx5,220 ANA_CL_VLAN_FILTER_CTRL(port->portno, 0));221 222 /* Egress configuration (REW_TAG_CFG): VLAN tag selected via IFH */223 val = REW_TAG_CTRL_TAG_TPID_CFG_SET(5);224 if (port->vlan_aware) {225 if (port->vid)226 /* Tag all frames except when VID == DEFAULT_VLAN */227 val |= REW_TAG_CTRL_TAG_CFG_SET(1);228 else229 val |= REW_TAG_CTRL_TAG_CFG_SET(3);230 }231 spx5_wr(val, sparx5, REW_TAG_CTRL(port->portno));232 233 /* Egress VID */234 spx5_rmw(REW_PORT_VLAN_CFG_PORT_VID_SET(port->vid),235 REW_PORT_VLAN_CFG_PORT_VID,236 sparx5,237 REW_PORT_VLAN_CFG(port->portno));238}239