^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);