rtl8366-core.c (10421B)
1// SPDX-License-Identifier: GPL-2.0 2/* Realtek SMI library helpers for the RTL8366x variants 3 * RTL8366RB and RTL8366S 4 * 5 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 6 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> 7 * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> 8 * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv> 9 * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com> 10 */ 11#include <linux/if_bridge.h> 12#include <net/dsa.h> 13 14#include "realtek.h" 15 16int rtl8366_mc_is_used(struct realtek_priv *priv, int mc_index, int *used) 17{ 18 int ret; 19 int i; 20 21 *used = 0; 22 for (i = 0; i < priv->num_ports; i++) { 23 int index = 0; 24 25 ret = priv->ops->get_mc_index(priv, i, &index); 26 if (ret) 27 return ret; 28 29 if (mc_index == index) { 30 *used = 1; 31 break; 32 } 33 } 34 35 return 0; 36} 37EXPORT_SYMBOL_GPL(rtl8366_mc_is_used); 38 39/** 40 * rtl8366_obtain_mc() - retrieve or allocate a VLAN member configuration 41 * @priv: the Realtek SMI device instance 42 * @vid: the VLAN ID to look up or allocate 43 * @vlanmc: the pointer will be assigned to a pointer to a valid member config 44 * if successful 45 * @return: index of a new member config or negative error number 46 */ 47static int rtl8366_obtain_mc(struct realtek_priv *priv, int vid, 48 struct rtl8366_vlan_mc *vlanmc) 49{ 50 struct rtl8366_vlan_4k vlan4k; 51 int ret; 52 int i; 53 54 /* Try to find an existing member config entry for this VID */ 55 for (i = 0; i < priv->num_vlan_mc; i++) { 56 ret = priv->ops->get_vlan_mc(priv, i, vlanmc); 57 if (ret) { 58 dev_err(priv->dev, "error searching for VLAN MC %d for VID %d\n", 59 i, vid); 60 return ret; 61 } 62 63 if (vid == vlanmc->vid) 64 return i; 65 } 66 67 /* We have no MC entry for this VID, try to find an empty one */ 68 for (i = 0; i < priv->num_vlan_mc; i++) { 69 ret = priv->ops->get_vlan_mc(priv, i, vlanmc); 70 if (ret) { 71 dev_err(priv->dev, "error searching for VLAN MC %d for VID %d\n", 72 i, vid); 73 return ret; 74 } 75 76 if (vlanmc->vid == 0 && vlanmc->member == 0) { 77 /* Update the entry from the 4K table */ 78 ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k); 79 if (ret) { 80 dev_err(priv->dev, "error looking for 4K VLAN MC %d for VID %d\n", 81 i, vid); 82 return ret; 83 } 84 85 vlanmc->vid = vid; 86 vlanmc->member = vlan4k.member; 87 vlanmc->untag = vlan4k.untag; 88 vlanmc->fid = vlan4k.fid; 89 ret = priv->ops->set_vlan_mc(priv, i, vlanmc); 90 if (ret) { 91 dev_err(priv->dev, "unable to set/update VLAN MC %d for VID %d\n", 92 i, vid); 93 return ret; 94 } 95 96 dev_dbg(priv->dev, "created new MC at index %d for VID %d\n", 97 i, vid); 98 return i; 99 } 100 } 101 102 /* MC table is full, try to find an unused entry and replace it */ 103 for (i = 0; i < priv->num_vlan_mc; i++) { 104 int used; 105 106 ret = rtl8366_mc_is_used(priv, i, &used); 107 if (ret) 108 return ret; 109 110 if (!used) { 111 /* Update the entry from the 4K table */ 112 ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k); 113 if (ret) 114 return ret; 115 116 vlanmc->vid = vid; 117 vlanmc->member = vlan4k.member; 118 vlanmc->untag = vlan4k.untag; 119 vlanmc->fid = vlan4k.fid; 120 ret = priv->ops->set_vlan_mc(priv, i, vlanmc); 121 if (ret) { 122 dev_err(priv->dev, "unable to set/update VLAN MC %d for VID %d\n", 123 i, vid); 124 return ret; 125 } 126 dev_dbg(priv->dev, "recycled MC at index %i for VID %d\n", 127 i, vid); 128 return i; 129 } 130 } 131 132 dev_err(priv->dev, "all VLAN member configurations are in use\n"); 133 return -ENOSPC; 134} 135 136int rtl8366_set_vlan(struct realtek_priv *priv, int vid, u32 member, 137 u32 untag, u32 fid) 138{ 139 struct rtl8366_vlan_mc vlanmc; 140 struct rtl8366_vlan_4k vlan4k; 141 int mc; 142 int ret; 143 144 if (!priv->ops->is_vlan_valid(priv, vid)) 145 return -EINVAL; 146 147 dev_dbg(priv->dev, 148 "setting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", 149 vid, member, untag); 150 151 /* Update the 4K table */ 152 ret = priv->ops->get_vlan_4k(priv, vid, &vlan4k); 153 if (ret) 154 return ret; 155 156 vlan4k.member |= member; 157 vlan4k.untag |= untag; 158 vlan4k.fid = fid; 159 ret = priv->ops->set_vlan_4k(priv, &vlan4k); 160 if (ret) 161 return ret; 162 163 dev_dbg(priv->dev, 164 "resulting VLAN%d 4k members: 0x%02x, untagged: 0x%02x\n", 165 vid, vlan4k.member, vlan4k.untag); 166 167 /* Find or allocate a member config for this VID */ 168 ret = rtl8366_obtain_mc(priv, vid, &vlanmc); 169 if (ret < 0) 170 return ret; 171 mc = ret; 172 173 /* Update the MC entry */ 174 vlanmc.member |= member; 175 vlanmc.untag |= untag; 176 vlanmc.fid = fid; 177 178 /* Commit updates to the MC entry */ 179 ret = priv->ops->set_vlan_mc(priv, mc, &vlanmc); 180 if (ret) 181 dev_err(priv->dev, "failed to commit changes to VLAN MC index %d for VID %d\n", 182 mc, vid); 183 else 184 dev_dbg(priv->dev, 185 "resulting VLAN%d MC members: 0x%02x, untagged: 0x%02x\n", 186 vid, vlanmc.member, vlanmc.untag); 187 188 return ret; 189} 190EXPORT_SYMBOL_GPL(rtl8366_set_vlan); 191 192int rtl8366_set_pvid(struct realtek_priv *priv, unsigned int port, 193 unsigned int vid) 194{ 195 struct rtl8366_vlan_mc vlanmc; 196 int mc; 197 int ret; 198 199 if (!priv->ops->is_vlan_valid(priv, vid)) 200 return -EINVAL; 201 202 /* Find or allocate a member config for this VID */ 203 ret = rtl8366_obtain_mc(priv, vid, &vlanmc); 204 if (ret < 0) 205 return ret; 206 mc = ret; 207 208 ret = priv->ops->set_mc_index(priv, port, mc); 209 if (ret) { 210 dev_err(priv->dev, "set PVID: failed to set MC index %d for port %d\n", 211 mc, port); 212 return ret; 213 } 214 215 dev_dbg(priv->dev, "set PVID: the PVID for port %d set to %d using existing MC index %d\n", 216 port, vid, mc); 217 218 return 0; 219} 220EXPORT_SYMBOL_GPL(rtl8366_set_pvid); 221 222int rtl8366_enable_vlan4k(struct realtek_priv *priv, bool enable) 223{ 224 int ret; 225 226 /* To enable 4k VLAN, ordinary VLAN must be enabled first, 227 * but if we disable 4k VLAN it is fine to leave ordinary 228 * VLAN enabled. 229 */ 230 if (enable) { 231 /* Make sure VLAN is ON */ 232 ret = priv->ops->enable_vlan(priv, true); 233 if (ret) 234 return ret; 235 236 priv->vlan_enabled = true; 237 } 238 239 ret = priv->ops->enable_vlan4k(priv, enable); 240 if (ret) 241 return ret; 242 243 priv->vlan4k_enabled = enable; 244 return 0; 245} 246EXPORT_SYMBOL_GPL(rtl8366_enable_vlan4k); 247 248int rtl8366_enable_vlan(struct realtek_priv *priv, bool enable) 249{ 250 int ret; 251 252 ret = priv->ops->enable_vlan(priv, enable); 253 if (ret) 254 return ret; 255 256 priv->vlan_enabled = enable; 257 258 /* If we turn VLAN off, make sure that we turn off 259 * 4k VLAN as well, if that happened to be on. 260 */ 261 if (!enable) { 262 priv->vlan4k_enabled = false; 263 ret = priv->ops->enable_vlan4k(priv, false); 264 } 265 266 return ret; 267} 268EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); 269 270int rtl8366_reset_vlan(struct realtek_priv *priv) 271{ 272 struct rtl8366_vlan_mc vlanmc; 273 int ret; 274 int i; 275 276 rtl8366_enable_vlan(priv, false); 277 rtl8366_enable_vlan4k(priv, false); 278 279 /* Clear the 16 VLAN member configurations */ 280 vlanmc.vid = 0; 281 vlanmc.priority = 0; 282 vlanmc.member = 0; 283 vlanmc.untag = 0; 284 vlanmc.fid = 0; 285 for (i = 0; i < priv->num_vlan_mc; i++) { 286 ret = priv->ops->set_vlan_mc(priv, i, &vlanmc); 287 if (ret) 288 return ret; 289 } 290 291 return 0; 292} 293EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); 294 295int rtl8366_vlan_add(struct dsa_switch *ds, int port, 296 const struct switchdev_obj_port_vlan *vlan, 297 struct netlink_ext_ack *extack) 298{ 299 bool untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); 300 bool pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID); 301 struct realtek_priv *priv = ds->priv; 302 u32 member = 0; 303 u32 untag = 0; 304 int ret; 305 306 if (!priv->ops->is_vlan_valid(priv, vlan->vid)) { 307 NL_SET_ERR_MSG_MOD(extack, "VLAN ID not valid"); 308 return -EINVAL; 309 } 310 311 /* Enable VLAN in the hardware 312 * FIXME: what's with this 4k business? 313 * Just rtl8366_enable_vlan() seems inconclusive. 314 */ 315 ret = rtl8366_enable_vlan4k(priv, true); 316 if (ret) { 317 NL_SET_ERR_MSG_MOD(extack, "Failed to enable VLAN 4K"); 318 return ret; 319 } 320 321 dev_dbg(priv->dev, "add VLAN %d on port %d, %s, %s\n", 322 vlan->vid, port, untagged ? "untagged" : "tagged", 323 pvid ? "PVID" : "no PVID"); 324 325 member |= BIT(port); 326 327 if (untagged) 328 untag |= BIT(port); 329 330 ret = rtl8366_set_vlan(priv, vlan->vid, member, untag, 0); 331 if (ret) { 332 dev_err(priv->dev, "failed to set up VLAN %04x", vlan->vid); 333 return ret; 334 } 335 336 if (!pvid) 337 return 0; 338 339 ret = rtl8366_set_pvid(priv, port, vlan->vid); 340 if (ret) { 341 dev_err(priv->dev, "failed to set PVID on port %d to VLAN %04x", 342 port, vlan->vid); 343 return ret; 344 } 345 346 return 0; 347} 348EXPORT_SYMBOL_GPL(rtl8366_vlan_add); 349 350int rtl8366_vlan_del(struct dsa_switch *ds, int port, 351 const struct switchdev_obj_port_vlan *vlan) 352{ 353 struct realtek_priv *priv = ds->priv; 354 int ret, i; 355 356 dev_dbg(priv->dev, "del VLAN %d on port %d\n", vlan->vid, port); 357 358 for (i = 0; i < priv->num_vlan_mc; i++) { 359 struct rtl8366_vlan_mc vlanmc; 360 361 ret = priv->ops->get_vlan_mc(priv, i, &vlanmc); 362 if (ret) 363 return ret; 364 365 if (vlan->vid == vlanmc.vid) { 366 /* Remove this port from the VLAN */ 367 vlanmc.member &= ~BIT(port); 368 vlanmc.untag &= ~BIT(port); 369 /* 370 * If no ports are members of this VLAN 371 * anymore then clear the whole member 372 * config so it can be reused. 373 */ 374 if (!vlanmc.member) { 375 vlanmc.vid = 0; 376 vlanmc.priority = 0; 377 vlanmc.fid = 0; 378 } 379 ret = priv->ops->set_vlan_mc(priv, i, &vlanmc); 380 if (ret) { 381 dev_err(priv->dev, 382 "failed to remove VLAN %04x\n", 383 vlan->vid); 384 return ret; 385 } 386 break; 387 } 388 } 389 390 return 0; 391} 392EXPORT_SYMBOL_GPL(rtl8366_vlan_del); 393 394void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset, 395 uint8_t *data) 396{ 397 struct realtek_priv *priv = ds->priv; 398 struct rtl8366_mib_counter *mib; 399 int i; 400 401 if (port >= priv->num_ports) 402 return; 403 404 for (i = 0; i < priv->num_mib_counters; i++) { 405 mib = &priv->mib_counters[i]; 406 strncpy(data + i * ETH_GSTRING_LEN, 407 mib->name, ETH_GSTRING_LEN); 408 } 409} 410EXPORT_SYMBOL_GPL(rtl8366_get_strings); 411 412int rtl8366_get_sset_count(struct dsa_switch *ds, int port, int sset) 413{ 414 struct realtek_priv *priv = ds->priv; 415 416 /* We only support SS_STATS */ 417 if (sset != ETH_SS_STATS) 418 return 0; 419 if (port >= priv->num_ports) 420 return -EINVAL; 421 422 return priv->num_mib_counters; 423} 424EXPORT_SYMBOL_GPL(rtl8366_get_sset_count); 425 426void rtl8366_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data) 427{ 428 struct realtek_priv *priv = ds->priv; 429 int i; 430 int ret; 431 432 if (port >= priv->num_ports) 433 return; 434 435 for (i = 0; i < priv->num_mib_counters; i++) { 436 struct rtl8366_mib_counter *mib; 437 u64 mibvalue = 0; 438 439 mib = &priv->mib_counters[i]; 440 ret = priv->ops->get_mib_counter(priv, port, mib, &mibvalue); 441 if (ret) { 442 dev_err(priv->dev, "error reading MIB counter %s\n", 443 mib->name); 444 } 445 data[i] = mibvalue; 446 } 447} 448EXPORT_SYMBOL_GPL(rtl8366_get_ethtool_stats);