// SPDX-License-Identifier: GPL-2.0 /* Realtek SMI subdriver for the Realtek RTL8366RB ethernet switch * * This is a sparsely documented chip, the only viable documentation seems * to be a patched up code drop from the vendor that appear in various * GPL source trees. * * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv> * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
*/
/* VLAN Ingress Control Register 1, one bit per port. * bit 0 .. 5 will make the switch drop ingress frames without * VID such as untagged or priority-tagged frames for respective * port. * bit 6 .. 11 will make the switch drop ingress frames carrying * a C-tag with VID != 0 for respective port.
*/ #define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E #define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) + 6))
/* VLAN Ingress Control Register 2, one bit per port. * bit0 .. bit5 will make the switch drop all ingress frames with * a VLAN classification that does not include the port is in its * member set.
*/ #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f
#define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ #define RTL8366RB_PORT_2 BIT(1) /* In userspace port 1 */ #define RTL8366RB_PORT_3 BIT(2) /* In userspace port 2 */ #define RTL8366RB_PORT_4 BIT(3) /* In userspace port 3 */ #define RTL8366RB_PORT_5 BIT(4) /* In userspace port 4 */
/* First configuration word per member config, VID and prio */ #define RTL8366RB_VLAN_VID_MASK 0xfff #define RTL8366RB_VLAN_PRIORITY_SHIFT 12 #define RTL8366RB_VLAN_PRIORITY_MASK 0x7 /* Second configuration word per member config, member and untagged */ #define RTL8366RB_VLAN_UNTAG_SHIFT 8 #define RTL8366RB_VLAN_UNTAG_MASK 0xff #define RTL8366RB_VLAN_MEMBER_MASK 0xff /* Third config word per member config, STAG currently unused */ #define RTL8366RB_VLAN_STAG_MBR_MASK 0xff #define RTL8366RB_VLAN_STAG_MBR_SHIFT 8 #define RTL8366RB_VLAN_STAG_IDX_MASK 0x7 #define RTL8366RB_VLAN_STAG_IDX_SHIFT 5 #define RTL8366RB_VLAN_FID_MASK 0x7
/* Port ingress bandwidth control */ #define RTL8366RB_IB_BASE 0x0200 #define RTL8366RB_IB_REG(pnum) (RTL8366RB_IB_BASE + (pnum)) #define RTL8366RB_IB_BDTH_MASK 0x3fff #define RTL8366RB_IB_PREIFG BIT(14)
/* Writing access counter address first * then ASIC will prepare 64bits counter wait for being retrived
*/
ret = regmap_write(priv->map, addr, 0); /* Write whatever */ if (ret) return ret;
/* Read MIB control register */
ret = regmap_read(priv->map, RTL8366RB_MIB_CTRL_REG, &val); if (ret) return -EIO;
if (val & RTL8366RB_MIB_CTRL_BUSY_MASK) return -EBUSY;
if (val & RTL8366RB_MIB_CTRL_RESET_MASK) return -EIO;
/* Read each individual MIB 16 bits at the time */
*mibvalue = 0; for (i = mib->length; i > 0; i--) {
ret = regmap_read(priv->map, addr + (i - 1), &val); if (ret) return ret;
*mibvalue = (*mibvalue << 16) | (val & 0xFFFF);
} return 0;
}
static u32 rtl8366rb_get_irqmask(struct irq_data *d)
{ int line = irqd_to_hwirq(d);
u32 val;
/* For line interrupts we combine link down in bits * 6..11 with link up in bits 0..5 into one interrupt.
*/ if (line < 12)
val = BIT(line) | BIT(line + 6); else
val = BIT(line); return val;
}
ret = regmap_update_bits(priv->map, RTL8366RB_INTERRUPT_MASK_REG,
rtl8366rb_get_irqmask(d),
rtl8366rb_get_irqmask(d)); if (ret)
dev_err(priv->dev, "could not unmask IRQ\n");
}
/* This clears the IRQ status register */
ret = regmap_read(priv->map, RTL8366RB_INTERRUPT_STATUS_REG,
&stat); if (ret) {
dev_err(priv->dev, "can't read interrupt status\n"); return IRQ_NONE;
}
stat &= RTL8366RB_INTERRUPT_VALID; if (!stat) return IRQ_NONE; while (stat) { int line = __ffs(stat); int child_irq;
stat &= ~BIT(line); /* For line interrupts we combine link down in bits * 6..11 with link up in bits 0..5 into one interrupt.
*/ if (line < 12 && line > 5)
line -= 5;
child_irq = irq_find_mapping(priv->irqdomain, line);
handle_nested_irq(child_irq);
} return IRQ_HANDLED;
}
staticint rtl8366rb_setup_cascaded_irq(struct realtek_priv *priv)
{ struct device_node *intc; unsignedlong irq_trig; int irq; int ret;
u32 val; int i;
intc = of_get_child_by_name(priv->dev->of_node, "interrupt-controller"); if (!intc) {
dev_err(priv->dev, "missing child interrupt-controller node\n"); return -EINVAL;
} /* RB8366RB IRQs cascade off this one */
irq = of_irq_get(intc, 0); if (irq <= 0) {
dev_err(priv->dev, "failed to get parent IRQ\n");
ret = irq ? irq : -EINVAL; goto out_put_node;
}
/* This clears the IRQ status register */
ret = regmap_read(priv->map, RTL8366RB_INTERRUPT_STATUS_REG,
&val); if (ret) {
dev_err(priv->dev, "can't read interrupt status\n"); goto out_put_node;
}
/* Fetch IRQ edge information from the descriptor */
irq_trig = irq_get_trigger_type(irq); switch (irq_trig) { case IRQF_TRIGGER_RISING: case IRQF_TRIGGER_HIGH:
dev_info(priv->dev, "active high/rising IRQ\n");
val = 0; break; case IRQF_TRIGGER_FALLING: case IRQF_TRIGGER_LOW:
dev_info(priv->dev, "active low/falling IRQ\n");
val = RTL8366RB_INTERRUPT_POLARITY; break;
}
ret = regmap_update_bits(priv->map, RTL8366RB_INTERRUPT_CONTROL_REG,
RTL8366RB_INTERRUPT_POLARITY,
val); if (ret) {
dev_err(priv->dev, "could not configure IRQ polarity\n"); goto out_put_node;
}
ret = devm_request_threaded_irq(priv->dev, irq, NULL,
rtl8366rb_irq, IRQF_ONESHOT, "RTL8366RB", priv); if (ret) {
dev_err(priv->dev, "unable to request irq: %d\n", ret); goto out_put_node;
}
priv->irqdomain = irq_domain_create_linear(of_fwnode_handle(intc), RTL8366RB_NUM_INTERRUPT,
&rtl8366rb_irqdomain_ops, priv); if (!priv->irqdomain) {
dev_err(priv->dev, "failed to create IRQ domain\n");
ret = -EINVAL; goto out_put_node;
} for (i = 0; i < priv->num_ports; i++)
irq_set_parent(irq_create_mapping(priv->irqdomain, i), irq);
/* This jam table activates "green ethernet", which means low power mode * and is claimed to detect the cable length and not use more power than * necessary, and the ports should enter power saving mode 10 seconds after * a cable is disconnected. Seems to always be the same.
*/ staticconststruct rtl8366rb_jam_tbl_entry rtl8366rb_green_jam[] = {
{0xBE78, 0x323C}, {0xBE77, 0x5000}, {0xBE2E, 0x7BA7},
{0xBE59, 0x3459}, {0xBE5A, 0x745A}, {0xBE5B, 0x785C},
{0xBE5C, 0x785C}, {0xBE6E, 0xE120}, {0xBE79, 0x323C},
};
/* Function that jams the tables in the proper registers */ staticint rtl8366rb_jam_table(conststruct rtl8366rb_jam_tbl_entry *jam_table, int jam_size, struct realtek_priv *priv, bool write_dbg)
{
u32 val; int ret; int i;
for (i = 0; i < jam_size; i++) { if ((jam_table[i].reg & 0xBE00) == 0xBE00) {
ret = regmap_read(priv->map,
RTL8366RB_PHY_ACCESS_BUSY_REG,
&val); if (ret) return ret; if (!(val & RTL8366RB_PHY_INT_BUSY)) {
ret = regmap_write(priv->map,
RTL8366RB_PHY_ACCESS_CTRL_REG,
RTL8366RB_PHY_CTRL_WRITE); if (ret) return ret;
}
} if (write_dbg)
dev_dbg(priv->dev, "jam %04x into register %04x\n",
jam_table[i].val,
jam_table[i].reg);
ret = regmap_write(priv->map,
jam_table[i].reg,
jam_table[i].val); if (ret) return ret;
} return 0;
}
/* This code is used also with LEDs disabled */ int rb8366rb_set_ledgroup_mode(struct realtek_priv *priv,
u8 led_group, enum rtl8366_ledgroup_mode mode)
{ int ret;
u32 val;
val = mode << RTL8366RB_LED_CTRL_OFFSET(led_group);
ret = regmap_update_bits(priv->map,
RTL8366RB_LED_CTRL_REG,
RTL8366RB_LED_CTRL_MASK(led_group),
val); if (ret) return ret;
return 0;
}
/* This code is used also with LEDs disabled */ staticint rtl8366rb_setup_all_leds_off(struct realtek_priv *priv)
{ int ret = 0; int i;
for (i = 0; i < RTL8366RB_NUM_LEDGROUPS; i++) {
ret = rb8366rb_set_ledgroup_mode(priv, i,
RTL8366RB_LEDGROUP_OFF); if (ret) return ret;
}
return ret;
}
staticint rtl8366rb_setup(struct dsa_switch *ds)
{ struct realtek_priv *priv = ds->priv; conststruct rtl8366rb_jam_tbl_entry *jam_table; struct rtl8366rb *rb;
u32 chip_ver = 0;
u32 chip_id = 0; int jam_size; int ret; int i;
rb = priv->chip_data;
ret = regmap_read(priv->map, RTL8366RB_CHIP_ID_REG, &chip_id); if (ret) {
dev_err(priv->dev, "unable to read chip id\n"); return ret;
}
switch (chip_id) { case RTL8366RB_CHIP_ID_8366: break; default:
dev_err(priv->dev, "unknown chip id (%04x)\n", chip_id); return -ENODEV;
}
ret = regmap_read(priv->map, RTL8366RB_CHIP_VERSION_CTRL_REG,
&chip_ver); if (ret) {
dev_err(priv->dev, "unable to read chip version\n"); return ret;
}
dev_info(priv->dev, "RTL%04x ver %u chip found\n",
chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK);
/* Do the init dance using the right jam table */ switch (chip_ver) { case 0:
jam_table = rtl8366rb_init_jam_ver_0;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_0); break; case 1:
jam_table = rtl8366rb_init_jam_ver_1;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_1); break; case 2:
jam_table = rtl8366rb_init_jam_ver_2;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_2); break; default:
jam_table = rtl8366rb_init_jam_ver_3;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_3); break;
}
/* Special jam tables for special routers * TODO: are these necessary? Maintainers, please test * without them, using just the off-the-shelf tables.
*/ if (of_machine_is_compatible("belkin,f5d8235-v1")) {
jam_table = rtl8366rb_init_jam_f5d8235;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_f5d8235);
} if (of_machine_is_compatible("netgear,dgn3500") ||
of_machine_is_compatible("netgear,dgn3500b")) {
jam_table = rtl8366rb_init_jam_dgn3500;
jam_size = ARRAY_SIZE(rtl8366rb_init_jam_dgn3500);
}
ret = rtl8366rb_jam_table(jam_table, jam_size, priv, true); if (ret) return ret;
/* Isolate all user ports so they can only send packets to itself and the CPU port */ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) {
ret = regmap_write(priv->map, RTL8366RB_PORT_ISO(i),
RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) |
RTL8366RB_PORT_ISO_EN); if (ret) return ret;
} /* CPU port can send packets to all ports */
ret = regmap_write(priv->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU),
RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) |
RTL8366RB_PORT_ISO_EN); if (ret) return ret;
/* Set up the "green ethernet" feature */
ret = rtl8366rb_jam_table(rtl8366rb_green_jam,
ARRAY_SIZE(rtl8366rb_green_jam), priv, false); if (ret) return ret;
ret = regmap_write(priv->map,
RTL8366RB_GREEN_FEATURE_REG,
(chip_ver == 1) ? 0x0007 : 0x0003); if (ret) return ret;
/* Vendor driver sets 0x240 in registers 0xc and 0xd (undocumented) */
ret = regmap_write(priv->map, 0x0c, 0x240); if (ret) return ret;
ret = regmap_write(priv->map, 0x0d, 0x240); if (ret) return ret;
/* Set some random MAC address */
ret = rtl8366rb_set_addr(priv); if (ret) return ret;
/* Enable CPU port with custom DSA tag 8899. * * If you set RTL8366RB_CPU_NO_TAG (bit 15) in this register * the custom tag is turned off.
*/
ret = regmap_update_bits(priv->map, RTL8366RB_CPU_CTRL_REG,
0xFFFF,
BIT(priv->cpu_port)); if (ret) return ret;
/* Make sure we default-enable the fixed CPU port */
ret = regmap_update_bits(priv->map, RTL8366RB_PECR,
BIT(priv->cpu_port),
0); if (ret) return ret;
/* Set default maximum packet length to 1536 bytes */
ret = regmap_update_bits(priv->map, RTL8366RB_SGCR,
RTL8366RB_SGCR_MAX_LENGTH_MASK,
RTL8366RB_SGCR_MAX_LENGTH_1536); if (ret) return ret; for (i = 0; i < RTL8366RB_NUM_PORTS; i++) { if (i == priv->cpu_port) /* CPU port need to also accept the tag */
rb->max_mtu[i] = ETH_DATA_LEN + RTL8366RB_CPU_TAG_SIZE; else
rb->max_mtu[i] = ETH_DATA_LEN;
}
/* Disable learning for all ports */
ret = regmap_write(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
RTL8366RB_PORT_ALL); if (ret) return ret;
/* Enable auto ageing for all ports */
ret = regmap_write(priv->map, RTL8366RB_SECURITY_CTRL, 0); if (ret) return ret;
/* Port 4 setup: this enables Port 4, usually the WAN port, * common PHY IO mode is apparently mode 0, and this is not what * the port is initialized to. There is no explanation of the * IO modes in the Realtek source code, if your WAN port is * connected to something exotic such as fiber, then this might * be worth experimenting with.
*/
ret = regmap_update_bits(priv->map, RTL8366RB_PMC0,
RTL8366RB_PMC0_P4_IOMODE_MASK,
0 << RTL8366RB_PMC0_P4_IOMODE_SHIFT); if (ret) return ret;
/* Accept all packets by default, we enable filtering on-demand */
ret = regmap_write(priv->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
0); if (ret) return ret;
ret = regmap_write(priv->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
0); if (ret) return ret;
/* Don't drop packets whose DA has not been learned */
ret = regmap_update_bits(priv->map, RTL8366RB_SSCR2,
RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0); if (ret) return ret;
/* Set blinking, used by all LED groups using HW triggers. * TODO: make this configurable
*/
ret = regmap_update_bits(priv->map, RTL8366RB_LED_BLINKRATE_REG,
RTL8366RB_LED_BLINKRATE_MASK,
RTL8366RB_LED_BLINKRATE_56MS); if (ret) return ret;
/* Set up LED activity: * Each port has 4 LEDs on fixed groups. Each group shares the same * hardware trigger across all ports. LEDs can only be indiviually * controlled setting the LED group to fixed mode and using the driver * to toggle them LEDs on/off.
*/ if (priv->leds_disabled) {
ret = rtl8366rb_setup_all_leds_off(priv); if (ret) return ret;
} else {
ret = rtl8366rb_setup_leds(priv); if (ret) return ret;
}
ret = rtl8366_reset_vlan(priv); if (ret) return ret;
ret = rtl8366rb_setup_cascaded_irq(priv); if (ret)
dev_info(priv->dev, "no interrupt support\n");
ret = rtl83xx_setup_user_mdio(ds); if (ret) {
dev_err(priv->dev, "could not set up MDIO bus\n"); return -ENODEV;
}
return 0;
}
staticenum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp)
{ /* This switch uses the 4 byte protocol A Realtek DSA tag */ return DSA_TAG_PROTO_RTL4_A;
}
staticvoid
rtl8366rb_mac_link_up(struct phylink_config *config, struct phy_device *phydev, unsignedint mode, phy_interface_t interface, int speed, int duplex, bool tx_pause, bool rx_pause)
{ struct dsa_port *dp = dsa_phylink_to_port(config); struct realtek_priv *priv = dp->ds->priv; int port = dp->index; unsignedint val; int ret;
/* Allow forcing the mode on the fixed CPU port, no autonegotiation. * We assume autonegotiation works on the PHY-facing ports.
*/ if (port != priv->cpu_port) return;
dev_dbg(priv->dev, "MAC link up on CPU port (%d)\n", port);
ret = regmap_update_bits(priv->map, RTL8366RB_MAC_FORCE_CTRL_REG,
BIT(port), BIT(port)); if (ret) {
dev_err(priv->dev, "failed to force CPU port\n"); return;
}
/* Conjure port config */ switch (speed) { case SPEED_10:
val = RTL8366RB_PAACR_SPEED_10M; break; case SPEED_100:
val = RTL8366RB_PAACR_SPEED_100M; break; case SPEED_1000:
val = RTL8366RB_PAACR_SPEED_1000M; break; default:
val = RTL8366RB_PAACR_SPEED_1000M; break;
}
if (duplex == DUPLEX_FULL)
val |= RTL8366RB_PAACR_FULL_DUPLEX;
if (tx_pause)
val |= RTL8366RB_PAACR_TX_PAUSE;
if (rx_pause)
val |= RTL8366RB_PAACR_RX_PAUSE;
val |= RTL8366RB_PAACR_LINK_UP;
ret = regmap_update_bits(priv->map, RTL8366RB_PAACR2,
0xFF00U,
val << 8); if (ret) {
dev_err(priv->dev, "failed to set PAACR on CPU port\n"); return;
}
dev_dbg(priv->dev, "set PAACR to %04x\n", val);
/* Enable the CPU port */
ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
0); if (ret) {
dev_err(priv->dev, "failed to enable the CPU port\n"); return;
}
}
staticvoid
rtl8366rb_mac_link_down(struct phylink_config *config, unsignedint mode,
phy_interface_t interface)
{ struct dsa_port *dp = dsa_phylink_to_port(config); struct realtek_priv *priv = dp->ds->priv; int port = dp->index; int ret;
if (port != priv->cpu_port) return;
dev_dbg(priv->dev, "MAC link down on CPU port (%d)\n", port);
/* Disable the CPU port */
ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
BIT(port)); if (ret) {
dev_err(priv->dev, "failed to disable the CPU port\n"); return;
}
}
staticint
rtl8366rb_port_enable(struct dsa_switch *ds, int port, struct phy_device *phy)
{ struct realtek_priv *priv = ds->priv; int ret;
dev_dbg(priv->dev, "enable port %d\n", port);
ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
0); if (ret) return ret;
return 0;
}
staticvoid
rtl8366rb_port_disable(struct dsa_switch *ds, int port)
{ struct realtek_priv *priv = ds->priv; int ret;
dev_dbg(priv->dev, "disable port %d\n", port);
ret = regmap_update_bits(priv->map, RTL8366RB_PECR, BIT(port),
BIT(port)); if (ret) return;
}
/* Loop over all other ports than the current one */ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { /* Current port handled last */ if (i == port) continue; /* Not on this bridge */ if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge)) continue; /* Join this port to each other port on the bridge */
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(i),
RTL8366RB_PORT_ISO_PORTS(BIT(port)),
RTL8366RB_PORT_ISO_PORTS(BIT(port))); if (ret)
dev_err(priv->dev, "failed to join port %d\n", port);
port_bitmap |= BIT(i);
}
/* Set the bits for the ports we can access */ return regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
RTL8366RB_PORT_ISO_PORTS(port_bitmap),
RTL8366RB_PORT_ISO_PORTS(port_bitmap));
}
/* Loop over all other ports than this one */ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { /* Current port handled last */ if (i == port) continue; /* Not on this bridge */ if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge)) continue; /* Remove this port from any other port on the bridge */
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(i),
RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0); if (ret)
dev_err(priv->dev, "failed to leave port %d\n", port);
port_bitmap |= BIT(i);
}
/* Clear the bits for the ports we can not access, leave ourselves */
regmap_update_bits(priv->map, RTL8366RB_PORT_ISO(port),
RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0);
}
/** * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames * @priv: SMI state container * @port: the port to drop untagged and C-tagged frames on * @drop: whether to drop or pass untagged and C-tagged frames * * Return: zero for success, a negative number on error.
*/ staticint rtl8366rb_drop_untagged(struct realtek_priv *priv, int port, bool drop)
{ return regmap_update_bits(priv->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG,
RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port),
drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0);
}
/* If the port is not in the member set, the frame will be dropped */
ret = regmap_update_bits(priv->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
BIT(port), vlan_filtering ? BIT(port) : 0); if (ret) return ret;
/* If VLAN filtering is enabled and PVID is also enabled, we must * not drop any untagged or C-tagged frames. If we turn off VLAN * filtering on a port, we need to accept any frames.
*/ if (vlan_filtering)
ret = rtl8366rb_drop_untagged(priv, port, !rb->pvid_enabled[port]); else
ret = rtl8366rb_drop_untagged(priv, port, false);
return ret;
}
staticint
rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack)
{ /* We support enabling/disabling learning */ if (flags.mask & ~(BR_LEARNING)) return -EINVAL;
return 0;
}
staticint
rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, struct switchdev_brport_flags flags, struct netlink_ext_ack *extack)
{ struct realtek_priv *priv = ds->priv; int ret;
if (flags.mask & BR_LEARNING) {
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
BIT(port),
(flags.val & BR_LEARNING) ? 0 : BIT(port)); if (ret) return ret;
}
return 0;
}
staticvoid
rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
{ struct realtek_priv *priv = ds->priv;
u32 val; int i;
switch (state) { case BR_STATE_DISABLED:
val = RTL8366RB_STP_STATE_DISABLED; break; case BR_STATE_BLOCKING: case BR_STATE_LISTENING:
val = RTL8366RB_STP_STATE_BLOCKING; break; case BR_STATE_LEARNING:
val = RTL8366RB_STP_STATE_LEARNING; break; case BR_STATE_FORWARDING:
val = RTL8366RB_STP_STATE_FORWARDING; break; default:
dev_err(priv->dev, "unknown bridge state requested\n"); return;
}
/* Set the same status for the port on all the FIDs */ for (i = 0; i < RTL8366RB_NUM_FIDS; i++) {
regmap_update_bits(priv->map, RTL8366RB_STP_STATE_BASE + i,
RTL8366RB_STP_STATE_MASK(port),
RTL8366RB_STP_STATE(port, val));
}
}
/* This will age out any learned L2 entries */
regmap_update_bits(priv->map, RTL8366RB_SECURITY_CTRL,
BIT(port), BIT(port)); /* Restore the normal state of things */
regmap_update_bits(priv->map, RTL8366RB_SECURITY_CTRL,
BIT(port), 0);
}
staticint rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{ struct realtek_priv *priv = ds->priv; struct rtl8366rb *rb; unsignedint max_mtu;
u32 len; int i;
/* Cache the per-port MTU setting */
rb = priv->chip_data;
rb->max_mtu[port] = new_mtu;
/* Roof out the MTU for the entire switch to the greatest * common denominator: the biggest set for any one port will * be the biggest MTU for the switch.
*/
max_mtu = ETH_DATA_LEN; for (i = 0; i < RTL8366RB_NUM_PORTS; i++) { if (rb->max_mtu[i] > max_mtu)
max_mtu = rb->max_mtu[i];
}
/* Translate to layer 2 size. * Add ethernet and (possible) VLAN headers, and checksum to the size. * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes.
*/
max_mtu += VLAN_ETH_HLEN;
max_mtu += ETH_FCS_LEN;
if (max_mtu <= 1522)
len = RTL8366RB_SGCR_MAX_LENGTH_1522; elseif (max_mtu > 1522 && max_mtu <= 1536) /* This will be the most common default if using VLAN and * CPU tagging on a port as both VLAN and CPU tag will * result in 1518 + 4 + 4 = 1526 bytes.
*/
len = RTL8366RB_SGCR_MAX_LENGTH_1536; elseif (max_mtu > 1536 && max_mtu <= 1552)
len = RTL8366RB_SGCR_MAX_LENGTH_1552; else
len = RTL8366RB_SGCR_MAX_LENGTH_16000;
staticint rtl8366rb_max_mtu(struct dsa_switch *ds, int port)
{ /* The max MTU is 16000 bytes, so we subtract the ethernet * headers with VLAN and checksum and arrive at * 16000 - 18 - 4 = 15978. This does not include the CPU tag * since that is added to the requested MTU by the DSA framework.
*/ return 16000 - VLAN_ETH_HLEN - ETH_FCS_LEN;
}
staticint rtl8366rb_get_vlan_4k(struct realtek_priv *priv, u32 vid, struct rtl8366_vlan_4k *vlan4k)
{
u32 data[3]; int ret; int i;
/* write VID */
ret = regmap_write(priv->map, RTL8366RB_VLAN_TABLE_WRITE_BASE,
vid & RTL8366RB_VLAN_VID_MASK); if (ret) return ret;
/* write table access control word */
ret = regmap_write(priv->map, RTL8366RB_TABLE_ACCESS_CTRL_REG,
RTL8366RB_TABLE_VLAN_READ_CTRL); if (ret) return ret;
for (i = 0; i < 3; i++) {
ret = regmap_read(priv->map,
RTL8366RB_VLAN_TABLE_READ_BASE + i,
&data[i]); if (ret) return ret;
}
staticint rtl8366rb_set_mc_index(struct realtek_priv *priv, int port, int index)
{ struct dsa_switch *ds = &priv->ds; struct rtl8366rb *rb; bool pvid_enabled; int ret;
rb = priv->chip_data;
pvid_enabled = !!index;
if (port >= priv->num_ports || index >= RTL8366RB_NUM_VLANS) return -EINVAL;
ret = regmap_update_bits(priv->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
RTL8366RB_PORT_VLAN_CTRL_MASK <<
RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
(index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); if (ret) return ret;
rb->pvid_enabled[port] = pvid_enabled;
/* If VLAN filtering is enabled and PVID is also enabled, we must * not drop any untagged or C-tagged frames. Make sure to update the * filtering setting.
*/ if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port)))
ret = rtl8366rb_drop_untagged(priv, port, !pvid_enabled);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.