root/drivers/net/dsa/rtl8366.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtl8366_mc_is_used
  2. rtl8366_set_vlan
  3. rtl8366_get_pvid
  4. rtl8366_set_pvid
  5. rtl8366_enable_vlan4k
  6. rtl8366_enable_vlan
  7. rtl8366_reset_vlan
  8. rtl8366_init_vlan
  9. rtl8366_vlan_filtering
  10. rtl8366_vlan_prepare
  11. rtl8366_vlan_add
  12. rtl8366_vlan_del
  13. rtl8366_get_strings
  14. rtl8366_get_sset_count
  15. rtl8366_get_ethtool_stats

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

/* [<][>][^][v][top][bottom][index][help] */