cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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