Commit e0b2e0d8 authored by Linus Walleij's avatar Linus Walleij Committed by Jakub Kicinski

net: dsa: rtl8366rb: Roof MTU for switch

The MTU setting for this DSA switch is global so we need
to keep track of the MTU set for each port, then as soon
as any MTU changes, roof the MTU to the biggest common
denominator and poke that into the switch MTU setting.

To achieve this we need a per-chip-variant state container
for the RTL8366RB to use for the RTL8366RB-specific
stuff. Other SMI switches does seem to have per-port
MTU setting capabilities.

Fixes: 5f4a8ef3 ("net: dsa: rtl8366rb: Support setting MTU")
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 14b26b12
...@@ -394,9 +394,10 @@ static int realtek_smi_probe(struct platform_device *pdev) ...@@ -394,9 +394,10 @@ static int realtek_smi_probe(struct platform_device *pdev)
var = of_device_get_match_data(dev); var = of_device_get_match_data(dev);
np = dev->of_node; np = dev->of_node;
smi = devm_kzalloc(dev, sizeof(*smi), GFP_KERNEL); smi = devm_kzalloc(dev, sizeof(*smi) + var->chip_data_sz, GFP_KERNEL);
if (!smi) if (!smi)
return -ENOMEM; return -ENOMEM;
smi->chip_data = (void *)smi + sizeof(*smi);
smi->map = devm_regmap_init(dev, NULL, smi, smi->map = devm_regmap_init(dev, NULL, smi,
&realtek_smi_mdio_regmap_config); &realtek_smi_mdio_regmap_config);
if (IS_ERR(smi->map)) { if (IS_ERR(smi->map)) {
......
...@@ -71,6 +71,7 @@ struct realtek_smi { ...@@ -71,6 +71,7 @@ struct realtek_smi {
int vlan4k_enabled; int vlan4k_enabled;
char buf[4096]; char buf[4096];
void *chip_data; /* Per-chip extra variant data */
}; };
/** /**
...@@ -111,6 +112,7 @@ struct realtek_smi_variant { ...@@ -111,6 +112,7 @@ struct realtek_smi_variant {
unsigned int clk_delay; unsigned int clk_delay;
u8 cmd_read; u8 cmd_read;
u8 cmd_write; u8 cmd_write;
size_t chip_data_sz;
}; };
/* SMI core calls */ /* SMI core calls */
......
...@@ -311,6 +311,14 @@ ...@@ -311,6 +311,14 @@
#define RTL8366RB_GREEN_FEATURE_TX BIT(0) #define RTL8366RB_GREEN_FEATURE_TX BIT(0)
#define RTL8366RB_GREEN_FEATURE_RX BIT(2) #define RTL8366RB_GREEN_FEATURE_RX BIT(2)
/**
* struct rtl8366rb - RTL8366RB-specific data
* @max_mtu: per-port max MTU setting
*/
struct rtl8366rb {
unsigned int max_mtu[RTL8366RB_NUM_PORTS];
};
static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
{ 0, 0, 4, "IfInOctets" }, { 0, 0, 4, "IfInOctets" },
{ 0, 4, 4, "EtherStatsOctets" }, { 0, 4, 4, "EtherStatsOctets" },
...@@ -712,6 +720,7 @@ static int rtl8366rb_setup(struct dsa_switch *ds) ...@@ -712,6 +720,7 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
{ {
struct realtek_smi *smi = ds->priv; struct realtek_smi *smi = ds->priv;
const u16 *jam_table; const u16 *jam_table;
struct rtl8366rb *rb;
u32 chip_ver = 0; u32 chip_ver = 0;
u32 chip_id = 0; u32 chip_id = 0;
int jam_size; int jam_size;
...@@ -719,6 +728,8 @@ static int rtl8366rb_setup(struct dsa_switch *ds) ...@@ -719,6 +728,8 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
int ret; int ret;
int i; int i;
rb = smi->chip_data;
ret = regmap_read(smi->map, RTL8366RB_CHIP_ID_REG, &chip_id); ret = regmap_read(smi->map, RTL8366RB_CHIP_ID_REG, &chip_id);
if (ret) { if (ret) {
dev_err(smi->dev, "unable to read chip id\n"); dev_err(smi->dev, "unable to read chip id\n");
...@@ -868,6 +879,9 @@ static int rtl8366rb_setup(struct dsa_switch *ds) ...@@ -868,6 +879,9 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
RTL8366RB_SGCR_MAX_LENGTH_1536); RTL8366RB_SGCR_MAX_LENGTH_1536);
if (ret) if (ret)
return ret; return ret;
for (i = 0; i < RTL8366RB_NUM_PORTS; i++)
/* layer 2 size, see rtl8366rb_change_mtu() */
rb->max_mtu[i] = 1532;
/* Enable learning for all ports */ /* Enable learning for all ports */
ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0); ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0);
...@@ -1109,20 +1123,36 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port) ...@@ -1109,20 +1123,36 @@ rtl8366rb_port_disable(struct dsa_switch *ds, int port)
static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{ {
struct realtek_smi *smi = ds->priv; struct realtek_smi *smi = ds->priv;
struct rtl8366rb *rb;
unsigned int max_mtu;
u32 len; u32 len;
int i;
/* Cache the per-port MTU setting */
rb = smi->chip_data;
rb->max_mtu[port] = new_mtu;
/* The first setting, 1522 bytes, is max IP packet 1500 bytes, /* 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.
*
* The first setting, 1522 bytes, is max IP packet 1500 bytes,
* plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes. * plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes.
* This function should consider the parameter an SDU, so the * This function should consider the parameter an SDU, so the
* MTU passed for this setting is 1518 bytes. The same logic * MTU passed for this setting is 1518 bytes. The same logic
* of subtracting the DSA tag of 4 bytes apply to the other * of subtracting the DSA tag of 4 bytes apply to the other
* settings. * settings.
*/ */
if (new_mtu <= 1518) max_mtu = 1518;
for (i = 0; i < RTL8366RB_NUM_PORTS; i++) {
if (rb->max_mtu[i] > max_mtu)
max_mtu = rb->max_mtu[i];
}
if (max_mtu <= 1518)
len = RTL8366RB_SGCR_MAX_LENGTH_1522; len = RTL8366RB_SGCR_MAX_LENGTH_1522;
else if (new_mtu > 1518 && new_mtu <= 1532) else if (max_mtu > 1518 && max_mtu <= 1532)
len = RTL8366RB_SGCR_MAX_LENGTH_1536; len = RTL8366RB_SGCR_MAX_LENGTH_1536;
else if (new_mtu > 1532 && new_mtu <= 1548) else if (max_mtu > 1532 && max_mtu <= 1548)
len = RTL8366RB_SGCR_MAX_LENGTH_1552; len = RTL8366RB_SGCR_MAX_LENGTH_1552;
else else
len = RTL8366RB_SGCR_MAX_LENGTH_16000; len = RTL8366RB_SGCR_MAX_LENGTH_16000;
...@@ -1505,5 +1535,6 @@ const struct realtek_smi_variant rtl8366rb_variant = { ...@@ -1505,5 +1535,6 @@ const struct realtek_smi_variant rtl8366rb_variant = {
.clk_delay = 10, .clk_delay = 10,
.cmd_read = 0xa9, .cmd_read = 0xa9,
.cmd_write = 0xa8, .cmd_write = 0xa8,
.chip_data_sz = sizeof(struct rtl8366rb),
}; };
EXPORT_SYMBOL_GPL(rtl8366rb_variant); EXPORT_SYMBOL_GPL(rtl8366rb_variant);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment