Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /* Realtek SMI library helpers for the RTL8366x variants
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * RTL8366RB and RTL8366S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/if_bridge.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <net/dsa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include "realtek-smi-core.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	*used = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	for (i = 0; i < smi->num_ports; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 		int index = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 		ret = smi->ops->get_mc_index(smi, i, &index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 		if (mc_index == index) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 			*used = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) EXPORT_SYMBOL_GPL(rtl8366_mc_is_used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  * @smi: the Realtek SMI device instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * @vid: the VLAN ID to look up or allocate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * @vlanmc: the pointer will be assigned to a pointer to a valid member config
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  * if successful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * @return: index of a new member config or negative error number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) static int rtl8366_obtain_mc(struct realtek_smi *smi, int vid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 			     struct rtl8366_vlan_mc *vlanmc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	struct rtl8366_vlan_4k vlan4k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	/* Try to find an existing member config entry for this VID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	for (i = 0; i < smi->num_vlan_mc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 		ret = smi->ops->get_vlan_mc(smi, i, vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 			dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 				i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		if (vid == vlanmc->vid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 			return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	/* We have no MC entry for this VID, try to find an empty one */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	for (i = 0; i < smi->num_vlan_mc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		ret = smi->ops->get_vlan_mc(smi, i, vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 			dev_err(smi->dev, "error searching for VLAN MC %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 				i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		if (vlanmc->vid == 0 && vlanmc->member == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 			/* Update the entry from the 4K table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 			ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 			if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 				dev_err(smi->dev, "error looking for 4K VLAN MC %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 					i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 			vlanmc->vid = vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 			vlanmc->member = vlan4k.member;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 			vlanmc->untag = vlan4k.untag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 			vlanmc->fid = vlan4k.fid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 			ret = smi->ops->set_vlan_mc(smi, i, vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 			if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 				dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 					i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			dev_dbg(smi->dev, "created new MC at index %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 				i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 			return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	/* MC table is full, try to find an unused entry and replace it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	for (i = 0; i < smi->num_vlan_mc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		int used;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		ret = rtl8366_mc_is_used(smi, i, &used);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		if (!used) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 			/* Update the entry from the 4K table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 			ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 			if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 			vlanmc->vid = vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 			vlanmc->member = vlan4k.member;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 			vlanmc->untag = vlan4k.untag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 			vlanmc->fid = vlan4k.fid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 			ret = smi->ops->set_vlan_mc(smi, i, vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 			if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 				dev_err(smi->dev, "unable to set/update VLAN MC %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 					i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 			dev_dbg(smi->dev, "recycled MC at index %i for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 				i, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 			return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	dev_err(smi->dev, "all VLAN member configurations are in use\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	return -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) int rtl8366_set_vlan(struct realtek_smi *smi, int vid, u32 member,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		     u32 untag, u32 fid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	struct rtl8366_vlan_mc vlanmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	struct rtl8366_vlan_4k vlan4k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	int mc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	if (!smi->ops->is_vlan_valid(smi, vid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	dev_dbg(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		"setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 		vid, member, untag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	/* Update the 4K table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	ret = smi->ops->get_vlan_4k(smi, vid, &vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	vlan4k.member |= member;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	vlan4k.untag |= untag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	vlan4k.fid = fid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	ret = smi->ops->set_vlan_4k(smi, &vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	dev_dbg(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 		"resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		vid, vlan4k.member, vlan4k.untag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	/* Find or allocate a member config for this VID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	ret = rtl8366_obtain_mc(smi, vid, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	mc = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	/* Update the MC entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	vlanmc.member |= member;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	vlanmc.untag |= untag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	vlanmc.fid = fid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	/* Commit updates to the MC entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	ret = smi->ops->set_vlan_mc(smi, mc, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		dev_err(smi->dev, "failed to commit changes to VLAN MC index %d for VID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			mc, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		dev_dbg(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			"resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 			vid, vlanmc.member, vlanmc.untag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) EXPORT_SYMBOL_GPL(rtl8366_set_vlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) int rtl8366_set_pvid(struct realtek_smi *smi, unsigned int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 		     unsigned int vid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	struct rtl8366_vlan_mc vlanmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	int mc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	if (!smi->ops->is_vlan_valid(smi, vid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	/* Find or allocate a member config for this VID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	ret = rtl8366_obtain_mc(smi, vid, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	mc = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	ret = smi->ops->set_mc_index(smi, port, mc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		dev_err(smi->dev, "set PVID: failed to set MC index %d for port %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 			mc, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	dev_dbg(smi->dev, "set PVID: the PVID for port %d set to %d using existing MC index %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		port, vid, mc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) EXPORT_SYMBOL_GPL(rtl8366_set_pvid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	/* To enable 4k VLAN, ordinary VLAN must be enabled first,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	 * but if we disable 4k VLAN it is fine to leave ordinary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	 * VLAN enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		/* Make sure VLAN is ON */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		ret = smi->ops->enable_vlan(smi, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		smi->vlan_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	ret = smi->ops->enable_vlan4k(smi, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	smi->vlan4k_enabled = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	ret = smi->ops->enable_vlan(smi, enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	smi->vlan_enabled = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	/* If we turn VLAN off, make sure that we turn off
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	 * 4k VLAN as well, if that happened to be on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	if (!enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 		smi->vlan4k_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		ret = smi->ops->enable_vlan4k(smi, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) EXPORT_SYMBOL_GPL(rtl8366_enable_vlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int rtl8366_reset_vlan(struct realtek_smi *smi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct rtl8366_vlan_mc vlanmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	rtl8366_enable_vlan(smi, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	rtl8366_enable_vlan4k(smi, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 	/* Clear the 16 VLAN member configurations */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	vlanmc.vid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	vlanmc.priority = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	vlanmc.member = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	vlanmc.untag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	vlanmc.fid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	for (i = 0; i < smi->num_vlan_mc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) EXPORT_SYMBOL_GPL(rtl8366_reset_vlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int rtl8366_init_vlan(struct realtek_smi *smi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	int port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	ret = rtl8366_reset_vlan(smi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	/* Loop over the available ports, for each port, associate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	 * it with the VLAN (port+1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	for (port = 0; port < smi->num_ports; port++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		if (port == smi->cpu_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 			/* For the CPU port, make all ports members of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 			 * VLAN.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 			mask = GENMASK((int)smi->num_ports - 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 			/* For all other ports, enable itself plus the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 			 * CPU port.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			mask = BIT(port) | BIT(smi->cpu_port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 		/* For each port, set the port as member of VLAN (port+1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		 * and untagged, except for the CPU port: the CPU port (5) is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		 * member of VLAN 6 and so are ALL the other ports as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		 * Use filter 0 (no filter).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 		dev_info(smi->dev, "VLAN%d port mask for port %d, %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 			 (port + 1), port, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		ret = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		dev_info(smi->dev, "VLAN%d port %d, PVID set to %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 			 (port + 1), port, (port + 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		ret = rtl8366_set_pvid(smi, port, (port + 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 			return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	return rtl8366_enable_vlan(smi, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) EXPORT_SYMBOL_GPL(rtl8366_init_vlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 			   struct switchdev_trans *trans)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	struct rtl8366_vlan_4k vlan4k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	/* Use VLAN nr port + 1 since VLAN0 is not valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	if (switchdev_trans_ph_prepare(trans)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		if (!smi->ops->is_vlan_valid(smi, port + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	dev_info(smi->dev, "%s filtering on port %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		 vlan_filtering ? "enable" : "disable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		 port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	/* TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	 * The hardware support filter ID (FID) 0..7, I have no clue how to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	 * support this in the driver when the callback only says on/off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 	ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 	/* Just set the filter to FID 1 for now then */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	ret = rtl8366_set_vlan(smi, port + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			       vlan4k.member,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			       vlan4k.untag,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 			       1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) int rtl8366_vlan_prepare(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 			 const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	u16 vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	for (vid = vlan->vid_begin; vid < vlan->vid_end; vid++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 		if (!smi->ops->is_vlan_valid(smi, vid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	dev_info(smi->dev, "prepare VLANs %04x..%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 		 vlan->vid_begin, vlan->vid_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	/* Enable VLAN in the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	 * FIXME: what's with this 4k business?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	 * Just rtl8366_enable_vlan() seems inconclusive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	ret = rtl8366_enable_vlan4k(smi, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) EXPORT_SYMBOL_GPL(rtl8366_vlan_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) void rtl8366_vlan_add(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		      const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	bool untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	bool pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	u32 member = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	u32 untag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	u16 vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	for (vid = vlan->vid_begin; vid < vlan->vid_end; vid++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		if (!smi->ops->is_vlan_valid(smi, vid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	dev_info(smi->dev, "add VLAN %d on port %d, %s, %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		 vlan->vid_begin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		 port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		 untagged ? "untagged" : "tagged",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		 pvid ? " PVID" : "no PVID");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 		dev_err(smi->dev, "port is DSA or CPU port\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 		member |= BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 		if (untagged)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 			untag |= BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 		ret = rtl8366_set_vlan(smi, vid, member, untag, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 			dev_err(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 				"failed to set up VLAN %04x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 				vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		if (!pvid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 		ret = rtl8366_set_pvid(smi, port, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 			dev_err(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 				"failed to set PVID on port %d to VLAN %04x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 				port, vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 		if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 			dev_dbg(smi->dev, "VLAN add: added VLAN %d with PVID on port %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 				vid, port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) EXPORT_SYMBOL_GPL(rtl8366_vlan_add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) int rtl8366_vlan_del(struct dsa_switch *ds, int port,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		     const struct switchdev_obj_port_vlan *vlan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	u16 vid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	dev_info(smi->dev, "del VLAN on port %d\n", port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 		int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 		dev_info(smi->dev, "del VLAN %04x\n", vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 		for (i = 0; i < smi->num_vlan_mc; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 			struct rtl8366_vlan_mc vlanmc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 			ret = smi->ops->get_vlan_mc(smi, i, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 			if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 			if (vid == vlanmc.vid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 				/* Remove this port from the VLAN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 				vlanmc.member &= ~BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 				vlanmc.untag &= ~BIT(port);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 				 * If no ports are members of this VLAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 				 * anymore then clear the whole member
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 				 * config so it can be reused.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 				if (!vlanmc.member && vlanmc.untag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 					vlanmc.vid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 					vlanmc.priority = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 					vlanmc.fid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 				ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 				if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 					dev_err(smi->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 						"failed to remove VLAN %04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 						vid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 					return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) EXPORT_SYMBOL_GPL(rtl8366_vlan_del);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 			 uint8_t *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	struct rtl8366_mib_counter *mib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	if (port >= smi->num_ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	for (i = 0; i < smi->num_mib_counters; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 		mib = &smi->mib_counters[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		strncpy(data + i * ETH_GSTRING_LEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 			mib->name, ETH_GSTRING_LEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) EXPORT_SYMBOL_GPL(rtl8366_get_strings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	/* We only support SS_STATS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	if (sset != ETH_SS_STATS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	if (port >= smi->num_ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	return smi->num_mib_counters;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) EXPORT_SYMBOL_GPL(rtl8366_get_sset_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	struct realtek_smi *smi = ds->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 	if (port >= smi->num_ports)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	for (i = 0; i < smi->num_mib_counters; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 		struct rtl8366_mib_counter *mib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 		u64 mibvalue = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 		mib = &smi->mib_counters[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 		ret = smi->ops->get_mib_counter(smi, port, mib, &mibvalue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 			dev_err(smi->dev, "error reading MIB counter %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 				mib->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 		data[i] = mibvalue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats);