1*9da2c867SAlvin Šipraga // SPDX-License-Identifier: GPL-2.0 2*9da2c867SAlvin Šipraga /* VLAN configuration interface for the rtl8365mb switch family 3*9da2c867SAlvin Šipraga * 4*9da2c867SAlvin Šipraga * Copyright (C) 2022 Alvin Šipraga <alsi@bang-olufsen.dk> 5*9da2c867SAlvin Šipraga * 6*9da2c867SAlvin Šipraga * VLAN configuration takes place in two separate domains of the switch: the 7*9da2c867SAlvin Šipraga * VLAN4k table and the VLAN membership configuration (MC) database. While the 8*9da2c867SAlvin Šipraga * VLAN4k table is exhaustive and can be fully populated with 4096 VLAN 9*9da2c867SAlvin Šipraga * configurations, the same does not hold for the VLAN membership configuration 10*9da2c867SAlvin Šipraga * database, which is limited to 32 entries. 11*9da2c867SAlvin Šipraga * 12*9da2c867SAlvin Šipraga * The switch will normally only use the VLAN4k table when making forwarding 13*9da2c867SAlvin Šipraga * decisions. The VLAN membership configuration database is a vestigial ASIC 14*9da2c867SAlvin Šipraga * design and is only used for a few specific features in the rtl8365mb 15*9da2c867SAlvin Šipraga * family. This means that the limit of 32 entries should not hinder us in 16*9da2c867SAlvin Šipraga * programming a huge number of VLANs into the switch. 17*9da2c867SAlvin Šipraga * 18*9da2c867SAlvin Šipraga * One necessary use of the VLAN membership configuration database is for the 19*9da2c867SAlvin Šipraga * programming of a port-based VLAN ID (PVID). The PVID is programmed on a 20*9da2c867SAlvin Šipraga * per-port basis via register field, which refers to a specific VLAN membership 21*9da2c867SAlvin Šipraga * configuration via an index 0~31. In order to maintain coherent behaviour on a 22*9da2c867SAlvin Šipraga * port with a PVID, it is necessary to keep the VLAN configuration synchronized 23*9da2c867SAlvin Šipraga * between the VLAN4k table and the VLAN membership configuration database. 24*9da2c867SAlvin Šipraga * 25*9da2c867SAlvin Šipraga * Since VLAN membership configs are a scarce resource, it will only be used 26*9da2c867SAlvin Šipraga * when strictly needed (i.e. a VLAN with members using PVID). Otherwise, the 27*9da2c867SAlvin Šipraga * VLAN4k will be enough. 28*9da2c867SAlvin Šipraga * 29*9da2c867SAlvin Šipraga * With some exceptions, the entries in both the VLAN4k table and the VLAN 30*9da2c867SAlvin Šipraga * membership configuration database offer the same configuration options. The 31*9da2c867SAlvin Šipraga * differences are as follows: 32*9da2c867SAlvin Šipraga * 33*9da2c867SAlvin Šipraga * 1. VLAN4k entries can specify whether to use Independent or Shared VLAN 34*9da2c867SAlvin Šipraga * Learning (IVL or SVL respectively). VLAN membership config entries 35*9da2c867SAlvin Šipraga * cannot. This underscores the fact that VLAN membership configs are not 36*9da2c867SAlvin Šipraga * involved in the learning process of the ASIC. 37*9da2c867SAlvin Šipraga * 38*9da2c867SAlvin Šipraga * 2. VLAN membership config entries use an "enhanced VLAN ID" (efid), which has 39*9da2c867SAlvin Šipraga * a range 0~8191 compared with the standard 0~4095 range of the VLAN4k 40*9da2c867SAlvin Šipraga * table. This underscores the fact that VLAN membership configs can be used 41*9da2c867SAlvin Šipraga * to group ports on a layer beyond the standard VLAN configuration, which 42*9da2c867SAlvin Šipraga * may be useful for ACL rules which specify alternative forwarding 43*9da2c867SAlvin Šipraga * decisions. 44*9da2c867SAlvin Šipraga * 45*9da2c867SAlvin Šipraga * VLANMC index 0 is reserved as a neutral PVID, used for standalone ports. 46*9da2c867SAlvin Šipraga * 47*9da2c867SAlvin Šipraga */ 48*9da2c867SAlvin Šipraga 49*9da2c867SAlvin Šipraga #include "rtl8365mb_vlan.h" 50*9da2c867SAlvin Šipraga #include "rtl8365mb_table.h" 51*9da2c867SAlvin Šipraga #include <linux/if_bridge.h> 52*9da2c867SAlvin Šipraga #include <linux/lockdep.h> 53*9da2c867SAlvin Šipraga #include <linux/regmap.h> 54*9da2c867SAlvin Šipraga 55*9da2c867SAlvin Šipraga /* CVLAN (i.e. VLAN4k) table entry layout, u16[3] */ 56*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_SIZE 3 /* 48-bits */ 57*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK GENMASK(7, 0) 58*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_MBR_LO_MASK GENMASK(7, 0) 59*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK GENMASK(15, 8) 60*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_UNTAG_LO_MASK GENMASK(7, 0) 61*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_FID_MASK GENMASK(3, 0) 62*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK GENMASK(4, 4) 63*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK GENMASK(7, 5) 64*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK GENMASK(8, 8) 65*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK GENMASK(13, 9) 66*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_METERIDX_LO_MASK GENMASK(4, 0) 67*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK GENMASK(14, 14) 68*9da2c867SAlvin Šipraga /* extends RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK */ 69*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK GENMASK(2, 0) 70*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_MBR_HI_MASK GENMASK(10, 8) 71*9da2c867SAlvin Šipraga /* extends RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK */ 72*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK GENMASK(5, 3) 73*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_UNTAG_HI_MASK GENMASK(10, 8) 74*9da2c867SAlvin Šipraga /* extends RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK */ 75*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK GENMASK(6, 6) 76*9da2c867SAlvin Šipraga #define RTL8365MB_CVLAN_METERIDX_HI_MASK GENMASK(5, 5) 77*9da2c867SAlvin Šipraga 78*9da2c867SAlvin Šipraga /* VLAN member configuration registers 0~31, u16[3] */ 79*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_BASE 0x0728 80*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_ENTRY_SIZE 4 /* 64-bit */ 81*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_REG(index) \ 82*9da2c867SAlvin Šipraga (RTL8365MB_VLAN_MC_BASE + \ 83*9da2c867SAlvin Šipraga (RTL8365MB_VLAN_MC_ENTRY_SIZE * (index))) 84*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D0_MBR_MASK GENMASK(10, 0) 85*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D1_FID_MASK GENMASK(3, 0) 86*9da2c867SAlvin Šipraga 87*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D2_VBPEN_MASK GENMASK(0, 0) 88*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D2_VBPRI_MASK GENMASK(3, 1) 89*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK GENMASK(4, 4) 90*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D2_METERIDX_MASK GENMASK(10, 5) 91*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MC_D3_EVID_MASK GENMASK(12, 0) 92*9da2c867SAlvin Šipraga 93*9da2c867SAlvin Šipraga /* Some limits for VLAN4k/VLAN membership config entries */ 94*9da2c867SAlvin Šipraga #define RTL8365MB_PRIORITYMAX 7 95*9da2c867SAlvin Šipraga #define RTL8365MB_FIDMAX 15 96*9da2c867SAlvin Šipraga #define RTL8365MB_METERMAX 63 97*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_MCMAX 31 98*9da2c867SAlvin Šipraga 99*9da2c867SAlvin Šipraga /* RTL8367S supports 4k vlans (vid<=4095) and 32 enhanced vlans 100*9da2c867SAlvin Šipraga * for VIDs up to 8191 101*9da2c867SAlvin Šipraga */ 102*9da2c867SAlvin Šipraga #define RTL8365MB_MAX_4K_VID 0x0FFF /* 4095 */ 103*9da2c867SAlvin Šipraga #define RTL8365MB_MAX_MC_VID 0x1FFF /* 8191 */ 104*9da2c867SAlvin Šipraga 105*9da2c867SAlvin Šipraga /* Port-based VID registers 0~5 - each one holds an MC index for two ports */ 106*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_BASE 0x0700 107*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_REG(_p) \ 108*9da2c867SAlvin Šipraga (RTL8365MB_VLAN_PVID_CTRL_BASE + ((_p) >> 1)) 109*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_PORT0_MCIDX_MASK 0x001F 110*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_PORT1_MCIDX_MASK 0x1F00 111*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(_p) \ 112*9da2c867SAlvin Šipraga (((_p) & 1) << 3) 113*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(_p) \ 114*9da2c867SAlvin Šipraga (0x1F << RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(_p)) 115*9da2c867SAlvin Šipraga 116*9da2c867SAlvin Šipraga /* Frame type filtering registers */ 117*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_BASE 0x07aa 118*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port) \ 119*9da2c867SAlvin Šipraga (RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_BASE + ((port) >> 3)) 120*9da2c867SAlvin Šipraga /* required as FIELD_PREP cannot use non-constant masks */ 121*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port) \ 122*9da2c867SAlvin Šipraga (0x3 << RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port)) 123*9da2c867SAlvin Šipraga #define RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port) \ 124*9da2c867SAlvin Šipraga (((port) & 0x7) << 1) 125*9da2c867SAlvin Šipraga 126*9da2c867SAlvin Šipraga /* 127*9da2c867SAlvin Šipraga * struct rtl8365mb_vlan4k - VLAN4k table entry 128*9da2c867SAlvin Šipraga * @vid: VLAN ID (0~4095) 129*9da2c867SAlvin Šipraga * @member: port mask of ports in this VLAN 130*9da2c867SAlvin Šipraga * @untag: port mask of ports which untag on egress 131*9da2c867SAlvin Šipraga * @fid: filter ID - only used with SVL (unused) 132*9da2c867SAlvin Šipraga * @priority: priority classification (unused) 133*9da2c867SAlvin Šipraga * @priority_en: enable priority (unused) 134*9da2c867SAlvin Šipraga * @policing_en: enable policing (unused) 135*9da2c867SAlvin Šipraga * @ivl_en: enable IVL instead of default SVL 136*9da2c867SAlvin Šipraga * @meteridx: metering index (unused) 137*9da2c867SAlvin Šipraga * 138*9da2c867SAlvin Šipraga * This structure is used to get/set entries in the VLAN4k table. The 139*9da2c867SAlvin Šipraga * VLAN4k table dictates the VLAN configuration for the switch for the 140*9da2c867SAlvin Šipraga * vast majority of features. 141*9da2c867SAlvin Šipraga */ 142*9da2c867SAlvin Šipraga struct rtl8365mb_vlan4k { 143*9da2c867SAlvin Šipraga u16 vid; 144*9da2c867SAlvin Šipraga u16 member; 145*9da2c867SAlvin Šipraga u16 untag; 146*9da2c867SAlvin Šipraga u8 fid : 4; 147*9da2c867SAlvin Šipraga u8 priority : 3; 148*9da2c867SAlvin Šipraga u8 priority_en : 1; 149*9da2c867SAlvin Šipraga u8 policing_en : 1; 150*9da2c867SAlvin Šipraga u8 ivl_en : 1; 151*9da2c867SAlvin Šipraga u8 meteridx : 6; 152*9da2c867SAlvin Šipraga }; 153*9da2c867SAlvin Šipraga 154*9da2c867SAlvin Šipraga /* 155*9da2c867SAlvin Šipraga * struct rtl8365mb_vlanmc - VLAN membership config 156*9da2c867SAlvin Šipraga * @evid: Enhanced VLAN ID (0~8191) 157*9da2c867SAlvin Šipraga * @member: port mask of ports in this VLAN 158*9da2c867SAlvin Šipraga * @fid: filter ID - only used with SVL (unused) 159*9da2c867SAlvin Šipraga * @priority: priority classification (unused) 160*9da2c867SAlvin Šipraga * @priority_en: enable priority (unused) 161*9da2c867SAlvin Šipraga * @policing_en: enable policing (unused) 162*9da2c867SAlvin Šipraga * @meteridx: metering index (unused) 163*9da2c867SAlvin Šipraga * 164*9da2c867SAlvin Šipraga * This structure is used to get/set entries in the VLAN membership 165*9da2c867SAlvin Šipraga * configuration database. This feature is largely vestigial, but 166*9da2c867SAlvin Šipraga * still needed for at least the following features: 167*9da2c867SAlvin Šipraga * - PVID configuration 168*9da2c867SAlvin Šipraga * - ACL configuration 169*9da2c867SAlvin Šipraga * - selection of VLAN by the CPU tag when VSEL=1, although the switch 170*9da2c867SAlvin Šipraga * can also select VLAN based on the VLAN tag if VSEL=0 171*9da2c867SAlvin Šipraga * 172*9da2c867SAlvin Šipraga * This is a low-level structure and it is recommended to interface with 173*9da2c867SAlvin Šipraga * the VLAN membership config database via &struct rtl8365mb_vlanmc_entry. 174*9da2c867SAlvin Šipraga */ 175*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc { 176*9da2c867SAlvin Šipraga u16 evid; 177*9da2c867SAlvin Šipraga u16 member; 178*9da2c867SAlvin Šipraga u8 fid : 4; 179*9da2c867SAlvin Šipraga u8 priority : 3; 180*9da2c867SAlvin Šipraga u8 priority_en : 1; 181*9da2c867SAlvin Šipraga u8 policing_en : 1; 182*9da2c867SAlvin Šipraga u8 meteridx : 6; 183*9da2c867SAlvin Šipraga }; 184*9da2c867SAlvin Šipraga 185*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_4k_read(struct realtek_priv *priv, u16 vid, 186*9da2c867SAlvin Šipraga struct rtl8365mb_vlan4k *vlan4k) 187*9da2c867SAlvin Šipraga { 188*9da2c867SAlvin Šipraga u16 data[RTL8365MB_CVLAN_ENTRY_SIZE]; 189*9da2c867SAlvin Šipraga int val; 190*9da2c867SAlvin Šipraga int ret; 191*9da2c867SAlvin Šipraga 192*9da2c867SAlvin Šipraga ret = rtl8365mb_table_query(priv, RTL8365MB_TABLE_CVLAN, 193*9da2c867SAlvin Šipraga RTL8365MB_TABLE_OP_READ, &vid, 0, 0, 194*9da2c867SAlvin Šipraga data, ARRAY_SIZE(data)); 195*9da2c867SAlvin Šipraga if (ret) 196*9da2c867SAlvin Šipraga return ret; 197*9da2c867SAlvin Šipraga 198*9da2c867SAlvin Šipraga /* Unpack table entry */ 199*9da2c867SAlvin Šipraga memset(vlan4k, 0, sizeof(*vlan4k)); 200*9da2c867SAlvin Šipraga vlan4k->vid = vid; 201*9da2c867SAlvin Šipraga 202*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK, data[0]); 203*9da2c867SAlvin Šipraga vlan4k->member = FIELD_PREP(RTL8365MB_CVLAN_MBR_LO_MASK, val); 204*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK, data[2]); 205*9da2c867SAlvin Šipraga vlan4k->member |= FIELD_PREP(RTL8365MB_CVLAN_MBR_HI_MASK, val); 206*9da2c867SAlvin Šipraga 207*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK, data[0]); 208*9da2c867SAlvin Šipraga vlan4k->untag = FIELD_PREP(RTL8365MB_CVLAN_UNTAG_LO_MASK, val); 209*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK, data[2]); 210*9da2c867SAlvin Šipraga vlan4k->untag |= FIELD_PREP(RTL8365MB_CVLAN_UNTAG_HI_MASK, val); 211*9da2c867SAlvin Šipraga 212*9da2c867SAlvin Šipraga vlan4k->fid = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_FID_MASK, data[1]); 213*9da2c867SAlvin Šipraga vlan4k->priority_en = 214*9da2c867SAlvin Šipraga FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK, data[1]); 215*9da2c867SAlvin Šipraga vlan4k->priority = 216*9da2c867SAlvin Šipraga FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK, data[1]); 217*9da2c867SAlvin Šipraga vlan4k->policing_en = 218*9da2c867SAlvin Šipraga FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK, data[1]); 219*9da2c867SAlvin Šipraga 220*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK, data[1]); 221*9da2c867SAlvin Šipraga val = FIELD_PREP(RTL8365MB_CVLAN_METERIDX_LO_MASK, val); 222*9da2c867SAlvin Šipraga vlan4k->meteridx = val; 223*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK, data[2]); 224*9da2c867SAlvin Šipraga val = FIELD_PREP(RTL8365MB_CVLAN_METERIDX_HI_MASK, val); 225*9da2c867SAlvin Šipraga vlan4k->meteridx |= val; 226*9da2c867SAlvin Šipraga 227*9da2c867SAlvin Šipraga vlan4k->ivl_en = 228*9da2c867SAlvin Šipraga FIELD_GET(RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK, data[1]); 229*9da2c867SAlvin Šipraga 230*9da2c867SAlvin Šipraga return 0; 231*9da2c867SAlvin Šipraga } 232*9da2c867SAlvin Šipraga 233*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_4k_write(struct realtek_priv *priv, 234*9da2c867SAlvin Šipraga const struct rtl8365mb_vlan4k *vlan4k) 235*9da2c867SAlvin Šipraga { 236*9da2c867SAlvin Šipraga u16 data[RTL8365MB_CVLAN_ENTRY_SIZE] = { 0 }; 237*9da2c867SAlvin Šipraga u16 vid; 238*9da2c867SAlvin Šipraga int val; 239*9da2c867SAlvin Šipraga 240*9da2c867SAlvin Šipraga /* Pack table entry value */ 241*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_MBR_LO_MASK, vlan4k->member); 242*9da2c867SAlvin Šipraga data[0] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D0_MBR_MASK, val); 243*9da2c867SAlvin Šipraga 244*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_UNTAG_LO_MASK, vlan4k->untag); 245*9da2c867SAlvin Šipraga data[0] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D0_UNTAG_MASK, val); 246*9da2c867SAlvin Šipraga 247*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_FID_MASK, vlan4k->fid); 248*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_VBPEN_MASK, 249*9da2c867SAlvin Šipraga vlan4k->priority_en); 250*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_VBPRI_MASK, 251*9da2c867SAlvin Šipraga vlan4k->priority); 252*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_ENVLANPOL_MASK, 253*9da2c867SAlvin Šipraga vlan4k->policing_en); 254*9da2c867SAlvin Šipraga 255*9da2c867SAlvin Šipraga /* FIELD_* does not play nice with struct bitfield. */ 256*9da2c867SAlvin Šipraga val = vlan4k->meteridx; 257*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_METERIDX_LO_MASK, val); 258*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_METERIDX_MASK, val); 259*9da2c867SAlvin Šipraga 260*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D1_IVL_SVL_MASK, 261*9da2c867SAlvin Šipraga vlan4k->ivl_en); 262*9da2c867SAlvin Šipraga 263*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_MBR_HI_MASK, vlan4k->member); 264*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_MBR_EXT_MASK, val); 265*9da2c867SAlvin Šipraga 266*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_UNTAG_HI_MASK, vlan4k->untag); 267*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_UNTAG_EXT_MASK, val); 268*9da2c867SAlvin Šipraga 269*9da2c867SAlvin Šipraga val = vlan4k->meteridx; 270*9da2c867SAlvin Šipraga val = FIELD_GET(RTL8365MB_CVLAN_METERIDX_HI_MASK, val); 271*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_CVLAN_ENTRY_D2_METERIDX_EXT_MASK, val); 272*9da2c867SAlvin Šipraga 273*9da2c867SAlvin Šipraga vid = vlan4k->vid; 274*9da2c867SAlvin Šipraga return rtl8365mb_table_query(priv, RTL8365MB_TABLE_CVLAN, 275*9da2c867SAlvin Šipraga RTL8365MB_TABLE_OP_WRITE, &vid, 0, 0, 276*9da2c867SAlvin Šipraga data, ARRAY_SIZE(data)); 277*9da2c867SAlvin Šipraga } 278*9da2c867SAlvin Šipraga 279*9da2c867SAlvin Šipraga static int 280*9da2c867SAlvin Šipraga rtl8365mb_vlan_4k_port_set(struct dsa_switch *ds, int port, 281*9da2c867SAlvin Šipraga const struct switchdev_obj_port_vlan *vlan, 282*9da2c867SAlvin Šipraga struct netlink_ext_ack *extack, 283*9da2c867SAlvin Šipraga bool include) 284*9da2c867SAlvin Šipraga { 285*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 286*9da2c867SAlvin Šipraga struct rtl8365mb_vlan4k vlan4k = {0}; 287*9da2c867SAlvin Šipraga int ret; 288*9da2c867SAlvin Šipraga 289*9da2c867SAlvin Šipraga dev_dbg(priv->dev, "%s VLAN %d 4K on port %d\n", 290*9da2c867SAlvin Šipraga include ? "add" : "del", 291*9da2c867SAlvin Šipraga vlan->vid, port); 292*9da2c867SAlvin Šipraga 293*9da2c867SAlvin Šipraga if (vlan->vid > RTL8365MB_MAX_4K_VID) { 294*9da2c867SAlvin Šipraga NL_SET_ERR_MSG_MOD(extack, "VLAN ID greater than " 295*9da2c867SAlvin Šipraga __stringify(RTL8365MB_MAX_4K_VID)); 296*9da2c867SAlvin Šipraga return -EINVAL; 297*9da2c867SAlvin Šipraga } 298*9da2c867SAlvin Šipraga 299*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_4k_read(priv, vlan->vid, &vlan4k); 300*9da2c867SAlvin Šipraga if (ret) { 301*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to read VLAN 4k table\n"); 302*9da2c867SAlvin Šipraga return ret; 303*9da2c867SAlvin Šipraga } 304*9da2c867SAlvin Šipraga 305*9da2c867SAlvin Šipraga if (include) 306*9da2c867SAlvin Šipraga vlan4k.member |= BIT(port); 307*9da2c867SAlvin Šipraga else 308*9da2c867SAlvin Šipraga vlan4k.member &= ~BIT(port); 309*9da2c867SAlvin Šipraga 310*9da2c867SAlvin Šipraga if (include && (vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED)) 311*9da2c867SAlvin Šipraga vlan4k.untag |= BIT(port); 312*9da2c867SAlvin Šipraga else 313*9da2c867SAlvin Šipraga vlan4k.untag &= ~BIT(port); 314*9da2c867SAlvin Šipraga vlan4k.ivl_en = true; /* always use Independent VLAN Learning */ 315*9da2c867SAlvin Šipraga 316*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_4k_write(priv, &vlan4k); 317*9da2c867SAlvin Šipraga if (ret) { 318*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to write VLAN 4k table\n"); 319*9da2c867SAlvin Šipraga return ret; 320*9da2c867SAlvin Šipraga } 321*9da2c867SAlvin Šipraga 322*9da2c867SAlvin Šipraga return 0; 323*9da2c867SAlvin Šipraga } 324*9da2c867SAlvin Šipraga 325*9da2c867SAlvin Šipraga /* 326*9da2c867SAlvin Šipraga * rtl8365mb_vlan_4k_port_add() - Add a port to a VLAN 4K table entry 327*9da2c867SAlvin Šipraga * @ds: dsa switch instance 328*9da2c867SAlvin Šipraga * @port: port index 329*9da2c867SAlvin Šipraga * @vlan: switchdev VLAN object containing the target VID and flags 330*9da2c867SAlvin Šipraga * @extack: netlink extended ACK for error reporting 331*9da2c867SAlvin Šipraga * 332*9da2c867SAlvin Šipraga * Adds the specified port to the hardware VLAN 4K membership table. 333*9da2c867SAlvin Šipraga * 334*9da2c867SAlvin Šipraga * Context: Can sleep. Must be called with &priv->vlan_lock held. 335*9da2c867SAlvin Šipraga * Takes and releases &priv->map_lock. 336*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 337*9da2c867SAlvin Šipraga */ 338*9da2c867SAlvin Šipraga int rtl8365mb_vlan_4k_port_add(struct dsa_switch *ds, int port, 339*9da2c867SAlvin Šipraga const struct switchdev_obj_port_vlan *vlan, 340*9da2c867SAlvin Šipraga struct netlink_ext_ack *extack) 341*9da2c867SAlvin Šipraga { 342*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 343*9da2c867SAlvin Šipraga 344*9da2c867SAlvin Šipraga lockdep_assert_held(&priv->vlan_lock); 345*9da2c867SAlvin Šipraga 346*9da2c867SAlvin Šipraga return rtl8365mb_vlan_4k_port_set(ds, port, vlan, extack, true); 347*9da2c867SAlvin Šipraga } 348*9da2c867SAlvin Šipraga 349*9da2c867SAlvin Šipraga /* 350*9da2c867SAlvin Šipraga * rtl8365mb_vlan_4k_port_del() - Remove a port from a VLAN 4K table entry 351*9da2c867SAlvin Šipraga * @ds: dsa switch instance 352*9da2c867SAlvin Šipraga * @port: port index 353*9da2c867SAlvin Šipraga * @vlan: switchdev VLAN object containing the target VID 354*9da2c867SAlvin Šipraga * 355*9da2c867SAlvin Šipraga * Removes the specified port from the hardware VLAN 4K membership table. 356*9da2c867SAlvin Šipraga * 357*9da2c867SAlvin Šipraga * Context: Can sleep. Must be called with &priv->vlan_lock held. 358*9da2c867SAlvin Šipraga * Takes and releases &priv->map_lock. 359*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 360*9da2c867SAlvin Šipraga */ 361*9da2c867SAlvin Šipraga int rtl8365mb_vlan_4k_port_del(struct dsa_switch *ds, int port, 362*9da2c867SAlvin Šipraga const struct switchdev_obj_port_vlan *vlan) 363*9da2c867SAlvin Šipraga { 364*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 365*9da2c867SAlvin Šipraga 366*9da2c867SAlvin Šipraga lockdep_assert_held(&priv->vlan_lock); 367*9da2c867SAlvin Šipraga 368*9da2c867SAlvin Šipraga return rtl8365mb_vlan_4k_port_set(ds, port, vlan, NULL, false); 369*9da2c867SAlvin Šipraga } 370*9da2c867SAlvin Šipraga 371*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_mc_read(struct realtek_priv *priv, u32 index, 372*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc *vlanmc) 373*9da2c867SAlvin Šipraga { 374*9da2c867SAlvin Šipraga u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE]; 375*9da2c867SAlvin Šipraga int ret; 376*9da2c867SAlvin Šipraga 377*9da2c867SAlvin Šipraga ret = regmap_bulk_read(priv->map, RTL8365MB_VLAN_MC_REG(index), &data, 378*9da2c867SAlvin Šipraga RTL8365MB_VLAN_MC_ENTRY_SIZE); 379*9da2c867SAlvin Šipraga if (ret) 380*9da2c867SAlvin Šipraga return ret; 381*9da2c867SAlvin Šipraga 382*9da2c867SAlvin Šipraga vlanmc->member = FIELD_GET(RTL8365MB_VLAN_MC_D0_MBR_MASK, data[0]); 383*9da2c867SAlvin Šipraga vlanmc->fid = FIELD_GET(RTL8365MB_VLAN_MC_D1_FID_MASK, data[1]); 384*9da2c867SAlvin Šipraga vlanmc->meteridx = FIELD_GET(RTL8365MB_VLAN_MC_D2_METERIDX_MASK, 385*9da2c867SAlvin Šipraga data[2]); 386*9da2c867SAlvin Šipraga vlanmc->policing_en = FIELD_GET(RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK, 387*9da2c867SAlvin Šipraga data[2]); 388*9da2c867SAlvin Šipraga vlanmc->priority = FIELD_GET(RTL8365MB_VLAN_MC_D2_VBPRI_MASK, data[2]); 389*9da2c867SAlvin Šipraga vlanmc->priority_en = FIELD_GET(RTL8365MB_VLAN_MC_D2_VBPEN_MASK, 390*9da2c867SAlvin Šipraga data[2]); 391*9da2c867SAlvin Šipraga vlanmc->evid = FIELD_GET(RTL8365MB_VLAN_MC_D3_EVID_MASK, data[3]); 392*9da2c867SAlvin Šipraga 393*9da2c867SAlvin Šipraga return 0; 394*9da2c867SAlvin Šipraga } 395*9da2c867SAlvin Šipraga 396*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_mc_write(struct realtek_priv *priv, u32 index, 397*9da2c867SAlvin Šipraga const struct rtl8365mb_vlanmc *vlanmc) 398*9da2c867SAlvin Šipraga { 399*9da2c867SAlvin Šipraga u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE] = { 0 }; 400*9da2c867SAlvin Šipraga int ret; 401*9da2c867SAlvin Šipraga 402*9da2c867SAlvin Šipraga data[0] |= FIELD_PREP(RTL8365MB_VLAN_MC_D0_MBR_MASK, vlanmc->member); 403*9da2c867SAlvin Šipraga data[1] |= FIELD_PREP(RTL8365MB_VLAN_MC_D1_FID_MASK, vlanmc->fid); 404*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_METERIDX_MASK, 405*9da2c867SAlvin Šipraga vlanmc->meteridx); 406*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_ENVLANPOL_MASK, 407*9da2c867SAlvin Šipraga vlanmc->policing_en); 408*9da2c867SAlvin Šipraga data[2] |= 409*9da2c867SAlvin Šipraga FIELD_PREP(RTL8365MB_VLAN_MC_D2_VBPRI_MASK, vlanmc->priority); 410*9da2c867SAlvin Šipraga data[2] |= FIELD_PREP(RTL8365MB_VLAN_MC_D2_VBPEN_MASK, 411*9da2c867SAlvin Šipraga vlanmc->priority_en); 412*9da2c867SAlvin Šipraga data[3] |= FIELD_PREP(RTL8365MB_VLAN_MC_D3_EVID_MASK, vlanmc->evid); 413*9da2c867SAlvin Šipraga 414*9da2c867SAlvin Šipraga ret = regmap_bulk_write(priv->map, RTL8365MB_VLAN_MC_REG(index), &data, 415*9da2c867SAlvin Šipraga RTL8365MB_VLAN_MC_ENTRY_SIZE); 416*9da2c867SAlvin Šipraga 417*9da2c867SAlvin Šipraga return ret; 418*9da2c867SAlvin Šipraga } 419*9da2c867SAlvin Šipraga 420*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_mc_erase(struct realtek_priv *priv, u32 index) 421*9da2c867SAlvin Šipraga { 422*9da2c867SAlvin Šipraga u16 data[RTL8365MB_VLAN_MC_ENTRY_SIZE] = { 0 }; 423*9da2c867SAlvin Šipraga int ret; 424*9da2c867SAlvin Šipraga 425*9da2c867SAlvin Šipraga ret = regmap_bulk_write(priv->map, RTL8365MB_VLAN_MC_REG(index), &data, 426*9da2c867SAlvin Šipraga RTL8365MB_VLAN_MC_ENTRY_SIZE); 427*9da2c867SAlvin Šipraga 428*9da2c867SAlvin Šipraga return ret; 429*9da2c867SAlvin Šipraga } 430*9da2c867SAlvin Šipraga 431*9da2c867SAlvin Šipraga /* 432*9da2c867SAlvin Šipraga * rtl8365mb_vlan_mc_find() - find VLANMC index by VID or the first free index 433*9da2c867SAlvin Šipraga * 434*9da2c867SAlvin Šipraga * @priv: realtek_priv pointer 435*9da2c867SAlvin Šipraga * @vid: VLAN ID 436*9da2c867SAlvin Šipraga * @index: found index 437*9da2c867SAlvin Šipraga * @first_free: found free index 438*9da2c867SAlvin Šipraga * 439*9da2c867SAlvin Šipraga * If a VLAN MC entry using @vid was found, @index will return the matched index 440*9da2c867SAlvin Šipraga * and @first_free is undefined. If not found, @index will return 0 and 441*9da2c867SAlvin Šipraga * @first_free will return the first found free index in VLAN MC or 0 if the 442*9da2c867SAlvin Šipraga * table is full. 443*9da2c867SAlvin Šipraga * 444*9da2c867SAlvin Šipraga * Although 0 is a valid VLAN MC index, it is reserved for ports without PVID, 445*9da2c867SAlvin Šipraga * including standalone, non-member ports. It uses VID == 0. 446*9da2c867SAlvin Šipraga * 447*9da2c867SAlvin Šipraga * Both @index and @first_free will be in the * 1..@RTL8365MB_VLAN_MCMAX range. 448*9da2c867SAlvin Šipraga * 449*9da2c867SAlvin Šipraga * Return: Returns 0 on success, a negative error on failure. 450*9da2c867SAlvin Šipraga */ 451*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_mc_find(struct realtek_priv *priv, u16 vid, 452*9da2c867SAlvin Šipraga u8 *index, u8 *first_free) 453*9da2c867SAlvin Šipraga { 454*9da2c867SAlvin Šipraga u32 vlan_entry_d3; 455*9da2c867SAlvin Šipraga u8 vlanmc_idx; 456*9da2c867SAlvin Šipraga u16 evid; 457*9da2c867SAlvin Šipraga int ret; 458*9da2c867SAlvin Šipraga 459*9da2c867SAlvin Šipraga *index = 0; 460*9da2c867SAlvin Šipraga *first_free = 0; 461*9da2c867SAlvin Šipraga 462*9da2c867SAlvin Šipraga /* look for existing entry or an empty one */ 463*9da2c867SAlvin Šipraga /* By design, VlanMC[0] is reserved as a neutral PVID value for 464*9da2c867SAlvin Šipraga * standalone ports. It always has EVID == 0. That way, we assume that 465*9da2c867SAlvin Šipraga * all entries after index 0 with VID == 0 are empty. 466*9da2c867SAlvin Šipraga **/ 467*9da2c867SAlvin Šipraga for (vlanmc_idx = 1; vlanmc_idx <= RTL8365MB_VLAN_MCMAX; vlanmc_idx++) { 468*9da2c867SAlvin Šipraga /* just read the 4th word, where the evid is */ 469*9da2c867SAlvin Šipraga ret = regmap_read(priv->map, 470*9da2c867SAlvin Šipraga RTL8365MB_VLAN_MC_REG(vlanmc_idx) + 3, 471*9da2c867SAlvin Šipraga &vlan_entry_d3); 472*9da2c867SAlvin Šipraga if (ret) 473*9da2c867SAlvin Šipraga return ret; 474*9da2c867SAlvin Šipraga 475*9da2c867SAlvin Šipraga evid = FIELD_GET(RTL8365MB_VLAN_MC_D3_EVID_MASK, vlan_entry_d3); 476*9da2c867SAlvin Šipraga 477*9da2c867SAlvin Šipraga if (evid == vid) { 478*9da2c867SAlvin Šipraga *index = vlanmc_idx; 479*9da2c867SAlvin Šipraga return 0; 480*9da2c867SAlvin Šipraga } 481*9da2c867SAlvin Šipraga 482*9da2c867SAlvin Šipraga if (evid == 0x0 && *first_free < 1) 483*9da2c867SAlvin Šipraga *first_free = vlanmc_idx; 484*9da2c867SAlvin Šipraga } 485*9da2c867SAlvin Šipraga return 0; 486*9da2c867SAlvin Šipraga } 487*9da2c867SAlvin Šipraga 488*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_port_get_pvid_idx(struct realtek_priv *priv, 489*9da2c867SAlvin Šipraga int port, u8 *vlanmc_idx) 490*9da2c867SAlvin Šipraga { 491*9da2c867SAlvin Šipraga u32 data; 492*9da2c867SAlvin Šipraga int ret; 493*9da2c867SAlvin Šipraga 494*9da2c867SAlvin Šipraga ret = regmap_read(priv->map, RTL8365MB_VLAN_PVID_CTRL_REG(port), &data); 495*9da2c867SAlvin Šipraga if (ret) 496*9da2c867SAlvin Šipraga return ret; 497*9da2c867SAlvin Šipraga 498*9da2c867SAlvin Šipraga *vlanmc_idx = (data & RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(port)) 499*9da2c867SAlvin Šipraga >> RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(port); 500*9da2c867SAlvin Šipraga 501*9da2c867SAlvin Šipraga return 0; 502*9da2c867SAlvin Šipraga } 503*9da2c867SAlvin Šipraga 504*9da2c867SAlvin Šipraga /* 505*9da2c867SAlvin Šipraga * rtl8365mb_vlan_mc_port_set() - include or exclude a port from VlanMC 506*9da2c867SAlvin Šipraga * @ds: dsa switch 507*9da2c867SAlvin Šipraga * @port: the port number 508*9da2c867SAlvin Šipraga * @vid: the vlan VID to include/exclude @port 509*9da2c867SAlvin Šipraga * @pvid: inform if vid is used as pvid in @port 510*9da2c867SAlvin Šipraga * @extack: optional extack to return errors 511*9da2c867SAlvin Šipraga * @include: whether to include or exclude @port 512*9da2c867SAlvin Šipraga * 513*9da2c867SAlvin Šipraga * This function is used to include/exclude ports to the VlanMC table. 514*9da2c867SAlvin Šipraga * 515*9da2c867SAlvin Šipraga * VlanMC stands for VLAN membership config and it is used exclusively for 516*9da2c867SAlvin Šipraga * PVID. If @vlan members are not using PVID, this function will either 517*9da2c867SAlvin Šipraga * remove or not create a new VlanMC entry. 518*9da2c867SAlvin Šipraga * 519*9da2c867SAlvin Šipraga * VlanMC members are used as a reference port map, cleaning the entry once 520*9da2c867SAlvin Šipraga * no port is using it. 521*9da2c867SAlvin Šipraga * 522*9da2c867SAlvin Šipraga * Port PVID and accepted frame type are updated as well. 523*9da2c867SAlvin Šipraga * 524*9da2c867SAlvin Šipraga * Context: Can sleep. Must be called with &priv->vlan_lock held. 525*9da2c867SAlvin Šipraga * Takes and releases &priv->map_lock. 526*9da2c867SAlvin Šipraga * Return: Returns 0 on success, a negative error on failure. 527*9da2c867SAlvin Šipraga */ 528*9da2c867SAlvin Šipraga static 529*9da2c867SAlvin Šipraga int rtl8365mb_vlan_mc_port_set(struct dsa_switch *ds, int port, 530*9da2c867SAlvin Šipraga u16 vid, bool pvid, 531*9da2c867SAlvin Šipraga struct netlink_ext_ack *extack, 532*9da2c867SAlvin Šipraga bool include) 533*9da2c867SAlvin Šipraga { 534*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 535*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc vlanmc = {0}; 536*9da2c867SAlvin Šipraga u8 first_unused = 0; 537*9da2c867SAlvin Šipraga u8 vlanmc_idx = 0; 538*9da2c867SAlvin Šipraga int ret; 539*9da2c867SAlvin Šipraga 540*9da2c867SAlvin Šipraga dev_dbg(priv->dev, "%s VLAN %d MC on port %d\n", 541*9da2c867SAlvin Šipraga include ? "add" : "del", 542*9da2c867SAlvin Šipraga vid, port); 543*9da2c867SAlvin Šipraga 544*9da2c867SAlvin Šipraga if (vid > RTL8365MB_MAX_MC_VID) { 545*9da2c867SAlvin Šipraga NL_SET_ERR_MSG_MOD(extack, "VLAN ID greater than " 546*9da2c867SAlvin Šipraga __stringify(RTL8365MB_MAX_MC_VID)); 547*9da2c867SAlvin Šipraga return -EINVAL; 548*9da2c867SAlvin Šipraga } 549*9da2c867SAlvin Šipraga 550*9da2c867SAlvin Šipraga /* look for existing entry or an empty slot */ 551*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_find(priv, vid, &vlanmc_idx, 552*9da2c867SAlvin Šipraga &first_unused); 553*9da2c867SAlvin Šipraga if (ret) { 554*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to find a VLAN MC table index\n"); 555*9da2c867SAlvin Šipraga return ret; 556*9da2c867SAlvin Šipraga } 557*9da2c867SAlvin Šipraga 558*9da2c867SAlvin Šipraga if (vlanmc_idx) { 559*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_read(priv, vlanmc_idx, &vlanmc); 560*9da2c867SAlvin Šipraga if (ret) { 561*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to read VLAN MC table\n"); 562*9da2c867SAlvin Šipraga return ret; 563*9da2c867SAlvin Šipraga } 564*9da2c867SAlvin Šipraga } else if (include) { 565*9da2c867SAlvin Šipraga /* for now, vlan_mc is only required for PVID. Defer allocation 566*9da2c867SAlvin Šipraga * until at least one port uses PVID. 567*9da2c867SAlvin Šipraga */ 568*9da2c867SAlvin Šipraga if (!pvid) { 569*9da2c867SAlvin Šipraga dev_dbg(priv->dev, 570*9da2c867SAlvin Šipraga "Not creating VlanMC for vlan %d until a port uses PVID (%d does not)\n", 571*9da2c867SAlvin Šipraga vid, port); 572*9da2c867SAlvin Šipraga return 0; 573*9da2c867SAlvin Šipraga } 574*9da2c867SAlvin Šipraga 575*9da2c867SAlvin Šipraga if (!first_unused) { 576*9da2c867SAlvin Šipraga NL_SET_ERR_MSG_MOD(extack, "All VLAN MC entries (0.." 577*9da2c867SAlvin Šipraga __stringify(RTL8365MB_VLAN_MCMAX) 578*9da2c867SAlvin Šipraga ") are in use."); 579*9da2c867SAlvin Šipraga return -ENOSPC; 580*9da2c867SAlvin Šipraga } 581*9da2c867SAlvin Šipraga 582*9da2c867SAlvin Šipraga vlanmc_idx = first_unused; 583*9da2c867SAlvin Šipraga vlanmc.evid = vid; 584*9da2c867SAlvin Šipraga 585*9da2c867SAlvin Šipraga } else /* excluding and VLANMC not found */ { 586*9da2c867SAlvin Šipraga return 0; 587*9da2c867SAlvin Šipraga } 588*9da2c867SAlvin Šipraga 589*9da2c867SAlvin Šipraga dev_dbg(priv->dev, 590*9da2c867SAlvin Šipraga "VLAN %d (idx: %d) PVID curr members: %08x\n", 591*9da2c867SAlvin Šipraga vid, vlanmc_idx, vlanmc.member); 592*9da2c867SAlvin Šipraga 593*9da2c867SAlvin Šipraga /* here we either have an existing VLANMC (with PVID members) or the 594*9da2c867SAlvin Šipraga * added port is using this VLAN as PVID 595*9da2c867SAlvin Šipraga */ 596*9da2c867SAlvin Šipraga if (include) 597*9da2c867SAlvin Šipraga vlanmc.member |= BIT(port); 598*9da2c867SAlvin Šipraga else 599*9da2c867SAlvin Šipraga vlanmc.member &= ~BIT(port); 600*9da2c867SAlvin Šipraga 601*9da2c867SAlvin Šipraga /* just like we don't need to create a VLAN_MC when there is no port 602*9da2c867SAlvin Šipraga * using it as PVID, we can erase it when there is no more port using 603*9da2c867SAlvin Šipraga * it as PVID. 604*9da2c867SAlvin Šipraga */ 605*9da2c867SAlvin Šipraga if (!vlanmc.member) { 606*9da2c867SAlvin Šipraga dev_dbg(priv->dev, 607*9da2c867SAlvin Šipraga "Clearing VlanMC index %d previously used by VID %d\n", 608*9da2c867SAlvin Šipraga vlanmc_idx, vid); 609*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_erase(priv, vlanmc_idx); 610*9da2c867SAlvin Šipraga } else { 611*9da2c867SAlvin Šipraga dev_dbg(priv->dev, 612*9da2c867SAlvin Šipraga "Saving VlanMC index %d with VID %d\n", 613*9da2c867SAlvin Šipraga vlanmc_idx, vid); 614*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_write(priv, vlanmc_idx, &vlanmc); 615*9da2c867SAlvin Šipraga } 616*9da2c867SAlvin Šipraga if (ret) { 617*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to write vlan MC entry\n"); 618*9da2c867SAlvin Šipraga return ret; 619*9da2c867SAlvin Šipraga } 620*9da2c867SAlvin Šipraga 621*9da2c867SAlvin Šipraga return 0; 622*9da2c867SAlvin Šipraga } 623*9da2c867SAlvin Šipraga 624*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_port_set_pvid(struct realtek_priv *priv, 625*9da2c867SAlvin Šipraga int port, u16 vlanmc_idx) 626*9da2c867SAlvin Šipraga { 627*9da2c867SAlvin Šipraga int ret; 628*9da2c867SAlvin Šipraga u32 val; 629*9da2c867SAlvin Šipraga 630*9da2c867SAlvin Šipraga dev_dbg(priv->dev, "set PVID IDX %d on port %d\n", vlanmc_idx, port); 631*9da2c867SAlvin Šipraga 632*9da2c867SAlvin Šipraga val = vlanmc_idx << RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_OFFSET(port); 633*9da2c867SAlvin Šipraga ret = regmap_update_bits(priv->map, 634*9da2c867SAlvin Šipraga RTL8365MB_VLAN_PVID_CTRL_REG(port), 635*9da2c867SAlvin Šipraga RTL8365MB_VLAN_PVID_CTRL_PORT_MCIDX_MASK(port), 636*9da2c867SAlvin Šipraga val); 637*9da2c867SAlvin Šipraga if (ret) 638*9da2c867SAlvin Šipraga return ret; 639*9da2c867SAlvin Šipraga 640*9da2c867SAlvin Šipraga return 0; 641*9da2c867SAlvin Šipraga } 642*9da2c867SAlvin Šipraga 643*9da2c867SAlvin Šipraga static int rtl8365mb_vlan_get_pvid_mc(struct realtek_priv *priv, 644*9da2c867SAlvin Šipraga int port, u8 *vlanmc_idx, 645*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc *vlanmc) 646*9da2c867SAlvin Šipraga { 647*9da2c867SAlvin Šipraga int ret; 648*9da2c867SAlvin Šipraga 649*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_get_pvid_idx(priv, port, vlanmc_idx); 650*9da2c867SAlvin Šipraga if (ret) 651*9da2c867SAlvin Šipraga return ret; 652*9da2c867SAlvin Šipraga 653*9da2c867SAlvin Šipraga memset(vlanmc, 0, sizeof(*vlanmc)); 654*9da2c867SAlvin Šipraga 655*9da2c867SAlvin Šipraga if (!*vlanmc_idx) 656*9da2c867SAlvin Šipraga return 0; 657*9da2c867SAlvin Šipraga 658*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_read(priv, *vlanmc_idx, vlanmc); 659*9da2c867SAlvin Šipraga if (ret) 660*9da2c867SAlvin Šipraga return ret; 661*9da2c867SAlvin Šipraga 662*9da2c867SAlvin Šipraga return 0; 663*9da2c867SAlvin Šipraga } 664*9da2c867SAlvin Šipraga 665*9da2c867SAlvin Šipraga /* 666*9da2c867SAlvin Šipraga * rtl8365mb_vlan_port_get_pvid - Retrieve the port PVID 667*9da2c867SAlvin Šipraga * @priv: realtek switch private structure 668*9da2c867SAlvin Šipraga * @port: port index 669*9da2c867SAlvin Šipraga * @pvid: pointer to store the retrieved VLAN ID 670*9da2c867SAlvin Šipraga * 671*9da2c867SAlvin Šipraga * Returns the port PVID if defined or 0 if not. 672*9da2c867SAlvin Šipraga * 673*9da2c867SAlvin Šipraga * Context: Can sleep. Takes and releases &priv->map_lock. 674*9da2c867SAlvin Šipraga * Return: 0 on success or a negative error code on failure. 675*9da2c867SAlvin Šipraga */ 676*9da2c867SAlvin Šipraga int rtl8365mb_vlan_port_get_pvid(struct realtek_priv *priv, int port, u16 *pvid) 677*9da2c867SAlvin Šipraga { 678*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc vlanmc; 679*9da2c867SAlvin Šipraga u8 vlanmc_idx; 680*9da2c867SAlvin Šipraga int ret; 681*9da2c867SAlvin Šipraga 682*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &vlanmc_idx, &vlanmc); 683*9da2c867SAlvin Šipraga if (ret) 684*9da2c867SAlvin Šipraga return ret; 685*9da2c867SAlvin Šipraga 686*9da2c867SAlvin Šipraga *pvid = vlanmc.evid; 687*9da2c867SAlvin Šipraga return 0; 688*9da2c867SAlvin Šipraga } 689*9da2c867SAlvin Šipraga 690*9da2c867SAlvin Šipraga /* 691*9da2c867SAlvin Šipraga * rtl8365mb_vlan_port_get_framefilter() - Get the ingress frame filtering mode 692*9da2c867SAlvin Šipraga * for a port 693*9da2c867SAlvin Šipraga * @priv: realtek switch private structure 694*9da2c867SAlvin Šipraga * @port: port index 695*9da2c867SAlvin Šipraga * @frame_type: pointer to store the retrieved ingress frame filter type 696*9da2c867SAlvin Šipraga * 697*9da2c867SAlvin Šipraga * Context: Can sleep. Takes and releases &priv->map_lock. 698*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 699*9da2c867SAlvin Šipraga */ 700*9da2c867SAlvin Šipraga int 701*9da2c867SAlvin Šipraga rtl8365mb_vlan_port_get_framefilter(struct realtek_priv *priv, 702*9da2c867SAlvin Šipraga int port, 703*9da2c867SAlvin Šipraga enum rtl8365mb_frame_ingress *frame_type) 704*9da2c867SAlvin Šipraga { 705*9da2c867SAlvin Šipraga u32 val; 706*9da2c867SAlvin Šipraga int ret; 707*9da2c867SAlvin Šipraga 708*9da2c867SAlvin Šipraga /* Even if ACCEPT_FRAME_TYPE_ANY, the switch will still check if the 709*9da2c867SAlvin Šipraga * port is a member of vlan PVID 710*9da2c867SAlvin Šipraga */ 711*9da2c867SAlvin Šipraga 712*9da2c867SAlvin Šipraga ret = regmap_read(priv->map, RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port), 713*9da2c867SAlvin Šipraga &val); 714*9da2c867SAlvin Šipraga if (ret) 715*9da2c867SAlvin Šipraga return ret; 716*9da2c867SAlvin Šipraga 717*9da2c867SAlvin Šipraga *frame_type = field_get(RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port), 718*9da2c867SAlvin Šipraga val); 719*9da2c867SAlvin Šipraga 720*9da2c867SAlvin Šipraga return 0; 721*9da2c867SAlvin Šipraga } 722*9da2c867SAlvin Šipraga 723*9da2c867SAlvin Šipraga /* 724*9da2c867SAlvin Šipraga * rtl8365mb_vlan_port_set_framefilter() - Set the ingress frame filtering mode 725*9da2c867SAlvin Šipraga * for a port 726*9da2c867SAlvin Šipraga * @priv: realtek switch private structure 727*9da2c867SAlvin Šipraga * @port: port index 728*9da2c867SAlvin Šipraga * @frame_type: the ingress frame filter type to configure 729*9da2c867SAlvin Šipraga * 730*9da2c867SAlvin Šipraga * Context: Can sleep. Takes and releases &priv->map_lock. 731*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 732*9da2c867SAlvin Šipraga */ 733*9da2c867SAlvin Šipraga int 734*9da2c867SAlvin Šipraga rtl8365mb_vlan_port_set_framefilter(struct realtek_priv *priv, 735*9da2c867SAlvin Šipraga int port, 736*9da2c867SAlvin Šipraga enum rtl8365mb_frame_ingress frame_type) 737*9da2c867SAlvin Šipraga { 738*9da2c867SAlvin Šipraga u32 val; 739*9da2c867SAlvin Šipraga 740*9da2c867SAlvin Šipraga /* Even if ACCEPT_FRAME_TYPE_ANY, the switch will still check if the 741*9da2c867SAlvin Šipraga * port is a member of vlan PVID 742*9da2c867SAlvin Šipraga */ 743*9da2c867SAlvin Šipraga val = frame_type << RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_OFFSET(port); 744*9da2c867SAlvin Šipraga 745*9da2c867SAlvin Šipraga return regmap_update_bits(priv->map, 746*9da2c867SAlvin Šipraga RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_REG(port), 747*9da2c867SAlvin Šipraga RTL8365MB_VLAN_ACCEPT_FRAME_TYPE_MASK(port), 748*9da2c867SAlvin Šipraga val); 749*9da2c867SAlvin Šipraga } 750*9da2c867SAlvin Šipraga 751*9da2c867SAlvin Šipraga /* 752*9da2c867SAlvin Šipraga * rtl8365mb_vlan_pvid_port_set() - Configure a port's PVID and associated 753*9da2c867SAlvin Šipraga * VLANMC entry 754*9da2c867SAlvin Šipraga * @ds: dsa switch instance 755*9da2c867SAlvin Šipraga * @port: port index 756*9da2c867SAlvin Šipraga * @vid: target VID 757*9da2c867SAlvin Šipraga * @extack: netlink extended ACK for error reporting 758*9da2c867SAlvin Šipraga * 759*9da2c867SAlvin Šipraga * Allocates or reuses a hardware VLANMC entry to map the given port to its new 760*9da2c867SAlvin Šipraga * PVID. Gracefully unwinds and restores previous configuration if a hardware 761*9da2c867SAlvin Šipraga * write operation fails during execution. 762*9da2c867SAlvin Šipraga * 763*9da2c867SAlvin Šipraga * Context: Can sleep. Must be called with &priv->vlan_lock held. 764*9da2c867SAlvin Šipraga * Takes and releases &priv->map_lock. 765*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 766*9da2c867SAlvin Šipraga */ 767*9da2c867SAlvin Šipraga int rtl8365mb_vlan_pvid_port_set(struct dsa_switch *ds, int port, u16 vid, 768*9da2c867SAlvin Šipraga struct netlink_ext_ack *extack) 769*9da2c867SAlvin Šipraga { 770*9da2c867SAlvin Šipraga enum rtl8365mb_frame_ingress accepted_frame, prev_accepted_frame; 771*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 772*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc prev_vlanmc = {0}; 773*9da2c867SAlvin Šipraga u8 _unused_first_free_idx; 774*9da2c867SAlvin Šipraga u8 prev_vlanmc_idx; 775*9da2c867SAlvin Šipraga u8 vlanmc_idx; 776*9da2c867SAlvin Šipraga int ret; 777*9da2c867SAlvin Šipraga 778*9da2c867SAlvin Šipraga lockdep_assert_held(&priv->vlan_lock); 779*9da2c867SAlvin Šipraga 780*9da2c867SAlvin Šipraga /* Read the old PVID exclusively to undo in case of error */ 781*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &prev_vlanmc_idx, 782*9da2c867SAlvin Šipraga &prev_vlanmc); 783*9da2c867SAlvin Šipraga if (ret) { 784*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to read current VLAN MC\n"); 785*9da2c867SAlvin Šipraga return ret; 786*9da2c867SAlvin Šipraga } 787*9da2c867SAlvin Šipraga 788*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_get_framefilter(priv, port, 789*9da2c867SAlvin Šipraga &prev_accepted_frame); 790*9da2c867SAlvin Šipraga if (ret) { 791*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to get current framefilter\n"); 792*9da2c867SAlvin Šipraga return ret; 793*9da2c867SAlvin Šipraga } 794*9da2c867SAlvin Šipraga 795*9da2c867SAlvin Šipraga /* Find or allocate a new vlan MC and add port to members, 796*9da2c867SAlvin Šipraga * although members are not checked by the HW in vlan MC. 797*9da2c867SAlvin Šipraga */ 798*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_port_set(ds, port, vid, true, extack, true); 799*9da2c867SAlvin Šipraga if (ret) 800*9da2c867SAlvin Šipraga return ret; 801*9da2c867SAlvin Šipraga 802*9da2c867SAlvin Šipraga /* look for existing entry */ 803*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_find(priv, vid, &vlanmc_idx, 804*9da2c867SAlvin Šipraga &_unused_first_free_idx); 805*9da2c867SAlvin Šipraga if (ret) { 806*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to find a VLAN MC table index\n"); 807*9da2c867SAlvin Šipraga goto undo_vlan_mc_port_set; 808*9da2c867SAlvin Šipraga } 809*9da2c867SAlvin Šipraga 810*9da2c867SAlvin Šipraga if (!vlanmc_idx) { 811*9da2c867SAlvin Šipraga dev_err(priv->dev, "VLAN should already exist in VLAN MC\n"); 812*9da2c867SAlvin Šipraga ret = -ENOENT; 813*9da2c867SAlvin Šipraga goto undo_vlan_mc_port_set; 814*9da2c867SAlvin Šipraga } 815*9da2c867SAlvin Šipraga 816*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_set_pvid(priv, port, vlanmc_idx); 817*9da2c867SAlvin Šipraga if (ret) { 818*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to set port PVID\n"); 819*9da2c867SAlvin Šipraga goto undo_vlan_mc_port_set; 820*9da2c867SAlvin Šipraga } 821*9da2c867SAlvin Šipraga 822*9da2c867SAlvin Šipraga /* Changing accept frame is what enables PVID (if not enabled before) */ 823*9da2c867SAlvin Šipraga accepted_frame = RTL8365MB_FRAME_TYPE_ANY_FRAME; 824*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_set_framefilter(priv, port, accepted_frame); 825*9da2c867SAlvin Šipraga if (ret) { 826*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to set port frame filter\n"); 827*9da2c867SAlvin Šipraga goto undo_vlan_port_set_pvid; 828*9da2c867SAlvin Šipraga } 829*9da2c867SAlvin Šipraga 830*9da2c867SAlvin Šipraga /* A VLAN can be added with PVID without removing from the old 831*9da2c867SAlvin Šipraga * PVID VLAN. Clear PVID from the old VLAN MC (if needed). 832*9da2c867SAlvin Šipraga */ 833*9da2c867SAlvin Šipraga if (prev_vlanmc_idx && (prev_vlanmc.evid != vid)) { 834*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_port_set(ds, port, prev_vlanmc.evid, 835*9da2c867SAlvin Šipraga false, NULL, false); 836*9da2c867SAlvin Šipraga if (ret) { 837*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to clear old VLAN MC\n"); 838*9da2c867SAlvin Šipraga goto undo_set_framefilter; 839*9da2c867SAlvin Šipraga } 840*9da2c867SAlvin Šipraga } 841*9da2c867SAlvin Šipraga 842*9da2c867SAlvin Šipraga return 0; 843*9da2c867SAlvin Šipraga 844*9da2c867SAlvin Šipraga undo_set_framefilter: 845*9da2c867SAlvin Šipraga (void)rtl8365mb_vlan_port_set_framefilter(priv, port, 846*9da2c867SAlvin Šipraga prev_accepted_frame); 847*9da2c867SAlvin Šipraga 848*9da2c867SAlvin Šipraga undo_vlan_port_set_pvid: 849*9da2c867SAlvin Šipraga (void)rtl8365mb_vlan_port_set_pvid(priv, port, prev_vlanmc_idx); 850*9da2c867SAlvin Šipraga 851*9da2c867SAlvin Šipraga undo_vlan_mc_port_set: 852*9da2c867SAlvin Šipraga if (prev_vlanmc.evid != vid) 853*9da2c867SAlvin Šipraga (void)rtl8365mb_vlan_mc_port_set(ds, port, vid, false, NULL, 854*9da2c867SAlvin Šipraga false); 855*9da2c867SAlvin Šipraga 856*9da2c867SAlvin Šipraga return ret; 857*9da2c867SAlvin Šipraga } 858*9da2c867SAlvin Šipraga 859*9da2c867SAlvin Šipraga /* 860*9da2c867SAlvin Šipraga * rtl8365mb_vlan_pvid_port_clear() - Remove a port's PVID configuration 861*9da2c867SAlvin Šipraga * @ds: dsa switch instance 862*9da2c867SAlvin Šipraga * @port: port index 863*9da2c867SAlvin Šipraga * @vid: VLAN VID for PVID 864*9da2c867SAlvin Šipraga * 865*9da2c867SAlvin Šipraga * Resets the target port's hardware PVID allocation to 0. Cleans up and frees 866*9da2c867SAlvin Šipraga * the associated VLANMC entry if no other ports are referencing it. 867*9da2c867SAlvin Šipraga * 868*9da2c867SAlvin Šipraga * Context: Can sleep. Must be called with &priv->vlan_lock held. 869*9da2c867SAlvin Šipraga * Takes and releases &priv->map_lock. 870*9da2c867SAlvin Šipraga * Return: 0 on success, or a negative error code on failure. 871*9da2c867SAlvin Šipraga */ 872*9da2c867SAlvin Šipraga int rtl8365mb_vlan_pvid_port_clear(struct dsa_switch *ds, int port, u16 vid) 873*9da2c867SAlvin Šipraga { 874*9da2c867SAlvin Šipraga enum rtl8365mb_frame_ingress accepted_frame, prev_accepted_frame; 875*9da2c867SAlvin Šipraga struct realtek_priv *priv = ds->priv; 876*9da2c867SAlvin Šipraga struct rtl8365mb_vlanmc vlanmc = {0}; 877*9da2c867SAlvin Šipraga u8 vlanmc_idx; 878*9da2c867SAlvin Šipraga int ret; 879*9da2c867SAlvin Šipraga 880*9da2c867SAlvin Šipraga lockdep_assert_held(&priv->vlan_lock); 881*9da2c867SAlvin Šipraga 882*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_get_pvid_mc(priv, port, &vlanmc_idx, 883*9da2c867SAlvin Šipraga &vlanmc); 884*9da2c867SAlvin Šipraga if (ret) { 885*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to read current VLAN MC\n"); 886*9da2c867SAlvin Šipraga return ret; 887*9da2c867SAlvin Šipraga } 888*9da2c867SAlvin Šipraga 889*9da2c867SAlvin Šipraga /* Port is not using PVID. Nothing to remove. */ 890*9da2c867SAlvin Šipraga if (!vlanmc_idx) 891*9da2c867SAlvin Šipraga return 0; 892*9da2c867SAlvin Šipraga 893*9da2c867SAlvin Šipraga /* We are leaving a non PVID vlan, Nothing to remove. */ 894*9da2c867SAlvin Šipraga if (vlanmc.evid != vid) 895*9da2c867SAlvin Šipraga return 0; 896*9da2c867SAlvin Šipraga 897*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_get_framefilter(priv, port, 898*9da2c867SAlvin Šipraga &prev_accepted_frame); 899*9da2c867SAlvin Šipraga if (ret) { 900*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to get current framefilter\n"); 901*9da2c867SAlvin Šipraga return ret; 902*9da2c867SAlvin Šipraga } 903*9da2c867SAlvin Šipraga 904*9da2c867SAlvin Šipraga /* Changing accept frame is what really removes PVID. But only do 905*9da2c867SAlvin Šipraga * that if we are filtering vlan 906*9da2c867SAlvin Šipraga */ 907*9da2c867SAlvin Šipraga if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { 908*9da2c867SAlvin Šipraga accepted_frame = RTL8365MB_FRAME_TYPE_TAGGED_ONLY; 909*9da2c867SAlvin Šipraga 910*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_set_framefilter(priv, port, 911*9da2c867SAlvin Šipraga accepted_frame); 912*9da2c867SAlvin Šipraga if (ret) { 913*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to set port frame filter\n"); 914*9da2c867SAlvin Šipraga return ret; 915*9da2c867SAlvin Šipraga } 916*9da2c867SAlvin Šipraga } else { 917*9da2c867SAlvin Šipraga /* skip undo_set_framefilter */ 918*9da2c867SAlvin Šipraga accepted_frame = prev_accepted_frame; 919*9da2c867SAlvin Šipraga } 920*9da2c867SAlvin Šipraga 921*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_port_set_pvid(priv, port, 0); 922*9da2c867SAlvin Šipraga if (ret) { 923*9da2c867SAlvin Šipraga dev_err(priv->dev, "Failed to set port PVID to 0\n"); 924*9da2c867SAlvin Šipraga goto undo_set_framefilter; 925*9da2c867SAlvin Šipraga } 926*9da2c867SAlvin Šipraga 927*9da2c867SAlvin Šipraga /* Clears the VLAN MC membership and maybe VLAN MC entry if empty */ 928*9da2c867SAlvin Šipraga ret = rtl8365mb_vlan_mc_port_set(ds, port, vlanmc.evid, 929*9da2c867SAlvin Šipraga false, NULL, false); 930*9da2c867SAlvin Šipraga if (ret) 931*9da2c867SAlvin Šipraga goto undo_port_set_pvid; 932*9da2c867SAlvin Šipraga 933*9da2c867SAlvin Šipraga return 0; 934*9da2c867SAlvin Šipraga 935*9da2c867SAlvin Šipraga undo_port_set_pvid: 936*9da2c867SAlvin Šipraga (void)rtl8365mb_vlan_port_set_pvid(priv, port, vlanmc_idx); 937*9da2c867SAlvin Šipraga 938*9da2c867SAlvin Šipraga undo_set_framefilter: 939*9da2c867SAlvin Šipraga if (prev_accepted_frame != accepted_frame) 940*9da2c867SAlvin Šipraga (void)rtl8365mb_vlan_port_set_framefilter(priv, port, 941*9da2c867SAlvin Šipraga prev_accepted_frame); 942*9da2c867SAlvin Šipraga 943*9da2c867SAlvin Šipraga return ret; 944*9da2c867SAlvin Šipraga } 945