Skip to content

Commit

Permalink
Merge branch 'DSA-mtu'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
Configure the MTU on DSA switches

This series adds support for configuring the MTU on front-panel switch
ports, while seamlessly adapting the CPU port and the DSA master to the
largest value plus the tagger overhead.

It also implements bridge MTU auto-normalization within the DSA core, as
resulted after the feedback of the implementation of this feature inside
the bridge driver in v2.

Support was added for quite a number of switches, in the hope that this
series would gain some traction:
 - sja1105
 - felix
 - vsc73xx
 - b53 and rest of the platform

V3 of this series was submitted here:
https://patchwork.ozlabs.org/cover/1262394/

V2 of this series was submitted here:
https://patchwork.ozlabs.org/cover/1261471/

V1 of this series was submitted here:
https://patchwork.ozlabs.org/cover/1199868/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 27, 2020
2 parents 22f3397 + 0b912fc commit 1a147b7
Show file tree
Hide file tree
Showing 20 changed files with 500 additions and 48 deletions.
27 changes: 22 additions & 5 deletions drivers/net/dsa/b53/b53_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,6 @@ int b53_configure_vlan(struct dsa_switch *ds)
b53_write16(dev, B53_VLAN_PAGE,
B53_VLAN_PORT_DEF_TAG(i), def_vid);

if (!is5325(dev) && !is5365(dev))
b53_set_jumbo(dev, dev->enable_jumbo, false);

return 0;
}
EXPORT_SYMBOL(b53_configure_vlan);
Expand Down Expand Up @@ -807,8 +804,6 @@ static int b53_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
static int b53_reset_switch(struct b53_device *priv)
{
/* reset vlans */
priv->enable_jumbo = false;

memset(priv->vlans, 0, sizeof(*priv->vlans) * priv->num_vlans);
memset(priv->ports, 0, sizeof(*priv->ports) * priv->num_ports);

Expand Down Expand Up @@ -2065,6 +2060,26 @@ int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e)
}
EXPORT_SYMBOL(b53_set_mac_eee);

static int b53_change_mtu(struct dsa_switch *ds, int port, int mtu)
{
struct b53_device *dev = ds->priv;
bool enable_jumbo;
bool allow_10_100;

if (is5325(dev) || is5365(dev))
return -EOPNOTSUPP;

enable_jumbo = (mtu >= JMS_MIN_SIZE);
allow_10_100 = (dev->chip_id == BCM583XX_DEVICE_ID);

return b53_set_jumbo(dev, enable_jumbo, allow_10_100);
}

static int b53_get_max_mtu(struct dsa_switch *ds, int port)
{
return JMS_MAX_SIZE;
}

static const struct dsa_switch_ops b53_switch_ops = {
.get_tag_protocol = b53_get_tag_protocol,
.setup = b53_setup,
Expand Down Expand Up @@ -2102,6 +2117,8 @@ static const struct dsa_switch_ops b53_switch_ops = {
.port_mdb_prepare = b53_mdb_prepare,
.port_mdb_add = b53_mdb_add,
.port_mdb_del = b53_mdb_del,
.port_max_mtu = b53_get_max_mtu,
.port_change_mtu = b53_change_mtu,
};

struct b53_chip_data {
Expand Down
19 changes: 19 additions & 0 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,7 @@ static int felix_setup(struct dsa_switch *ds)
ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)),
ANA_PGID_PGID, PGID_UC);

ds->mtu_enforcement_ingress = true;
/* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040)
* isn't instantiated for the Felix PF.
* In-band AN may take a few ms to complete, so we need to poll.
Expand Down Expand Up @@ -609,6 +610,22 @@ static bool felix_txtstamp(struct dsa_switch *ds, int port,
return false;
}

static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
struct ocelot *ocelot = ds->priv;

ocelot_port_set_maxlen(ocelot, port, new_mtu);

return 0;
}

static int felix_get_max_mtu(struct dsa_switch *ds, int port)
{
struct ocelot *ocelot = ds->priv;

return ocelot_get_max_mtu(ocelot, port);
}

static int felix_cls_flower_add(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress)
{
Expand Down Expand Up @@ -664,6 +681,8 @@ static const struct dsa_switch_ops felix_switch_ops = {
.port_hwtstamp_set = felix_hwtstamp_set,
.port_rxtstamp = felix_rxtstamp,
.port_txtstamp = felix_txtstamp,
.port_change_mtu = felix_change_mtu,
.port_max_mtu = felix_get_max_mtu,
.cls_flower_add = felix_cls_flower_add,
.cls_flower_del = felix_cls_flower_del,
.cls_flower_stats = felix_cls_flower_stats,
Expand Down
1 change: 1 addition & 0 deletions drivers/net/dsa/sja1105/sja1105.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ enum sja1105_reset_reason {
SJA1105_RX_HWTSTAMPING,
SJA1105_AGEING_TIME,
SJA1105_SCHEDULING,
SJA1105_BEST_EFFORT_POLICING,
};

int sja1105_static_config_reload(struct sja1105_private *priv,
Expand Down
50 changes: 46 additions & 4 deletions drivers/net/dsa/sja1105/sja1105_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,12 +519,12 @@ static int sja1105_init_avb_params(struct sja1105_private *priv)
#define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000)

static void sja1105_setup_policer(struct sja1105_l2_policing_entry *policing,
int index)
int index, int mtu)
{
policing[index].sharindx = index;
policing[index].smax = 65535; /* Burst size in bytes */
policing[index].rate = SJA1105_RATE_MBPS(1000);
policing[index].maxlen = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
policing[index].maxlen = mtu;
policing[index].partition = 0;
}

Expand Down Expand Up @@ -556,12 +556,16 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
*/
for (i = 0, k = 0; i < SJA1105_NUM_PORTS; i++) {
int bcast = (SJA1105_NUM_PORTS * SJA1105_NUM_TC) + i;
int mtu = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN;

if (dsa_is_cpu_port(priv->ds, i))
mtu += VLAN_HLEN;

for (j = 0; j < SJA1105_NUM_TC; j++, k++)
sja1105_setup_policer(policing, k);
sja1105_setup_policer(policing, k, mtu);

/* Set up this port's policer for broadcast traffic */
sja1105_setup_policer(policing, bcast);
sja1105_setup_policer(policing, bcast, mtu);
}
return 0;
}
Expand Down Expand Up @@ -1544,6 +1548,7 @@ static const char * const sja1105_reset_reasons[] = {
[SJA1105_RX_HWTSTAMPING] = "RX timestamping",
[SJA1105_AGEING_TIME] = "Ageing time",
[SJA1105_SCHEDULING] = "Time-aware scheduling",
[SJA1105_BEST_EFFORT_POLICING] = "Best-effort policing",
};

/* For situations where we need to change a setting at runtime that is only
Expand Down Expand Up @@ -1952,6 +1957,8 @@ static int sja1105_setup(struct dsa_switch *ds)
/* Advertise the 8 egress queues */
ds->num_tx_queues = SJA1105_NUM_TC;

ds->mtu_enforcement_ingress = true;

/* The DSA/switchdev model brings up switch ports in standalone mode by
* default, and that means vlan_filtering is 0 since they're not under
* a bridge, so it's safe to set up switch tagging at this time.
Expand Down Expand Up @@ -2120,6 +2127,39 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds,
return sja1105_static_config_reload(priv, SJA1105_AGEING_TIME);
}

static int sja1105_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
int bcast = (SJA1105_NUM_PORTS * SJA1105_NUM_TC) + port;
struct sja1105_l2_policing_entry *policing;
struct sja1105_private *priv = ds->priv;
int tc;

new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN;

if (dsa_is_cpu_port(ds, port))
new_mtu += VLAN_HLEN;

policing = priv->static_config.tables[BLK_IDX_L2_POLICING].entries;

/* We set all 9 port policers to the same value, so just checking the
* broadcast one is fine.
*/
if (policing[bcast].maxlen == new_mtu)
return 0;

for (tc = 0; tc < SJA1105_NUM_TC; tc++)
policing[port * SJA1105_NUM_TC + tc].maxlen = new_mtu;

policing[bcast].maxlen = new_mtu;

return sja1105_static_config_reload(priv, SJA1105_BEST_EFFORT_POLICING);
}

static int sja1105_get_max_mtu(struct dsa_switch *ds, int port)
{
return 2043 - VLAN_ETH_HLEN - ETH_FCS_LEN;
}

static int sja1105_port_setup_tc(struct dsa_switch *ds, int port,
enum tc_setup_type type,
void *type_data)
Expand Down Expand Up @@ -2215,6 +2255,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.setup = sja1105_setup,
.teardown = sja1105_teardown,
.set_ageing_time = sja1105_set_ageing_time,
.port_change_mtu = sja1105_change_mtu,
.port_max_mtu = sja1105_get_max_mtu,
.phylink_validate = sja1105_phylink_validate,
.phylink_mac_link_state = sja1105_mac_pcs_get_state,
.phylink_mac_config = sja1105_mac_config,
Expand Down
30 changes: 20 additions & 10 deletions drivers/net/dsa/vitesse-vsc73xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,16 +664,6 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
VSC73XX_MAC_CFG_TX_EN |
VSC73XX_MAC_CFG_RX_EN);

/* Max length, we can do up to 9.6 KiB, so allow that.
* According to application not "VSC7398 Jumbo Frames" setting
* up the MTU to 9.6 KB does not affect the performance on standard
* frames, so just enable it. It is clear from the application note
* that "9.6 kilobytes" == 9600 bytes.
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
port,
VSC73XX_MAXLEN, 9600);

/* Flow control for the CPU port:
* Use a zero delay pause frame when pause condition is left
* Obey pause control frames
Expand Down Expand Up @@ -1030,6 +1020,24 @@ static void vsc73xx_get_ethtool_stats(struct dsa_switch *ds, int port,
}
}

static int vsc73xx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
struct vsc73xx *vsc = ds->priv;

return vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
VSC73XX_MAXLEN, new_mtu);
}

/* According to application not "VSC7398 Jumbo Frames" setting
* up the MTU to 9.6 KB does not affect the performance on standard
* frames. It is clear from the application note that
* "9.6 kilobytes" == 9600 bytes.
*/
static int vsc73xx_get_max_mtu(struct dsa_switch *ds, int port)
{
return 9600;
}

static const struct dsa_switch_ops vsc73xx_ds_ops = {
.get_tag_protocol = vsc73xx_get_tag_protocol,
.setup = vsc73xx_setup,
Expand All @@ -1041,6 +1049,8 @@ static const struct dsa_switch_ops vsc73xx_ds_ops = {
.get_sset_count = vsc73xx_get_sset_count,
.port_enable = vsc73xx_port_enable,
.port_disable = vsc73xx_port_disable,
.port_change_mtu = vsc73xx_change_mtu,
.port_max_mtu = vsc73xx_get_max_mtu,
};

static int vsc73xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/ethernet/broadcom/bgmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,14 @@ static int bgmac_set_mac_address(struct net_device *net_dev, void *addr)
return 0;
}

static int bgmac_change_mtu(struct net_device *net_dev, int mtu)
{
struct bgmac *bgmac = netdev_priv(net_dev);

bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + mtu);
return 0;
}

static const struct net_device_ops bgmac_netdev_ops = {
.ndo_open = bgmac_open,
.ndo_stop = bgmac_stop,
Expand All @@ -1256,6 +1264,7 @@ static const struct net_device_ops bgmac_netdev_ops = {
.ndo_set_mac_address = bgmac_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = phy_do_ioctl_running,
.ndo_change_mtu = bgmac_change_mtu,
};

/**************************************************
Expand Down Expand Up @@ -1530,6 +1539,9 @@ int bgmac_enet_probe(struct bgmac *bgmac)
net_dev->hw_features = net_dev->features;
net_dev->vlan_features = net_dev->features;

/* Omit FCS from max MTU size */
net_dev->max_mtu = BGMAC_RX_MAX_FRAME_SIZE - ETH_FCS_LEN;

err = register_netdev(bgmac->net_dev);
if (err) {
dev_err(bgmac->dev, "Cannot register net device\n");
Expand Down
5 changes: 3 additions & 2 deletions drivers/net/ethernet/broadcom/bgmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@
#define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */
#define BGMAC_DESC_CTL0_EOF 0x40000000 /* End of frame */
#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */
#define BGMAC_DESC_CTL1_LEN 0x00001FFF
#define BGMAC_DESC_CTL1_LEN 0x00003FFF

#define BGMAC_PHY_NOREGS BRCM_PSEUDO_PHY_ADDR
#define BGMAC_PHY_MASK 0x1F
Expand All @@ -366,7 +366,8 @@
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
#define BGMAC_RX_BUF_OFFSET (NET_SKB_PAD + NET_IP_ALIGN - \
BGMAC_RX_FRAME_OFFSET)
#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
/* Jumbo frame size with FCS */
#define BGMAC_RX_MAX_FRAME_SIZE 9724
#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
Expand Down
45 changes: 35 additions & 10 deletions drivers/net/ethernet/mscc/ocelot.c
Original file line number Diff line number Diff line change
Expand Up @@ -2185,13 +2185,25 @@ static int ocelot_init_timestamp(struct ocelot *ocelot)

/* Configure the maximum SDU (L2 payload) on RX to the value specified in @sdu.
* The length of VLAN tags is accounted for automatically via DEV_MAC_TAGS_CFG.
* In the special case that it's the NPI port that we're configuring, the
* length of the tag and optional prefix needs to be accounted for privately,
* in order to be able to sustain communication at the requested @sdu.
*/
static void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
{
struct ocelot_port *ocelot_port = ocelot->ports[port];
int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
int atop_wm;

if (port == ocelot->npi) {
maxlen += OCELOT_TAG_LEN;

if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_SHORT)
maxlen += OCELOT_SHORT_PREFIX_LEN;
else if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_LONG)
maxlen += OCELOT_LONG_PREFIX_LEN;
}

ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG);

/* Set Pause WM hysteresis
Expand All @@ -2209,6 +2221,24 @@ static void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
SYS_ATOP, port);
ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
}
EXPORT_SYMBOL(ocelot_port_set_maxlen);

int ocelot_get_max_mtu(struct ocelot *ocelot, int port)
{
int max_mtu = 65535 - ETH_HLEN - ETH_FCS_LEN;

if (port == ocelot->npi) {
max_mtu -= OCELOT_TAG_LEN;

if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_SHORT)
max_mtu -= OCELOT_SHORT_PREFIX_LEN;
else if (ocelot->inj_prefix == OCELOT_TAG_PREFIX_LONG)
max_mtu -= OCELOT_LONG_PREFIX_LEN;
}

return max_mtu;
}
EXPORT_SYMBOL(ocelot_get_max_mtu);

void ocelot_init_port(struct ocelot *ocelot, int port)
{
Expand Down Expand Up @@ -2318,6 +2348,10 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
{
int cpu = ocelot->num_phys_ports;

ocelot->npi = npi;
ocelot->inj_prefix = injection;
ocelot->xtr_prefix = extraction;

/* The unicast destination PGID for the CPU port module is unused */
ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu);
/* Instead set up a multicast destination PGID for traffic copied to
Expand All @@ -2330,19 +2364,10 @@ void ocelot_configure_cpu(struct ocelot *ocelot, int npi,
ANA_PORT_PORT_CFG, cpu);

if (npi >= 0 && npi < ocelot->num_phys_ports) {
int sdu = ETH_DATA_LEN + OCELOT_TAG_LEN;

ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
QSYS_EXT_CPU_CFG_EXT_CPU_PORT(npi),
QSYS_EXT_CPU_CFG);

if (injection == OCELOT_TAG_PREFIX_SHORT)
sdu += OCELOT_SHORT_PREFIX_LEN;
else if (injection == OCELOT_TAG_PREFIX_LONG)
sdu += OCELOT_LONG_PREFIX_LEN;

ocelot_port_set_maxlen(ocelot, npi, sdu);

/* Enable NPI port */
ocelot_write_rix(ocelot,
QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE |
Expand Down
Loading

0 comments on commit 1a147b7

Please sign in to comment.