summaryrefslogtreecommitdiff
path: root/drivers/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa')
-rw-r--r--drivers/net/dsa/Makefile4
-rw-r--r--drivers/net/dsa/bcm_sf2.c6
-rw-r--r--drivers/net/dsa/bcm_sf2.h6
-rw-r--r--drivers/net/dsa/bcm_sf2_cfp.c6
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h6
-rw-r--r--drivers/net/dsa/dsa_loop.c6
-rw-r--r--drivers/net/dsa/lan9303-core.c11
-rw-r--r--drivers/net/dsa/lan9303_i2c.c11
-rw-r--r--drivers/net/dsa/lan9303_mdio.c11
-rw-r--r--drivers/net/dsa/microchip/ksz9477.c66
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c5
-rw-r--r--drivers/net/dsa/microchip/ksz_priv.h2
-rw-r--r--drivers/net/dsa/mt7530.c56
-rw-r--r--drivers/net/dsa/mt7530.h14
-rw-r--r--drivers/net/dsa/mv88e6060.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c194
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h16
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1_atu.c12
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1_vtu.c16
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.c26
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2_avb.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/global2_scratch.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.c34
-rw-r--r--drivers/net/dsa/mv88e6xxx/hwtstamp.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/phy.c10
-rw-r--r--drivers/net/dsa/mv88e6xxx/phy.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/port.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/ptp.c38
-rw-r--r--drivers/net/dsa/mv88e6xxx/ptp.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c30
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h6
-rw-r--r--drivers/net/dsa/mv88e6xxx/smi.c6
-rw-r--r--drivers/net/dsa/mv88e6xxx/smi.h6
-rw-r--r--drivers/net/dsa/qca8k.h10
-rw-r--r--drivers/net/dsa/realtek-smi-core.c (renamed from drivers/net/dsa/realtek-smi.c)2
-rw-r--r--drivers/net/dsa/realtek-smi-core.h (renamed from drivers/net/dsa/realtek-smi.h)0
-rw-r--r--drivers/net/dsa/rtl8366.c9
-rw-r--r--drivers/net/dsa/rtl8366rb.c2
-rw-r--r--drivers/net/dsa/sja1105/Kconfig9
-rw-r--r--drivers/net/dsa/sja1105/Makefile4
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h34
-rw-r--r--drivers/net/dsa/sja1105/sja1105_clocking.c100
-rw-r--r--drivers/net/dsa/sja1105/sja1105_dynamic_config.c2
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c478
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.c404
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.h64
-rw-r--r--drivers/net/dsa/sja1105/sja1105_spi.c60
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.c62
-rw-r--r--drivers/net/dsa/sja1105/sja1105_static_config.h10
53 files changed, 1408 insertions, 512 deletions
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index fefb6aaa82ba..d99dc6de0006 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -9,8 +9,8 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
-obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek.o
-realtek-objs := realtek-smi.o rtl8366.o rtl8366rb.o
+obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
+realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 4ccb3239f5f7..3811fdbda13e 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Broadcom Starfighter 2 DSA switch driver
*
* Copyright (C) 2014, Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/list.h>
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index eb3655bea467..1df30ccec42d 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Broadcom Starfighter2 private context
*
* Copyright (C) 2014, Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef __BCM_SF2_H
diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c
index 4212bc4a5f31..d264776a95a3 100644
--- a/drivers/net/dsa/bcm_sf2_cfp.c
+++ b/drivers/net/dsa/bcm_sf2_cfp.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Broadcom Starfighter 2 DSA switch CFP support
*
* Copyright (C) 2016, Broadcom
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/list.h>
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index 67f056206f37..d8a5e6269c0e 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Broadcom Starfighter 2 switch register defines
*
* Copyright (C) 2014, Broadcom Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef __BCM_SF2_REGS_H
#define __BCM_SF2_REGS_H
diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c
index 17482ae09aa5..925ed135a4d9 100644
--- a/drivers/net/dsa/dsa_loop.c
+++ b/drivers/net/dsa/dsa_loop.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Distributed Switch Architecture loopback driver
*
* Copyright (C) 2016, Florian Fainelli <f.fainelli@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/platform_device.h>
diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c
index 2ffab7ee3d80..7a2063e7737a 100644
--- a/drivers/net/dsa/lan9303-core.c
+++ b/drivers/net/dsa/lan9303-core.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/net/dsa/lan9303_i2c.c b/drivers/net/dsa/lan9303_i2c.c
index 909a7e864246..9bffaef65a04 100644
--- a/drivers/net/dsa/lan9303_i2c.c
+++ b/drivers/net/dsa/lan9303_i2c.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/net/dsa/lan9303_mdio.c b/drivers/net/dsa/lan9303_mdio.c
index cc9c2ea1c4fe..9cbe80460b53 100644
--- a/drivers/net/dsa/lan9303_mdio.c
+++ b/drivers/net/dsa/lan9303_mdio.c
@@ -1,18 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de>
*
* Partially based on a patch from
* Copyright (c) 2014 Stefan Roese <sr@denx.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c
index c026d15721f6..508380f80875 100644
--- a/drivers/net/dsa/microchip/ksz9477.c
+++ b/drivers/net/dsa/microchip/ksz9477.c
@@ -258,6 +258,10 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
data16 |= (BROADCAST_STORM_VALUE * BROADCAST_STORM_PROT_RATE) / 100;
ksz_write16(dev, REG_SW_MAC_CTRL_2, data16);
+ if (dev->synclko_125)
+ ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1,
+ SW_ENABLE_REFCLKO | SW_REFCLKO_IS_125MHZ);
+
return 0;
}
@@ -1165,6 +1169,62 @@ static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port)
return interface;
}
+static void ksz9477_port_mmd_write(struct ksz_device *dev, int port,
+ u8 dev_addr, u16 reg_addr, u16 val)
+{
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP,
+ MMD_SETUP(PORT_MMD_OP_INDEX, dev_addr));
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, reg_addr);
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_SETUP,
+ MMD_SETUP(PORT_MMD_OP_DATA_NO_INCR, dev_addr));
+ ksz_pwrite16(dev, port, REG_PORT_PHY_MMD_INDEX_DATA, val);
+}
+
+static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
+{
+ /* Apply PHY settings to address errata listed in
+ * KSZ9477, KSZ9897, KSZ9896, KSZ9567, KSZ8565
+ * Silicon Errata and Data Sheet Clarification documents:
+ *
+ * Register settings are needed to improve PHY receive performance
+ */
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x6f, 0xdd0b);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x8f, 0x6032);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x9d, 0x248c);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0x75, 0x0060);
+ ksz9477_port_mmd_write(dev, port, 0x01, 0xd3, 0x7777);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x06, 0x3008);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x08, 0x2001);
+
+ /* Transmit waveform amplitude can be improved
+ * (1000BASE-T, 100BASE-TX, 10BASE-Te)
+ */
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x04, 0x00d0);
+
+ /* Energy Efficient Ethernet (EEE) feature select must
+ * be manually disabled (except on KSZ8565 which is 100Mbit)
+ */
+ if (dev->features & GBIT_SUPPORT)
+ ksz9477_port_mmd_write(dev, port, 0x07, 0x3c, 0x0000);
+
+ /* Register settings are required to meet data sheet
+ * supply current specifications
+ */
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x13, 0x6eff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x14, 0xe6ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x15, 0x6eff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x16, 0xe6ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x17, 0x00ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x18, 0x43ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x19, 0xc3ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1a, 0x6fff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1b, 0x07ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1c, 0x0fff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1d, 0xe7ff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x1e, 0xefff);
+ ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee);
+}
+
static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
{
u8 data8;
@@ -1203,6 +1263,8 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL,
false);
+ if (dev->phy_errata_9477)
+ ksz9477_phy_errata_setup(dev, port);
} else {
/* force flow control */
ksz_port_cfg(dev, port, REG_PORT_CTRL_0,
@@ -1474,6 +1536,7 @@ struct ksz_chip_data {
int num_statics;
int cpu_ports;
int port_cnt;
+ bool phy_errata_9477;
};
static const struct ksz_chip_data ksz9477_switch_chips[] = {
@@ -1485,6 +1548,7 @@ static const struct ksz_chip_data ksz9477_switch_chips[] = {
.num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */
+ .phy_errata_9477 = true,
},
{
.chip_id = 0x00989700,
@@ -1494,6 +1558,7 @@ static const struct ksz_chip_data ksz9477_switch_chips[] = {
.num_statics = 16,
.cpu_ports = 0x7F, /* can be configured as cpu port */
.port_cnt = 7, /* total physical port count */
+ .phy_errata_9477 = true,
},
{
.chip_id = 0x00989300,
@@ -1522,6 +1587,7 @@ static int ksz9477_switch_init(struct ksz_device *dev)
dev->num_statics = chip->num_statics;
dev->port_cnt = chip->port_cnt;
dev->cpu_ports = chip->cpu_ports;
+ dev->phy_errata_9477 = chip->phy_errata_9477;
break;
}
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 39dace8e3512..4f6648d5ac8b 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -83,6 +83,9 @@ static void ksz_mib_read_work(struct work_struct *work)
int i;
for (i = 0; i < dev->mib_port_cnt; i++) {
+ if (dsa_is_unused_port(dev->ds, i))
+ continue;
+
p = &dev->ports[i];
mib = &p->mib;
mutex_lock(&mib->cnt_mutex);
@@ -460,6 +463,8 @@ int ksz_switch_register(struct ksz_device *dev,
ret = of_get_phy_mode(dev->dev->of_node);
if (ret >= 0)
dev->interface = ret;
+ dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
+ "microchip,synclko-125");
}
ret = dsa_register_switch(dev->ds);
diff --git a/drivers/net/dsa/microchip/ksz_priv.h b/drivers/net/dsa/microchip/ksz_priv.h
index b52e5ca17ab4..c615d2a81dd5 100644
--- a/drivers/net/dsa/microchip/ksz_priv.h
+++ b/drivers/net/dsa/microchip/ksz_priv.h
@@ -77,6 +77,8 @@ struct ksz_device {
int last_port; /* ports after that not used */
phy_interface_t interface;
u32 regs_size;
+ bool phy_errata_9477;
+ bool synclko_125;
struct vlan_table *vlan_cache;
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 8d531c5f21f3..3181e95586d6 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Mediatek MT7530 DSA Switch driver
* Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
@@ -436,24 +428,48 @@ static int
mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
{
struct mt7530_priv *priv = ds->priv;
- u32 ncpo1, ssc_delta, trgint, i;
+ u32 ncpo1, ssc_delta, trgint, i, xtal;
+
+ xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
+
+ if (xtal == HWTRAP_XTAL_20MHZ) {
+ dev_err(priv->dev,
+ "%s: MT7530 with a 20MHz XTAL is not supported!\n",
+ __func__);
+ return -EINVAL;
+ }
switch (mode) {
case PHY_INTERFACE_MODE_RGMII:
trgint = 0;
+ /* PLL frequency: 125MHz */
ncpo1 = 0x0c80;
- ssc_delta = 0x87;
break;
case PHY_INTERFACE_MODE_TRGMII:
trgint = 1;
- ncpo1 = 0x1400;
- ssc_delta = 0x57;
+ if (priv->id == ID_MT7621) {
+ /* PLL frequency: 150MHz: 1.2GBit */
+ if (xtal == HWTRAP_XTAL_40MHZ)
+ ncpo1 = 0x0780;
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ncpo1 = 0x0a00;
+ } else { /* PLL frequency: 250MHz: 2.0Gbit */
+ if (xtal == HWTRAP_XTAL_40MHZ)
+ ncpo1 = 0x0c80;
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ncpo1 = 0x1400;
+ }
break;
default:
dev_err(priv->dev, "xMII mode %d not supported\n", mode);
return -EINVAL;
}
+ if (xtal == HWTRAP_XTAL_25MHZ)
+ ssc_delta = 0x57;
+ else
+ ssc_delta = 0x87;
+
mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
P6_INTF_MODE(trgint));
@@ -515,7 +531,9 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
mt7530_rmw(priv, MT7530_TRGMII_RD(i),
RD_TAP_MASK, RD_TAP(16));
else
- mt7623_trgmii_set(priv, GSW_INTF_MODE, INTF_MODE_TRGMII);
+ if (priv->id != ID_MT7621)
+ mt7623_trgmii_set(priv, GSW_INTF_MODE,
+ INTF_MODE_TRGMII);
return 0;
}
@@ -621,13 +639,13 @@ static void mt7530_adjust_link(struct dsa_switch *ds, int port,
struct mt7530_priv *priv = ds->priv;
if (phy_is_pseudo_fixed_link(phydev)) {
- if (priv->id == ID_MT7530) {
- dev_dbg(priv->dev, "phy-mode for master device = %x\n",
- phydev->interface);
+ dev_dbg(priv->dev, "phy-mode for master device = %x\n",
+ phydev->interface);
- /* Setup TX circuit incluing relevant PAD and driving */
- mt7530_pad_clk_setup(ds, phydev->interface);
+ /* Setup TX circuit incluing relevant PAD and driving */
+ mt7530_pad_clk_setup(ds, phydev->interface);
+ if (priv->id == ID_MT7530) {
/* Setup RX circuit, relevant PAD and driving on the
* host which must be placed after the setup on the
* device side is all finished.
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 1eec7bdc283a..bfac90f48102 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -1,14 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __MT7530_H
@@ -252,6 +244,10 @@ enum mt7530_vlan_port_attr {
/* Register for hw trap status */
#define MT7530_HWTRAP 0x7800
+#define HWTRAP_XTAL_MASK (BIT(10) | BIT(9))
+#define HWTRAP_XTAL_25MHZ (BIT(10) | BIT(9))
+#define HWTRAP_XTAL_40MHZ (BIT(10))
+#define HWTRAP_XTAL_20MHZ (BIT(9))
/* Register for hw trap modification */
#define MT7530_MHWTRAP 0x7804
diff --git a/drivers/net/dsa/mv88e6060.h b/drivers/net/dsa/mv88e6060.h
index c0e7a0f2fb6a..6c13c2421b64 100644
--- a/drivers/net/dsa/mv88e6060.h
+++ b/drivers/net/dsa/mv88e6060.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* drivers/net/dsa/mv88e6060.h - Marvell 88e6060 switch chip support
* Copyright (c) 2015 Neil Armstrong
*
* Based on mv88e6xxx.h
* Copyright (c) 2008 Marvell Semiconductor
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef __MV88E6060_H
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index df9c51da7733..40b1fb22d8df 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88e6xxx Ethernet switch single-chip support
*
@@ -7,11 +8,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/delay.h>
@@ -122,9 +118,9 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
u16 ctl1;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -139,13 +135,13 @@ static irqreturn_t mv88e6xxx_g1_irq_thread_work(struct mv88e6xxx_chip *chip)
}
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &ctl1);
if (err)
goto unlock;
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &reg);
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
ctl1 &= GENMASK(chip->g1_irq.nirqs, 0);
@@ -166,7 +162,7 @@ static void mv88e6xxx_g1_irq_bus_lock(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
}
static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
@@ -188,7 +184,7 @@ static void mv88e6xxx_g1_irq_bus_sync_unlock(struct irq_data *d)
goto out;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static const struct irq_chip mv88e6xxx_g1_irq_chip = {
@@ -243,9 +239,9 @@ static void mv88e6xxx_g1_irq_free(struct mv88e6xxx_chip *chip)
*/
free_irq(chip->irq, chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_g1_irq_free_common(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_g1_irq_setup_common(struct mv88e6xxx_chip *chip)
@@ -314,12 +310,12 @@ static int mv88e6xxx_g1_irq_setup(struct mv88e6xxx_chip *chip)
*/
irq_set_lockdep_class(chip->irq, &lock_key, &request_key);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->irq, NULL,
mv88e6xxx_g1_irq_thread_fn,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(chip->dev), chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err)
mv88e6xxx_g1_irq_free_common(chip);
@@ -363,9 +359,9 @@ static void mv88e6xxx_irq_poll_free(struct mv88e6xxx_chip *chip)
kthread_cancel_delayed_work_sync(&chip->irq_poll_work);
kthread_destroy_worker(chip->kworker);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_g1_irq_free_common(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
@@ -500,11 +496,11 @@ static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
mv88e6xxx_phy_is_internal(ds, port))
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
phydev->duplex, phydev->pause,
phydev->interface);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
@@ -620,12 +616,12 @@ static int mv88e6xxx_link_state(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->port_link_state)
err = chip->info->ops->port_link_state(chip, port, state);
else
err = -EOPNOTSUPP;
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -655,10 +651,10 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port,
}
pause = !!phylink_test(state->advertising, Pause);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, pause,
state->interface);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err && err != -EOPNOTSUPP)
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
@@ -669,9 +665,9 @@ static void mv88e6xxx_mac_link_force(struct dsa_switch *ds, int port, int link)
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->port_set_link(chip, port, link);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(chip->dev, "p%d: failed to force MAC link\n", port);
@@ -869,7 +865,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
if (stringset != ETH_SS_STATS)
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->stats_get_strings)
count = chip->info->ops->stats_get_strings(chip, data);
@@ -882,7 +878,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
data += count * ETH_GSTRING_LEN;
mv88e6xxx_atu_vtu_get_strings(data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
@@ -925,7 +921,7 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
if (sset != ETH_SS_STATS)
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->stats_get_sset_count)
count = chip->info->ops->stats_get_sset_count(chip);
if (count < 0)
@@ -942,7 +938,7 @@ static int mv88e6xxx_get_sset_count(struct dsa_switch *ds, int port, int sset)
count += ARRAY_SIZE(mv88e6xxx_atu_vtu_stats_strings);
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return count;
}
@@ -957,11 +953,11 @@ static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
stat = &mv88e6xxx_hw_stats[i];
if (stat->type & types) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
bank1_select,
histogram);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
j++;
}
@@ -1020,14 +1016,14 @@ static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
if (chip->info->ops->stats_get_stats)
count = chip->info->ops->stats_get_stats(chip, port, data);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->serdes_get_stats) {
data += count;
count = chip->info->ops->serdes_get_stats(chip, port, data);
}
data += count;
mv88e6xxx_atu_vtu_get_stats(chip, port, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
@@ -1036,10 +1032,10 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int ret;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ret = mv88e6xxx_stats_snapshot(chip, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (ret < 0)
return;
@@ -1066,7 +1062,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
memset(p, 0xff, 32 * sizeof(u16));
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
for (i = 0; i < 32; i++) {
@@ -1075,7 +1071,7 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port,
p[i] = reg;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port,
@@ -1141,9 +1137,9 @@ static void mv88e6xxx_port_stp_state_set(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_state(chip, port, state);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(ds->dev, "p%d: failed to update state\n", port);
@@ -1328,9 +1324,9 @@ static void mv88e6xxx_port_fast_age(struct dsa_switch *ds, int port)
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_remove(chip, 0, port, false);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
dev_err(ds->dev, "p%d: failed to flush ATU\n", port);
@@ -1410,7 +1406,7 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
int err;
if (!vid)
- return -EINVAL;
+ return -EOPNOTSUPP;
entry->vid = vid - 1;
entry->valid = false;
@@ -1458,7 +1454,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
if (!vid_begin)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
do {
err = mv88e6xxx_vtu_getnext(chip, &vlan);
@@ -1498,7 +1494,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
} while (vlan.vid < vid_end);
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1514,9 +1510,9 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
if (!chip->info->max_vid)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1650,7 +1646,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
else
member = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
@@ -1661,7 +1657,7 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
dev_err(ds->dev, "p%d: failed to set PVID %d\n", port,
vlan->vid_end);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
@@ -1707,7 +1703,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
if (!chip->info->max_vid)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_get_pvid(chip, port, &pvid);
if (err)
@@ -1726,7 +1722,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
}
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1737,10 +1733,10 @@ static int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1751,10 +1747,10 @@ static int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, addr, vid,
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1771,9 +1767,7 @@ static int mv88e6xxx_port_db_dump_fid(struct mv88e6xxx_chip *chip,
eth_broadcast_addr(addr.mac);
do {
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
- mutex_unlock(&chip->reg_lock);
if (err)
return err;
@@ -1806,10 +1800,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
int err;
/* Dump port's default Filtering Information Database (VLAN ID 0) */
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_port_get_fid(chip, port, &fid);
- mutex_unlock(&chip->reg_lock);
-
if (err)
return err;
@@ -1819,9 +1810,7 @@ static int mv88e6xxx_port_db_dump(struct mv88e6xxx_chip *chip, int port,
/* Dump VLANs' Filtering Information Databases */
do {
- mutex_lock(&chip->reg_lock);
err = mv88e6xxx_vtu_getnext(chip, &vlan);
- mutex_unlock(&chip->reg_lock);
if (err)
return err;
@@ -1841,8 +1830,13 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
dsa_fdb_dump_cb_t *cb, void *data)
{
struct mv88e6xxx_chip *chip = ds->priv;
+ int err;
+
+ mv88e6xxx_reg_lock(chip);
+ err = mv88e6xxx_port_db_dump(chip, port, cb, data);
+ mv88e6xxx_reg_unlock(chip);
- return mv88e6xxx_port_db_dump(chip, port, cb, data);
+ return err;
}
static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
@@ -1889,9 +1883,9 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_bridge_map(chip, br);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1901,11 +1895,11 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_bridge_map(chip, br) ||
mv88e6xxx_port_vlan_map(chip, port))
dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
@@ -1917,9 +1911,9 @@ static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev,
if (!mv88e6xxx_has_pvt(chip))
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_pvt_map(chip, dev, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -1932,10 +1926,10 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev,
if (!mv88e6xxx_has_pvt(chip))
return;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_pvt_map(chip, dev, port))
dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_software_reset(struct mv88e6xxx_chip *chip)
@@ -2286,14 +2280,14 @@ static int mv88e6xxx_port_enable(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_serdes_power(chip, port, true);
if (!err && chip->info->ops->serdes_irq_setup)
err = chip->info->ops->serdes_irq_setup(chip, port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2302,7 +2296,7 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_port_set_state(chip, port, BR_STATE_DISABLED))
dev_err(chip->dev, "failed to disable port\n");
@@ -2313,7 +2307,7 @@ static void mv88e6xxx_port_disable(struct dsa_switch *ds, int port)
if (mv88e6xxx_serdes_power(chip, port, false))
dev_err(chip->dev, "failed to power off SERDES\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
@@ -2322,9 +2316,9 @@ static int mv88e6xxx_set_ageing_time(struct dsa_switch *ds,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_set_age_time(chip, ageing_time);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2454,7 +2448,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
chip->ds = ds;
ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->setup_errata) {
err = chip->info->ops->setup_errata(chip);
@@ -2561,7 +2555,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
goto unlock;
unlock:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2576,9 +2570,9 @@ static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
if (!chip->info->ops->phy_read)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (reg == MII_PHYSID2) {
/* Some internal PHYs don't have a model number. */
@@ -2611,9 +2605,9 @@ static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
if (!chip->info->ops->phy_write)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -2628,9 +2622,9 @@ static int mv88e6xxx_mdio_register(struct mv88e6xxx_chip *chip,
int err;
if (external) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g2_scratch_gpio_set_smi(chip, true);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -2751,9 +2745,9 @@ static int mv88e6xxx_get_eeprom(struct dsa_switch *ds,
if (!chip->info->ops->get_eeprom)
return -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->get_eeprom(chip, eeprom, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -2775,9 +2769,9 @@ static int mv88e6xxx_set_eeprom(struct dsa_switch *ds,
if (eeprom->magic != 0xc3ec4951)
return -EINVAL;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = chip->info->ops->set_eeprom(chip, eeprom, data);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -4538,9 +4532,9 @@ static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
u16 id;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
return err;
@@ -4603,12 +4597,12 @@ static void mv88e6xxx_port_mdb_add(struct dsa_switch *ds, int port,
{
struct mv88e6xxx_chip *chip = ds->priv;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC))
dev_err(ds->dev, "p%d: failed to load multicast MAC address\n",
port);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
@@ -4617,10 +4611,10 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_db_load_purge(chip, port, mdb->addr, mdb->vid,
MV88E6XXX_G1_ATU_DATA_STATE_UNUSED);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -4631,12 +4625,12 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err = -EOPNOTSUPP;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->port_set_egress_floods)
err = chip->info->ops->port_set_egress_floods(chip, port,
unicast,
multicast);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -4807,9 +4801,9 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
chip->eeprom_len = pdata->eeprom_len;
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_switch_reset(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -4828,12 +4822,12 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
* the PHYs will link their interrupts to these interrupt
* controllers
*/
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->irq > 0)
err = mv88e6xxx_g1_irq_setup(chip);
else
err = mv88e6xxx_irq_poll_setup(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 2fbe72b7587b..4646e46d47f2 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -1,12 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Ethernet switch single-chip definition
*
* Copyright (c) 2008 Marvell Semiconductor
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_CHIP_H
@@ -584,4 +580,14 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
phy_interface_t mode);
struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
+static inline void mv88e6xxx_reg_lock(struct mv88e6xxx_chip *chip)
+{
+ mutex_lock(&chip->reg_lock);
+}
+
+static inline void mv88e6xxx_reg_unlock(struct mv88e6xxx_chip *chip)
+{
+ mutex_unlock(&chip->reg_lock);
+}
+
#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 41c0792a2e2b..1323ef30a5e9 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Global (1) Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/bitfield.h>
diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h
index 9681ce25598a..d444266f7d78 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.h
+++ b/drivers/net/dsa/mv88e6xxx/global1.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Switch Global (1) Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_GLOBAL1_H
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 1ae680bc0eff..1cf388e9bd94 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Address Translation Unit (ATU) support
*
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2017 Savoir-faire Linux, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
@@ -321,7 +317,7 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
int err;
u16 val;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_atu_op(chip, 0,
MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
@@ -368,12 +364,12 @@ static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
entry.mac, entry.portvec, spid);
chip->ports[spid].atu_full_violation++;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return IRQ_HANDLED;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
err);
diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
index a8ef268c32cb..6cac997360e8 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx VLAN [Spanning Tree] Translation Unit (VTU [STU]) support
*
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2015 CMC Electronics, Inc.
* Copyright (c) 2017 Savoir-faire Linux, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/interrupt.h>
@@ -448,7 +444,7 @@ int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
* VTU DBNum[5:4] are located in VTU Operation 9:8
*/
op |= entry->fid & 0x000f;
- op |= (entry->fid & 0x0030) << 8;
+ op |= (entry->fid & 0x0030) << 4;
}
return mv88e6xxx_g1_vtu_op(chip, op);
@@ -477,7 +473,7 @@ int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
* VTU DBNum[7:4] are located in VTU Operation 11:8
*/
op |= entry->fid & 0x000f;
- op |= (entry->fid & 0x00f0) << 8;
+ op |= (entry->fid & 0x00f0) << 4;
}
return mv88e6xxx_g1_vtu_op(chip, op);
@@ -583,7 +579,7 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
int err;
u16 val;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g1_vtu_op(chip, MV88E6XXX_G1_VTU_OP_GET_CLR_VIOLATION);
if (err)
@@ -611,12 +607,12 @@ static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn(int irq, void *dev_id)
chip->ports[spid].vtu_miss_violation++;
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return IRQ_HANDLED;
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
dev_err(chip->dev, "VTU problem: error %d while handling interrupt\n",
err);
diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c
index 85984eb69ffd..2305b94b3051 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.c
+++ b/drivers/net/dsa/mv88e6xxx/global2.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Global 2 Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/bitfield.h>
@@ -897,20 +893,20 @@ static irqreturn_t mv88e6xxx_g2_watchdog_thread_fn(int irq, void *dev_id)
struct mv88e6xxx_chip *chip = dev_id;
irqreturn_t ret = IRQ_NONE;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_action)
ret = chip->info->ops->watchdog_ops->irq_action(chip, irq);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
static void mv88e6xxx_g2_watchdog_free(struct mv88e6xxx_chip *chip)
{
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_free)
chip->info->ops->watchdog_ops->irq_free(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->watchdog_irq, chip);
irq_dispose_mapping(chip->watchdog_irq);
@@ -932,10 +928,10 @@ static int mv88e6xxx_g2_watchdog_setup(struct mv88e6xxx_chip *chip)
if (err)
return err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (chip->info->ops->watchdog_ops->irq_setup)
err = chip->info->ops->watchdog_ops->irq_setup(chip);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
@@ -990,9 +986,9 @@ static irqreturn_t mv88e6xxx_g2_irq_thread_fn(int irq, void *dev_id)
int err;
u16 reg;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_g2_int_source(chip, &reg);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto out;
@@ -1011,7 +1007,7 @@ static void mv88e6xxx_g2_irq_bus_lock(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
}
static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
@@ -1023,7 +1019,7 @@ static void mv88e6xxx_g2_irq_bus_sync_unlock(struct irq_data *d)
if (err)
dev_err(chip->dev, "failed to mask interrupts\n");
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static const struct irq_chip mv88e6xxx_g2_irq_chip = {
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 6205c6b75bc7..a664fc25f132 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Switch Global 2 Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_GLOBAL2_H
diff --git a/drivers/net/dsa/mv88e6xxx/global2_avb.c b/drivers/net/dsa/mv88e6xxx/global2_avb.c
index 672b503a67e1..116b8cf5a6e3 100644
--- a/drivers/net/dsa/mv88e6xxx/global2_avb.c
+++ b/drivers/net/dsa/mv88e6xxx/global2_avb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Global 2 Registers support
*
@@ -8,11 +9,6 @@
*
* Copyright (c) 2017 National Instruments
* Brandon Streiff <brandon.streiff@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include "global2.h"
diff --git a/drivers/net/dsa/mv88e6xxx/global2_scratch.c b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
index 3f92b8892dc7..baddecadd8be 100644
--- a/drivers/net/dsa/mv88e6xxx/global2_scratch.c
+++ b/drivers/net/dsa/mv88e6xxx/global2_scratch.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Global 2 Scratch & Misc Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2017 National Instruments
* Brandon Streiff <brandon.streiff@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include "chip.h"
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index a17c16a2ab78..a4c488b12e8f 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch hardware timestamping support
*
@@ -7,11 +8,6 @@
* Erik Hons <erik.hons@ni.com>
* Brandon Streiff <brandon.streiff@ni.com>
* Dane Wagner <dane.wagner@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include "chip.h"
@@ -151,7 +147,7 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
return -ERANGE;
}
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (tstamp_enable) {
chip->enable_count += 1;
if (chip->enable_count == 1 && ptp_ops->global_enable)
@@ -165,7 +161,7 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
if (chip->enable_count == 0 && ptp_ops->global_disable)
ptp_ops->global_disable(chip);
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
/* Once hardware has been configured, enable timestamp checks
* in the RX/TX paths.
@@ -305,10 +301,10 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
skb_queue_splice_tail_init(rxq, &received);
spin_unlock_irqrestore(&rxq->lock, flags);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
reg, buf, ARRAY_SIZE(buf));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
pr_err("failed to get the receive time stamp\n");
@@ -318,9 +314,9 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
seq_id = buf[3];
if (status & MV88E6XXX_PTP_TS_VALID) {
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_write(chip, ps->port_id, reg, 0);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
pr_err("failed to clear the receive status\n");
}
@@ -331,9 +327,9 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
if (mv88e6xxx_ts_valid(status) && seq_match(skb, seq_id)) {
ns = timehi << 16 | timelo;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_cyc2time(&chip->tstamp_tc, ns);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
shwt = skb_hwtstamps(skb);
memset(shwt, 0, sizeof(*shwt));
shwt->hwtstamp = ns_to_ktime(ns);
@@ -409,12 +405,12 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
if (!ps->tx_skb)
return 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
ptp_ops->dep_sts_reg,
departure_block,
ARRAY_SIZE(departure_block));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err)
goto free_and_clear_skb;
@@ -434,9 +430,9 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
}
/* We have the timestamp; go ahead and clear valid now */
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
mv88e6xxx_port_ptp_write(chip, ps->port_id, ptp_ops->dep_sts_reg, 0);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
if (status != MV88E6XXX_PTP_TS_STATUS_NORMAL) {
@@ -451,9 +447,9 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
time_raw = ((u32)departure_block[2] << 16) | departure_block[1];
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_cyc2time(&chip->tstamp_tc, time_raw);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
shhwtstamps.hwtstamp = ns_to_ktime(ns);
dev_dbg(chip->dev,
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index b9a72661bcc4..9da9f197ba02 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Switch hardware timestamping support
*
@@ -7,11 +8,6 @@
* Erik Hons <erik.hons@ni.com>
* Brandon Streiff <brandon.streiff@ni.com>
* Dane Wagner <dane.wagner@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_HWTSTAMP_H
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
index 152a65d46e0b..252b5b3a3efe 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.c
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88e6xxx Ethernet switch PHY and PPU support
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/mdio.h>
@@ -141,7 +137,7 @@ static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (mutex_trylock(&chip->ppu_mutex)) {
if (mv88e6xxx_phy_ppu_enable(chip) == 0)
@@ -149,7 +145,7 @@ static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
mutex_unlock(&chip->ppu_mutex);
}
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
}
static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list *t)
diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h
index 556b74a0502a..05ea0d546969 100644
--- a/drivers/net/dsa/mv88e6xxx/phy.h
+++ b/drivers/net/dsa/mv88e6xxx/phy.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx PHY access
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_PHY_H
diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c
index a9a308051d7c..04309ef0a1cc 100644
--- a/drivers/net/dsa/mv88e6xxx/port.c
+++ b/drivers/net/dsa/mv88e6xxx/port.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch Port Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/bitfield.h>
diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h
index b3b57ea6ef07..8d5a6cd6fb19 100644
--- a/drivers/net/dsa/mv88e6xxx/port.h
+++ b/drivers/net/dsa/mv88e6xxx/port.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Switch Port Registers support
*
@@ -5,11 +6,6 @@
*
* Copyright (c) 2016-2017 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_PORT_H
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 42872d21857b..768d256f7c9f 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx Switch PTP support
*
@@ -7,11 +8,6 @@
* Erik Hons <erik.hons@ni.com>
* Brandon Streiff <brandon.streiff@ni.com>
* Dane Wagner <dane.wagner@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include "chip.h"
@@ -142,10 +138,10 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly)
u32 raw_ts;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS,
status, ARRAY_SIZE(status));
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
if (err) {
dev_err(chip->dev, "failed to read TAI status register\n");
@@ -162,18 +158,18 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly)
/* Clear the valid bit so the next timestamp can come in */
status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
/* This is an external timestamp */
ev.type = PTP_CLOCK_EXTTS;
/* We only have one timestamping channel. */
ev.index = 0;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ev.timestamp = timecounter_cyc2time(&chip->tstamp_tc, raw_ts);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
ptp_clock_event(chip->ptp_clock, &ev);
out:
@@ -196,12 +192,12 @@ static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
adj *= scaled_ppm;
diff = div_u64(adj, CC_MULT_DEM);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_read(&chip->tstamp_tc);
chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -210,9 +206,9 @@ static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_adjtime(&chip->tstamp_tc, delta);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -223,9 +219,9 @@ static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
u64 ns;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
ns = timecounter_read(&chip->tstamp_tc);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
*ts = ns_to_timespec64(ns);
@@ -240,9 +236,9 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
ns = timespec64_to_ns(ts);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return 0;
}
@@ -260,7 +256,7 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
if (pin < 0)
return -EBUSY;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (on) {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
@@ -282,7 +278,7 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return err;
}
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 28a030840517..0a1f8de8f062 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx Switch PTP support
*
@@ -7,11 +8,6 @@
* Erik Hons <erik.hons@ni.com>
* Brandon Streiff <brandon.streiff@ni.com>
* Dane Wagner <dane.wagner@ni.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_PTP_H
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 6a5de1b72f6c..20c526c2a9ee 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx SERDES manipulation, via SMI bus
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/interrupt.h>
@@ -212,7 +208,7 @@ static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
u16 status;
int err;
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
err = mv88e6352_serdes_read(chip, MV88E6352_SERDES_INT_STATUS, &status);
if (err)
@@ -223,7 +219,7 @@ static irqreturn_t mv88e6352_serdes_thread_fn(int irq, void *dev_id)
mv88e6352_serdes_irq_link(chip, port->port);
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
@@ -257,12 +253,12 @@ int mv88e6352_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
/* Requesting the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
mv88e6352_serdes_thread_fn,
IRQF_ONESHOT, "mv88e6xxx-serdes",
&chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err) {
dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
@@ -283,9 +279,9 @@ void mv88e6352_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
/* Freeing the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
chip->ports[port].serdes_irq = 0;
}
@@ -625,7 +621,7 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
lane = mv88e6390x_serdes_get_lane(chip, port->port);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
switch (cmode) {
case MV88E6XXX_PORT_STS_CMODE_SGMII:
@@ -641,7 +637,7 @@ static irqreturn_t mv88e6390_serdes_thread_fn(int irq, void *dev_id)
}
}
out:
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
return ret;
}
@@ -670,12 +666,12 @@ int mv88e6390x_serdes_irq_setup(struct mv88e6xxx_chip *chip, int port)
/* Requesting the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
err = request_threaded_irq(chip->ports[port].serdes_irq, NULL,
mv88e6390_serdes_thread_fn,
IRQF_ONESHOT, "mv88e6xxx-serdes",
&chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
if (err) {
dev_err(chip->dev, "Unable to request SERDES interrupt: %d\n",
@@ -709,9 +705,9 @@ void mv88e6390x_serdes_irq_free(struct mv88e6xxx_chip *chip, int port)
/* Freeing the IRQ will trigger irq callbacks. So we cannot
* hold the reg_lock.
*/
- mutex_unlock(&chip->reg_lock);
+ mv88e6xxx_reg_unlock(chip);
free_irq(chip->ports[port].serdes_irq, &chip->ports[port]);
- mutex_lock(&chip->reg_lock);
+ mv88e6xxx_reg_lock(chip);
chip->ports[port].serdes_irq = 0;
}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index c2e7eedfa9b9..ff5b94439335 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx SERDES manipulation, via SMI bus
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_SERDES_H
diff --git a/drivers/net/dsa/mv88e6xxx/smi.c b/drivers/net/dsa/mv88e6xxx/smi.c
index 775f8d55a962..5fc78a063843 100644
--- a/drivers/net/dsa/mv88e6xxx/smi.c
+++ b/drivers/net/dsa/mv88e6xxx/smi.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Marvell 88E6xxx System Management Interface (SMI) support
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include "chip.h"
diff --git a/drivers/net/dsa/mv88e6xxx/smi.h b/drivers/net/dsa/mv88e6xxx/smi.h
index 35e6403b65dc..c6c71d5757f5 100644
--- a/drivers/net/dsa/mv88e6xxx/smi.h
+++ b/drivers/net/dsa/mv88e6xxx/smi.h
@@ -1,14 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Marvell 88E6xxx System Management Interface (SMI) support
*
* Copyright (c) 2008 Marvell Semiconductor
*
* Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#ifndef _MV88E6XXX_SMI_H
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 249fd62268e5..91557433ce2f 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __QCA8K_H
diff --git a/drivers/net/dsa/realtek-smi.c b/drivers/net/dsa/realtek-smi-core.c
index ad41ec63cc9f..dc0509c02d29 100644
--- a/drivers/net/dsa/realtek-smi.c
+++ b/drivers/net/dsa/realtek-smi-core.c
@@ -40,7 +40,7 @@
#include <linux/bitops.h>
#include <linux/if_bridge.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define REALTEK_SMI_ACK_RETRY_COUNT 5
#define REALTEK_SMI_HW_STOP_DELAY 25 /* msecs */
diff --git a/drivers/net/dsa/realtek-smi.h b/drivers/net/dsa/realtek-smi-core.h
index 9a63b51e1d82..9a63b51e1d82 100644
--- a/drivers/net/dsa/realtek-smi.h
+++ b/drivers/net/dsa/realtek-smi-core.h
diff --git a/drivers/net/dsa/rtl8366.c b/drivers/net/dsa/rtl8366.c
index 6dedd43442cc..ca3d17e43ed8 100644
--- a/drivers/net/dsa/rtl8366.c
+++ b/drivers/net/dsa/rtl8366.c
@@ -11,7 +11,7 @@
#include <linux/if_bridge.h>
#include <net/dsa.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
int rtl8366_mc_is_used(struct realtek_smi *smi, int mc_index, int *used)
{
@@ -307,7 +307,8 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
struct rtl8366_vlan_4k vlan4k;
int ret;
- if (!smi->ops->is_vlan_valid(smi, port))
+ /* Use VLAN nr port + 1 since VLAN0 is not valid */
+ if (!smi->ops->is_vlan_valid(smi, port + 1))
return -EINVAL;
dev_info(smi->dev, "%s filtering on port %d\n",
@@ -318,12 +319,12 @@ int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
* The hardware support filter ID (FID) 0..7, I have no clue how to
* support this in the driver when the callback only says on/off.
*/
- ret = smi->ops->get_vlan_4k(smi, port, &vlan4k);
+ ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k);
if (ret)
return ret;
/* Just set the filter to FID 1 for now then */
- ret = rtl8366_set_vlan(smi, port,
+ ret = rtl8366_set_vlan(smi, port + 1,
vlan4k.member,
vlan4k.untag,
1);
diff --git a/drivers/net/dsa/rtl8366rb.c b/drivers/net/dsa/rtl8366rb.c
index 40b3974970c6..a268085ffad2 100644
--- a/drivers/net/dsa/rtl8366rb.c
+++ b/drivers/net/dsa/rtl8366rb.c
@@ -20,7 +20,7 @@
#include <linux/of_irq.h>
#include <linux/regmap.h>
-#include "realtek-smi.h"
+#include "realtek-smi-core.h"
#define RTL8366RB_PORT_NUM_CPU 5
#define RTL8366RB_NUM_PORTS 6
diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
index 1144fc5f61a8..770134a66e48 100644
--- a/drivers/net/dsa/sja1105/Kconfig
+++ b/drivers/net/dsa/sja1105/Kconfig
@@ -9,10 +9,17 @@ tristate "NXP SJA1105 Ethernet switch family support"
This is the driver for the NXP SJA1105 automotive Ethernet switch
family. These are 5-port devices and are managed over an SPI
interface. Probing is handled based on OF bindings and so is the
- linkage to phylib. The driver supports the following revisions:
+ linkage to PHYLINK. The driver supports the following revisions:
- SJA1105E (Gen. 1, No TT-Ethernet)
- SJA1105T (Gen. 1, TT-Ethernet)
- SJA1105P (Gen. 2, No SGMII, No TT-Ethernet)
- SJA1105Q (Gen. 2, No SGMII, TT-Ethernet)
- SJA1105R (Gen. 2, SGMII, No TT-Ethernet)
- SJA1105S (Gen. 2, SGMII, TT-Ethernet)
+
+config NET_DSA_SJA1105_PTP
+ bool "Support for the PTP clock on the NXP SJA1105 Ethernet switch"
+ depends on NET_DSA_SJA1105
+ help
+ This enables support for timestamping and PTP clock manipulations in
+ the SJA1105 DSA driver.
diff --git a/drivers/net/dsa/sja1105/Makefile b/drivers/net/dsa/sja1105/Makefile
index 941848de8b46..9a22f68b39e9 100644
--- a/drivers/net/dsa/sja1105/Makefile
+++ b/drivers/net/dsa/sja1105/Makefile
@@ -8,3 +8,7 @@ sja1105-objs := \
sja1105_clocking.o \
sja1105_static_config.o \
sja1105_dynamic_config.o \
+
+ifdef CONFIG_NET_DSA_SJA1105_PTP
+obj-$(CONFIG_NET_DSA_SJA1105) += sja1105_ptp.o
+endif
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index 61d00682de60..78094db32622 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -5,6 +5,8 @@
#ifndef _SJA1105_H
#define _SJA1105_H
+#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
#include <linux/dsa/sja1105.h>
#include <net/dsa.h>
#include <linux/mutex.h>
@@ -27,9 +29,14 @@ struct sja1105_regs {
u64 rgu;
u64 config;
u64 rmii_pll1;
+ u64 ptp_control;
+ u64 ptpclk;
+ u64 ptpclkrate;
+ u64 ptptsclk;
+ u64 ptpegr_ts[SJA1105_NUM_PORTS];
u64 pad_mii_tx[SJA1105_NUM_PORTS];
+ u64 pad_mii_id[SJA1105_NUM_PORTS];
u64 cgu_idiv[SJA1105_NUM_PORTS];
- u64 rgmii_pad_mii_tx[SJA1105_NUM_PORTS];
u64 mii_tx_clk[SJA1105_NUM_PORTS];
u64 mii_rx_clk[SJA1105_NUM_PORTS];
u64 mii_ext_tx_clk[SJA1105_NUM_PORTS];
@@ -50,9 +57,19 @@ struct sja1105_info {
* switch core and device_id)
*/
u64 part_no;
+ /* E/T and P/Q/R/S have partial timestamps of different sizes.
+ * They must be reconstructed on both families anyway to get the full
+ * 64-bit values back.
+ */
+ int ptp_ts_bits;
+ /* Also SPI commands are of different sizes to retrieve
+ * the egress timestamps.
+ */
+ int ptpegr_ts_bytes;
const struct sja1105_dynamic_table_ops *dyn_ops;
const struct sja1105_table_ops *static_ops;
const struct sja1105_regs *regs;
+ int (*ptp_cmd)(const void *ctx, const void *data);
int (*reset_cmd)(const void *ctx, const void *data);
int (*setup_rgmii_delay)(const void *ctx, int port);
/* Prototypes from include/net/dsa.h */
@@ -72,13 +89,25 @@ struct sja1105_private {
struct spi_device *spidev;
struct dsa_switch *ds;
struct sja1105_port ports[SJA1105_NUM_PORTS];
+ struct ptp_clock_info ptp_caps;
+ struct ptp_clock *clock;
+ /* The cycle counter translates the PTP timestamps (based on
+ * a free-running counter) into a software time domain.
+ */
+ struct cyclecounter tstamp_cc;
+ struct timecounter tstamp_tc;
+ struct delayed_work refresh_work;
+ /* Serializes all operations on the cycle counter */
+ struct mutex ptp_lock;
/* Serializes transmission of management frames so that
* the switch doesn't confuse them with one another.
*/
struct mutex mgmt_lock;
+ struct sja1105_tagger_data tagger_data;
};
#include "sja1105_dynamic_config.h"
+#include "sja1105_ptp.h"
struct sja1105_spi_message {
u64 access;
@@ -102,6 +131,8 @@ int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv,
sja1105_spi_rw_mode_t rw, u64 base_addr,
void *packed_buf, u64 buf_len);
int sja1105_static_config_upload(struct sja1105_private *priv);
+int sja1105_inhibit_tx(const struct sja1105_private *priv,
+ unsigned long port_bitmap, bool tx_inhibited);
extern struct sja1105_info sja1105e_info;
extern struct sja1105_info sja1105t_info;
@@ -130,6 +161,7 @@ typedef enum {
SJA1105_SPEED_AUTO = 0,
} sja1105_speed_t;
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);
diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c
index 94bfe0ee50a8..608126a15d72 100644
--- a/drivers/net/dsa/sja1105/sja1105_clocking.c
+++ b/drivers/net/dsa/sja1105/sja1105_clocking.c
@@ -19,6 +19,17 @@ struct sja1105_cfg_pad_mii_tx {
u64 clk_ipud;
};
+struct sja1105_cfg_pad_mii_id {
+ u64 rxc_stable_ovr;
+ u64 rxc_delay;
+ u64 rxc_bypass;
+ u64 rxc_pd;
+ u64 txc_stable_ovr;
+ u64 txc_delay;
+ u64 txc_bypass;
+ u64 txc_pd;
+};
+
/* UM10944 Table 82.
* IDIV_0_C to IDIV_4_C control registers
* (addr. 10000Bh to 10000Fh)
@@ -373,11 +384,88 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK);
return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
- regs->rgmii_pad_mii_tx[port],
+ regs->pad_mii_tx[port],
packed_buf, SJA1105_SIZE_CGU_CMD);
}
-static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
+static void
+sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+ enum packing_op op)
+{
+ const int size = SJA1105_SIZE_CGU_CMD;
+
+ sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
+ sja1105_packing(buf, &cmd->rxc_delay, 14, 10, size, op);
+ sja1105_packing(buf, &cmd->rxc_bypass, 9, 9, size, op);
+ sja1105_packing(buf, &cmd->rxc_pd, 8, 8, size, op);
+ sja1105_packing(buf, &cmd->txc_stable_ovr, 7, 7, size, op);
+ sja1105_packing(buf, &cmd->txc_delay, 6, 2, size, op);
+ sja1105_packing(buf, &cmd->txc_bypass, 1, 1, size, op);
+ sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
+}
+
+/* Valid range in degrees is an integer between 73.8 and 101.7 */
+static inline u64 sja1105_rgmii_delay(u64 phase)
+{
+ /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
+ * To avoid floating point operations we'll multiply by 10
+ * and get 1 decimal point precision.
+ */
+ phase *= 10;
+ return (phase - 738) / 9;
+}
+
+/* The RGMII delay setup procedure is 2-step and gets called upon each
+ * .phylink_mac_config. Both are strategic.
+ * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
+ * with recovering from a frequency change of the link partner's RGMII clock.
+ * The easiest way to recover from this is to temporarily power down the TDL,
+ * as it will re-lock at the new frequency afterwards.
+ */
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
+{
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ int rc;
+
+ if (priv->rgmii_rx_delay[port])
+ pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+ if (priv->rgmii_tx_delay[port])
+ pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+
+ /* Stage 1: Turn the RGMII delay lines off. */
+ pad_mii_id.rxc_bypass = 1;
+ pad_mii_id.rxc_pd = 1;
+ pad_mii_id.txc_bypass = 1;
+ pad_mii_id.txc_pd = 1;
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+ regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+ if (rc < 0)
+ return rc;
+
+ /* Stage 2: Turn the RGMII delay lines on. */
+ if (priv->rgmii_rx_delay[port]) {
+ pad_mii_id.rxc_bypass = 0;
+ pad_mii_id.rxc_pd = 0;
+ }
+ if (priv->rgmii_tx_delay[port]) {
+ pad_mii_id.txc_bypass = 0;
+ pad_mii_id.txc_pd = 0;
+ }
+ sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+ regs->pad_mii_id[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
+ sja1105_mii_role_t role)
{
struct device *dev = priv->ds->dev;
struct sja1105_mac_config_entry *mac;
@@ -429,6 +517,12 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
}
if (!priv->info->setup_rgmii_delay)
return 0;
+ /* The role has no hardware effect for RGMII. However we use it as
+ * a proxy for this interface being a MAC-to-MAC connection, with
+ * the RGMII internal delays needing to be applied by us.
+ */
+ if (role == XMII_MAC)
+ return 0;
return priv->info->setup_rgmii_delay(priv, port);
}
@@ -575,7 +669,7 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
rc = sja1105_rmii_clocking_setup(priv, port, role);
break;
case XMII_MODE_RGMII:
- rc = sja1105_rgmii_clocking_setup(priv, port);
+ rc = sja1105_rgmii_clocking_setup(priv, port, role);
break;
default:
dev_err(dev, "Invalid interface mode specified: %d\n",
diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
index 352bb6e89297..56c83b9d52e4 100644
--- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c
@@ -378,6 +378,7 @@ struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
.addr = 0x38,
},
[BLK_IDX_L2_FORWARDING_PARAMS] = {0},
+ [BLK_IDX_AVB_PARAMS] = {0},
[BLK_IDX_GENERAL_PARAMS] = {
.entry_packing = sja1105et_general_params_entry_packing,
.cmd_packing = sja1105et_general_params_cmd_packing,
@@ -441,6 +442,7 @@ struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
.addr = 0x38,
},
[BLK_IDX_L2_FORWARDING_PARAMS] = {0},
+ [BLK_IDX_AVB_PARAMS] = {0},
[BLK_IDX_GENERAL_PARAMS] = {
.entry_packing = sja1105et_general_params_entry_packing,
.cmd_packing = sja1105et_general_params_cmd_packing,
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index b151a8fafb9e..9395e8f5f790 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -70,8 +70,7 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
/* Keep standard IFG of 12 bytes on egress. */
.ifg = 0,
/* Always put the MAC speed in automatic mode, where it can be
- * retrieved from the PHY object through phylib and
- * sja1105_adjust_port_config.
+ * adjusted at runtime by PHYLINK.
*/
.speed = SJA1105_SPEED_AUTO,
/* No static correction for 1-step 1588 events */
@@ -116,7 +115,6 @@ static int sja1105_init_mac_settings(struct sja1105_private *priv)
if (!table->entries)
return -ENOMEM;
- /* Override table based on phylib DT bindings */
table->entry_count = SJA1105_NUM_PORTS;
mac = table->entries;
@@ -157,7 +155,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
if (!table->entries)
return -ENOMEM;
- /* Override table based on phylib DT bindings */
+ /* Override table based on PHYLINK DT bindings */
table->entry_count = SJA1105_MAX_XMII_PARAMS_COUNT;
mii = table->entries;
@@ -389,14 +387,14 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
.mirr_ptacu = 0,
.switchid = priv->ds->index,
/* Priority queue for link-local frames trapped to CPU */
- .hostprio = 0,
+ .hostprio = 7,
.mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A,
.mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK,
- .incl_srcpt1 = true,
+ .incl_srcpt1 = false,
.send_meta1 = false,
.mac_fltres0 = SJA1105_LINKLOCAL_FILTER_B,
.mac_flt0 = SJA1105_LINKLOCAL_FILTER_B_MASK,
- .incl_srcpt0 = true,
+ .incl_srcpt0 = false,
.send_meta0 = false,
/* The destination for traffic matching mac_fltres1 and
* mac_fltres0 on all ports except host_port. Such traffic
@@ -508,6 +506,39 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv)
return 0;
}
+static int sja1105_init_avb_params(struct sja1105_private *priv,
+ bool on)
+{
+ struct sja1105_avb_params_entry *avb;
+ struct sja1105_table *table;
+
+ table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS];
+
+ /* Discard previous AVB Parameters Table */
+ if (table->entry_count) {
+ kfree(table->entries);
+ table->entry_count = 0;
+ }
+
+ /* Configure the reception of meta frames only if requested */
+ if (!on)
+ return 0;
+
+ table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT,
+ table->ops->unpacked_entry_size, GFP_KERNEL);
+ if (!table->entries)
+ return -ENOMEM;
+
+ table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT;
+
+ avb = table->entries;
+
+ avb->destmeta = SJA1105_META_DMAC;
+ avb->srcmeta = SJA1105_META_SMAC;
+
+ return 0;
+}
+
static int sja1105_static_config_load(struct sja1105_private *priv,
struct sja1105_dt_port *ports)
{
@@ -548,6 +579,9 @@ static int sja1105_static_config_load(struct sja1105_private *priv,
rc = sja1105_init_general_params(priv);
if (rc < 0)
return rc;
+ rc = sja1105_init_avb_params(priv, false);
+ if (rc < 0)
+ return rc;
/* Send initial configuration to hardware via SPI */
return sja1105_static_config_upload(priv);
@@ -653,36 +687,18 @@ static int sja1105_parse_dt(struct sja1105_private *priv,
return rc;
}
-/* Convert back and forth MAC speed from Mbps to SJA1105 encoding */
+/* Convert link speed from SJA1105 to ethtool encoding */
static int sja1105_speed[] = {
- [SJA1105_SPEED_AUTO] = 0,
- [SJA1105_SPEED_10MBPS] = 10,
- [SJA1105_SPEED_100MBPS] = 100,
- [SJA1105_SPEED_1000MBPS] = 1000,
+ [SJA1105_SPEED_AUTO] = SPEED_UNKNOWN,
+ [SJA1105_SPEED_10MBPS] = SPEED_10,
+ [SJA1105_SPEED_100MBPS] = SPEED_100,
+ [SJA1105_SPEED_1000MBPS] = SPEED_1000,
};
-static sja1105_speed_t sja1105_get_speed_cfg(unsigned int speed_mbps)
-{
- int i;
-
- for (i = SJA1105_SPEED_AUTO; i <= SJA1105_SPEED_1000MBPS; i++)
- if (sja1105_speed[i] == speed_mbps)
- return i;
- return -EINVAL;
-}
-
-/* Set link speed and enable/disable traffic I/O in the MAC configuration
- * for a specific port.
- *
- * @speed_mbps: If 0, leave the speed unchanged, else adapt MAC to PHY speed.
- * @enabled: Manage Rx and Tx settings for this port. If false, overrides the
- * settings from the STP state, but not persistently (does not
- * overwrite the static MAC info for this port).
- */
+/* Set link speed in the MAC configuration for a specific port. */
static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
- int speed_mbps, bool enabled)
+ int speed_mbps)
{
- struct sja1105_mac_config_entry dyn_mac;
struct sja1105_xmii_params_entry *mii;
struct sja1105_mac_config_entry *mac;
struct device *dev = priv->ds->dev;
@@ -690,38 +706,44 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
sja1105_speed_t speed;
int rc;
- mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+ /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
+ * tables. On E/T, MAC reconfig tables are not readable, only writable.
+ * We have to *know* what the MAC looks like. For the sake of keeping
+ * the code common, we'll use the static configuration tables as a
+ * reasonable approximation for both E/T and P/Q/R/S.
+ */
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
+ mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
- speed = sja1105_get_speed_cfg(speed_mbps);
- if (speed_mbps && speed < 0) {
+ switch (speed_mbps) {
+ case SPEED_UNKNOWN:
+ /* No speed update requested */
+ speed = SJA1105_SPEED_AUTO;
+ break;
+ case SPEED_10:
+ speed = SJA1105_SPEED_10MBPS;
+ break;
+ case SPEED_100:
+ speed = SJA1105_SPEED_100MBPS;
+ break;
+ case SPEED_1000:
+ speed = SJA1105_SPEED_1000MBPS;
+ break;
+ default:
dev_err(dev, "Invalid speed %iMbps\n", speed_mbps);
return -EINVAL;
}
- /* If requested, overwrite SJA1105_SPEED_AUTO from the static MAC
- * configuration table, since this will be used for the clocking setup,
- * and we no longer need to store it in the static config (already told
- * hardware we want auto during upload phase).
+ /* Overwrite SJA1105_SPEED_AUTO from the static MAC configuration
+ * table, since this will be used for the clocking setup, and we no
+ * longer need to store it in the static config (already told hardware
+ * we want auto during upload phase).
*/
- if (speed_mbps)
- mac[port].speed = speed;
- else
- mac[port].speed = SJA1105_SPEED_AUTO;
-
- /* On P/Q/R/S, one can read from the device via the MAC reconfiguration
- * tables. On E/T, MAC reconfig tables are not readable, only writable.
- * We have to *know* what the MAC looks like. For the sake of keeping
- * the code common, we'll use the static configuration tables as a
- * reasonable approximation for both E/T and P/Q/R/S.
- */
- dyn_mac = mac[port];
- dyn_mac.ingress = enabled && mac[port].ingress;
- dyn_mac.egress = enabled && mac[port].egress;
+ mac[port].speed = speed;
/* Write to the dynamic reconfiguration tables */
- rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG,
- port, &dyn_mac, true);
+ rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port,
+ &mac[port], true);
if (rc < 0) {
dev_err(dev, "Failed to write MAC config: %d\n", rc);
return rc;
@@ -733,9 +755,6 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
* the clock setup does interrupt the clock signal for a certain time
* which causes trouble for all PHYs relying on this signal.
*/
- if (!enabled)
- return 0;
-
phy_mode = mii->xmii_mode[port];
if (phy_mode != XMII_MODE_RGMII)
return 0;
@@ -750,9 +769,24 @@ static void sja1105_mac_config(struct dsa_switch *ds, int port,
struct sja1105_private *priv = ds->priv;
if (!state->link)
- sja1105_adjust_port_config(priv, port, 0, false);
- else
- sja1105_adjust_port_config(priv, port, state->speed, true);
+ return;
+
+ sja1105_adjust_port_config(priv, port, state->speed);
+}
+
+static void sja1105_mac_link_down(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface)
+{
+ sja1105_inhibit_tx(ds->priv, BIT(port), true);
+}
+
+static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+ struct phy_device *phydev)
+{
+ sja1105_inhibit_tx(ds->priv, BIT(port), false);
}
static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
@@ -1207,27 +1241,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
sja1105_bridge_member(ds, port, br, false);
}
-static u8 sja1105_stp_state_get(struct sja1105_private *priv, int port)
-{
- struct sja1105_mac_config_entry *mac;
-
- mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
-
- if (!mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
- return BR_STATE_BLOCKING;
- if (mac[port].ingress && !mac[port].egress && !mac[port].dyn_learn)
- return BR_STATE_LISTENING;
- if (mac[port].ingress && !mac[port].egress && mac[port].dyn_learn)
- return BR_STATE_LEARNING;
- if (mac[port].ingress && mac[port].egress && mac[port].dyn_learn)
- return BR_STATE_FORWARDING;
- /* This is really an error condition if the MAC was in none of the STP
- * states above. But treating the port as disabled does nothing, which
- * is adequate, and it also resets the MAC to a known state later on.
- */
- return BR_STATE_DISABLED;
-}
-
/* For situations where we need to change a setting at runtime that is only
* available through the static configuration, resetting the switch in order
* to upload the new static config is unavoidable. Back up the settings we
@@ -1238,27 +1251,18 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
{
struct sja1105_mac_config_entry *mac;
int speed_mbps[SJA1105_NUM_PORTS];
- u8 stp_state[SJA1105_NUM_PORTS];
int rc, i;
mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries;
- /* Back up settings changed by sja1105_adjust_port_config and
- * sja1105_bridge_stp_state_set and restore their defaults.
+ /* Back up the dynamic link speed changed by sja1105_adjust_port_config
+ * in order to temporarily restore it to SJA1105_SPEED_AUTO - which the
+ * switch wants to see in the static config in order to allow us to
+ * change it through the dynamic interface later.
*/
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
speed_mbps[i] = sja1105_speed[mac[i].speed];
mac[i].speed = SJA1105_SPEED_AUTO;
- if (i == dsa_upstream_port(priv->ds, i)) {
- mac[i].ingress = true;
- mac[i].egress = true;
- mac[i].dyn_learn = true;
- } else {
- stp_state[i] = sja1105_stp_state_get(priv, i);
- mac[i].ingress = false;
- mac[i].egress = false;
- mac[i].dyn_learn = false;
- }
}
/* Reset switch and send updated static configuration */
@@ -1275,13 +1279,7 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
goto out;
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
- bool enabled = (speed_mbps[i] != 0);
-
- if (i != dsa_upstream_port(priv->ds, i))
- sja1105_bridge_stp_state_set(priv->ds, i, stp_state[i]);
-
- rc = sja1105_adjust_port_config(priv, i, speed_mbps[i],
- enabled);
+ rc = sja1105_adjust_port_config(priv, i, speed_mbps[i]);
if (rc < 0)
goto out;
}
@@ -1289,23 +1287,6 @@ out:
return rc;
}
-/* The TPID setting belongs to the General Parameters table,
- * which can only be partially reconfigured at runtime (and not the TPID).
- * So a switch reset is required.
- */
-static int sja1105_change_tpid(struct sja1105_private *priv,
- u16 tpid, u16 tpid2)
-{
- struct sja1105_general_params_entry *general_params;
- struct sja1105_table *table;
-
- table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
- general_params = table->entries;
- general_params->tpid = tpid;
- general_params->tpid2 = tpid2;
- return sja1105_static_config_reload(priv);
-}
-
static int sja1105_pvid_apply(struct sja1105_private *priv, int port, u16 pvid)
{
struct sja1105_mac_config_entry *mac;
@@ -1424,17 +1405,41 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
return 0;
}
+/* The TPID setting belongs to the General Parameters table,
+ * which can only be partially reconfigured at runtime (and not the TPID).
+ * So a switch reset is required.
+ */
static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
{
+ struct sja1105_general_params_entry *general_params;
struct sja1105_private *priv = ds->priv;
+ struct sja1105_table *table;
+ u16 tpid, tpid2;
int rc;
- if (enabled)
+ if (enabled) {
/* Enable VLAN filtering. */
- rc = sja1105_change_tpid(priv, ETH_P_8021Q, ETH_P_8021AD);
- else
+ tpid = ETH_P_8021AD;
+ tpid2 = ETH_P_8021Q;
+ } else {
/* Disable VLAN filtering. */
- rc = sja1105_change_tpid(priv, ETH_P_SJA1105, ETH_P_SJA1105);
+ tpid = ETH_P_SJA1105;
+ tpid2 = ETH_P_SJA1105;
+ }
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+ general_params = table->entries;
+ /* EtherType used to identify outer tagged (S-tag) VLAN traffic */
+ general_params->tpid = tpid;
+ /* EtherType used to identify inner tagged (C-tag) VLAN traffic */
+ general_params->tpid2 = tpid2;
+ /* When VLAN filtering is on, we need to at least be able to
+ * decode management traffic through the "backup plan".
+ */
+ general_params->incl_srcpt1 = enabled;
+ general_params->incl_srcpt0 = enabled;
+
+ rc = sja1105_static_config_reload(priv);
if (rc)
dev_err(ds->dev, "Failed to change VLAN Ethertype\n");
@@ -1523,6 +1528,11 @@ static int sja1105_setup(struct dsa_switch *ds)
return rc;
}
+ rc = sja1105_ptp_clock_register(priv);
+ if (rc < 0) {
+ dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc);
+ return rc;
+ }
/* Create and send configuration down to device */
rc = sja1105_static_config_load(priv, ports);
if (rc < 0) {
@@ -1552,8 +1562,16 @@ static int sja1105_setup(struct dsa_switch *ds)
return sja1105_setup_8021q_tagging(ds, true);
}
+static void sja1105_teardown(struct dsa_switch *ds)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ cancel_work_sync(&priv->tagger_data.rxtstamp_work);
+ skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue);
+}
+
static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
- struct sk_buff *skb)
+ struct sk_buff *skb, bool takets)
{
struct sja1105_mgmt_entry mgmt_route = {0};
struct sja1105_private *priv = ds->priv;
@@ -1566,6 +1584,8 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
mgmt_route.macaddr = ether_addr_to_u64(hdr->h_dest);
mgmt_route.destports = BIT(port);
mgmt_route.enfport = 1;
+ mgmt_route.tsreg = 0;
+ mgmt_route.takets = takets;
rc = sja1105_dynamic_config_write(priv, BLK_IDX_MGMT_ROUTE,
slot, &mgmt_route, true);
@@ -1617,7 +1637,11 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port,
{
struct sja1105_private *priv = ds->priv;
struct sja1105_port *sp = &priv->ports[port];
+ struct skb_shared_hwtstamps shwt = {0};
int slot = sp->mgmt_slot;
+ struct sk_buff *clone;
+ u64 now, ts;
+ int rc;
/* The tragic fact about the switch having 4x2 slots for installing
* management routes is that all of them except one are actually
@@ -1635,8 +1659,36 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port,
*/
mutex_lock(&priv->mgmt_lock);
- sja1105_mgmt_xmit(ds, port, slot, skb);
+ /* The clone, if there, was made by dsa_skb_tx_timestamp */
+ clone = DSA_SKB_CB(skb)->clone;
+
+ sja1105_mgmt_xmit(ds, port, slot, skb, !!clone);
+
+ if (!clone)
+ goto out;
+
+ skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
+
+ mutex_lock(&priv->ptp_lock);
+
+ now = priv->tstamp_cc.read(&priv->tstamp_cc);
+
+ rc = sja1105_ptpegr_ts_poll(priv, slot, &ts);
+ if (rc < 0) {
+ dev_err(ds->dev, "xmit: timed out polling for tstamp\n");
+ kfree_skb(clone);
+ goto out_unlock_ptp;
+ }
+
+ ts = sja1105_tstamp_reconstruct(priv, now, ts);
+ ts = timecounter_cyc2time(&priv->tstamp_tc, ts);
+ shwt.hwtstamp = ns_to_ktime(ts);
+ skb_complete_tx_timestamp(clone, &shwt);
+
+out_unlock_ptp:
+ mutex_unlock(&priv->ptp_lock);
+out:
mutex_unlock(&priv->mgmt_lock);
return NETDEV_TX_OK;
}
@@ -1665,15 +1717,180 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds,
return sja1105_static_config_reload(priv);
}
+/* Caller must hold priv->tagger_data.meta_lock */
+static int sja1105_change_rxtstamping(struct sja1105_private *priv,
+ bool on)
+{
+ struct sja1105_general_params_entry *general_params;
+ struct sja1105_table *table;
+ int rc;
+
+ table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS];
+ general_params = table->entries;
+ general_params->send_meta1 = on;
+ general_params->send_meta0 = on;
+
+ rc = sja1105_init_avb_params(priv, on);
+ if (rc < 0)
+ return rc;
+
+ /* Initialize the meta state machine to a known state */
+ if (priv->tagger_data.stampable_skb) {
+ kfree_skb(priv->tagger_data.stampable_skb);
+ priv->tagger_data.stampable_skb = NULL;
+ }
+
+ return sja1105_static_config_reload(priv);
+}
+
+static int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct hwtstamp_config config;
+ bool rx_on;
+ int rc;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->ports[port].hwts_tx_en = false;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->ports[port].hwts_tx_en = true;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ rx_on = false;
+ break;
+ default:
+ rx_on = true;
+ break;
+ }
+
+ if (rx_on != priv->tagger_data.hwts_rx_en) {
+ spin_lock(&priv->tagger_data.meta_lock);
+ rc = sja1105_change_rxtstamping(priv, rx_on);
+ spin_unlock(&priv->tagger_data.meta_lock);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to change RX timestamping: %d\n", rc);
+ return -EFAULT;
+ }
+ priv->tagger_data.hwts_rx_en = rx_on;
+ }
+
+ if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+ return -EFAULT;
+ return 0;
+}
+
+static int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
+ struct ifreq *ifr)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct hwtstamp_config config;
+
+ config.flags = 0;
+ if (priv->ports[port].hwts_tx_en)
+ config.tx_type = HWTSTAMP_TX_ON;
+ else
+ config.tx_type = HWTSTAMP_TX_OFF;
+ if (priv->tagger_data.hwts_rx_en)
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ else
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+#define to_tagger(d) \
+ container_of((d), struct sja1105_tagger_data, rxtstamp_work)
+#define to_sja1105(d) \
+ container_of((d), struct sja1105_private, tagger_data)
+
+static void sja1105_rxtstamp_work(struct work_struct *work)
+{
+ struct sja1105_tagger_data *data = to_tagger(work);
+ struct sja1105_private *priv = to_sja1105(data);
+ struct sk_buff *skb;
+ u64 now;
+
+ mutex_lock(&priv->ptp_lock);
+
+ now = priv->tstamp_cc.read(&priv->tstamp_cc);
+
+ while ((skb = skb_dequeue(&data->skb_rxtstamp_queue)) != NULL) {
+ struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
+ u64 ts;
+
+ *shwt = (struct skb_shared_hwtstamps) {0};
+
+ ts = SJA1105_SKB_CB(skb)->meta_tstamp;
+ ts = sja1105_tstamp_reconstruct(priv, now, ts);
+ ts = timecounter_cyc2time(&priv->tstamp_tc, ts);
+
+ shwt->hwtstamp = ns_to_ktime(ts);
+ netif_rx_ni(skb);
+ }
+
+ mutex_unlock(&priv->ptp_lock);
+}
+
+/* Called from dsa_skb_defer_rx_timestamp */
+static bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_tagger_data *data = &priv->tagger_data;
+
+ if (!data->hwts_rx_en)
+ return false;
+
+ /* We need to read the full PTP clock to reconstruct the Rx
+ * timestamp. For that we need a sleepable context.
+ */
+ skb_queue_tail(&data->skb_rxtstamp_queue, skb);
+ schedule_work(&data->rxtstamp_work);
+ return true;
+}
+
+/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone
+ * the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit
+ * callback, where we will timestamp it synchronously.
+ */
+static bool sja1105_port_txtstamp(struct dsa_switch *ds, int port,
+ struct sk_buff *skb, unsigned int type)
+{
+ struct sja1105_private *priv = ds->priv;
+ struct sja1105_port *sp = &priv->ports[port];
+
+ if (!sp->hwts_tx_en)
+ return false;
+
+ return true;
+}
+
static const struct dsa_switch_ops sja1105_switch_ops = {
.get_tag_protocol = sja1105_get_tag_protocol,
.setup = sja1105_setup,
+ .teardown = sja1105_teardown,
.set_ageing_time = sja1105_set_ageing_time,
.phylink_validate = sja1105_phylink_validate,
.phylink_mac_config = sja1105_mac_config,
+ .phylink_mac_link_up = sja1105_mac_link_up,
+ .phylink_mac_link_down = sja1105_mac_link_down,
.get_strings = sja1105_get_strings,
.get_ethtool_stats = sja1105_get_ethtool_stats,
.get_sset_count = sja1105_get_sset_count,
+ .get_ts_info = sja1105_get_ts_info,
.port_fdb_dump = sja1105_fdb_dump,
.port_fdb_add = sja1105_fdb_add,
.port_fdb_del = sja1105_fdb_del,
@@ -1688,6 +1905,10 @@ static const struct dsa_switch_ops sja1105_switch_ops = {
.port_mdb_add = sja1105_mdb_add,
.port_mdb_del = sja1105_mdb_del,
.port_deferred_xmit = sja1105_port_deferred_xmit,
+ .port_hwtstamp_get = sja1105_hwtstamp_get,
+ .port_hwtstamp_set = sja1105_hwtstamp_set,
+ .port_rxtstamp = sja1105_port_rxtstamp,
+ .port_txtstamp = sja1105_port_txtstamp,
};
static int sja1105_check_device_id(struct sja1105_private *priv)
@@ -1728,6 +1949,7 @@ static int sja1105_check_device_id(struct sja1105_private *priv)
static int sja1105_probe(struct spi_device *spi)
{
+ struct sja1105_tagger_data *tagger_data;
struct device *dev = &spi->dev;
struct sja1105_private *priv;
struct dsa_switch *ds;
@@ -1782,12 +2004,17 @@ static int sja1105_probe(struct spi_device *spi)
ds->priv = priv;
priv->ds = ds;
+ tagger_data = &priv->tagger_data;
+ skb_queue_head_init(&tagger_data->skb_rxtstamp_queue);
+ INIT_WORK(&tagger_data->rxtstamp_work, sja1105_rxtstamp_work);
+
/* Connections between dsa_port and sja1105_port */
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
struct sja1105_port *sp = &priv->ports[i];
ds->ports[i].priv = sp;
sp->dp = &ds->ports[i];
+ sp->data = tagger_data;
}
mutex_init(&priv->mgmt_lock);
@@ -1798,6 +2025,7 @@ static int sja1105_remove(struct spi_device *spi)
{
struct sja1105_private *priv = spi_get_drvdata(spi);
+ sja1105_ptp_clock_unregister(priv);
dsa_unregister_switch(priv->ds);
sja1105_static_config_free(&priv->static_config);
return 0;
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c
new file mode 100644
index 000000000000..3041cf9d5856
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
+ */
+#include "sja1105.h"
+
+/* The adjfine API clamps ppb between [-32,768,000, 32,768,000], and
+ * therefore scaled_ppm between [-2,147,483,648, 2,147,483,647].
+ * Set the maximum supported ppb to a round value smaller than the maximum.
+ *
+ * Percentually speaking, this is a +/- 0.032x adjustment of the
+ * free-running counter (0.968x to 1.032x).
+ */
+#define SJA1105_MAX_ADJ_PPB 32000000
+#define SJA1105_SIZE_PTP_CMD 4
+
+/* Timestamps are in units of 8 ns clock ticks (equivalent to a fixed
+ * 125 MHz clock) so the scale factor (MULT / SHIFT) needs to be 8.
+ * Furthermore, wisely pick SHIFT as 28 bits, which translates
+ * MULT into 2^31 (0x80000000). This is the same value around which
+ * the hardware PTPCLKRATE is centered, so the same ppb conversion
+ * arithmetic can be reused.
+ */
+#define SJA1105_CC_SHIFT 28
+#define SJA1105_CC_MULT (8 << SJA1105_CC_SHIFT)
+
+/* Having 33 bits of cycle counter left until a 64-bit overflow during delta
+ * conversion, we multiply this by the 8 ns counter resolution and arrive at
+ * a comfortable 68.71 second refresh interval until the delta would cause
+ * an integer overflow, in absence of any other readout.
+ * Approximate to 1 minute.
+ */
+#define SJA1105_REFRESH_INTERVAL (HZ * 60)
+
+/* This range is actually +/- SJA1105_MAX_ADJ_PPB
+ * divided by 1000 (ppb -> ppm) and with a 16-bit
+ * "fractional" part (actually fixed point).
+ * |
+ * v
+ * Convert scaled_ppm from the +/- ((10^6) << 16) range
+ * into the +/- (1 << 31) range.
+ *
+ * This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC)
+ * and defines the scaling factor between scaled_ppm and the actual
+ * frequency adjustments (both cycle counter and hardware).
+ *
+ * ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16)
+ * simplifies to
+ * ptpclkrate = scaled_ppm * 2^9 / 5^6
+ */
+#define SJA1105_CC_MULT_NUM (1 << 9)
+#define SJA1105_CC_MULT_DEM 15625
+
+#define ptp_to_sja1105(d) container_of((d), struct sja1105_private, ptp_caps)
+#define cc_to_sja1105(d) container_of((d), struct sja1105_private, tstamp_cc)
+#define dw_to_sja1105(d) container_of((d), struct sja1105_private, refresh_work)
+
+struct sja1105_ptp_cmd {
+ u64 resptp; /* reset */
+};
+
+int sja1105_get_ts_info(struct dsa_switch *ds, int port,
+ struct ethtool_ts_info *info)
+{
+ struct sja1105_private *priv = ds->priv;
+
+ /* Called during cleanup */
+ if (!priv->clock)
+ return -ENODEV;
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
+ info->phc_index = ptp_clock_index(priv->clock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sja1105_get_ts_info);
+
+int sja1105et_ptp_cmd(const void *ctx, const void *data)
+{
+ const struct sja1105_ptp_cmd *cmd = data;
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ const int size = SJA1105_SIZE_PTP_CMD;
+ u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
+ /* No need to keep this as part of the structure */
+ u64 valid = 1;
+
+ sja1105_pack(buf, &valid, 31, 31, size);
+ sja1105_pack(buf, &cmd->resptp, 2, 2, size);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
+ buf, SJA1105_SIZE_PTP_CMD);
+}
+EXPORT_SYMBOL_GPL(sja1105et_ptp_cmd);
+
+int sja1105pqrs_ptp_cmd(const void *ctx, const void *data)
+{
+ const struct sja1105_ptp_cmd *cmd = data;
+ const struct sja1105_private *priv = ctx;
+ const struct sja1105_regs *regs = priv->info->regs;
+ const int size = SJA1105_SIZE_PTP_CMD;
+ u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
+ /* No need to keep this as part of the structure */
+ u64 valid = 1;
+
+ sja1105_pack(buf, &valid, 31, 31, size);
+ sja1105_pack(buf, &cmd->resptp, 3, 3, size);
+
+ return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control,
+ buf, SJA1105_SIZE_PTP_CMD);
+}
+EXPORT_SYMBOL_GPL(sja1105pqrs_ptp_cmd);
+
+/* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap
+ * around in 0.135 seconds, and 32 bits for P/Q/R/S, wrapping around in 34.35
+ * seconds).
+ *
+ * This receives the RX or TX MAC timestamps, provided by hardware as
+ * the lower bits of the cycle counter, sampled at the time the timestamp was
+ * collected.
+ *
+ * To reconstruct into a full 64-bit-wide timestamp, the cycle counter is
+ * read and the high-order bits are filled in.
+ *
+ * Must be called within one wraparound period of the partial timestamp since
+ * it was generated by the MAC.
+ */
+u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now,
+ u64 ts_partial)
+{
+ u64 partial_tstamp_mask = CYCLECOUNTER_MASK(priv->info->ptp_ts_bits);
+ u64 ts_reconstructed;
+
+ ts_reconstructed = (now & ~partial_tstamp_mask) | ts_partial;
+
+ /* Check lower bits of current cycle counter against the timestamp.
+ * If the current cycle counter is lower than the partial timestamp,
+ * then wraparound surely occurred and must be accounted for.
+ */
+ if ((now & partial_tstamp_mask) <= ts_partial)
+ ts_reconstructed -= (partial_tstamp_mask + 1);
+
+ return ts_reconstructed;
+}
+EXPORT_SYMBOL_GPL(sja1105_tstamp_reconstruct);
+
+/* Reads the SPI interface for an egress timestamp generated by the switch
+ * for frames sent using management routes.
+ *
+ * SJA1105 E/T layout of the 4-byte SPI payload:
+ *
+ * 31 23 15 7 0
+ * | | | | |
+ * +-----+-----+-----+ ^
+ * ^ |
+ * | |
+ * 24-bit timestamp Update bit
+ *
+ *
+ * SJA1105 P/Q/R/S layout of the 8-byte SPI payload:
+ *
+ * 31 23 15 7 0 63 55 47 39 32
+ * | | | | | | | | | |
+ * ^ +-----+-----+-----+-----+
+ * | ^
+ * | |
+ * Update bit 32-bit timestamp
+ *
+ * Notice that the update bit is in the same place.
+ * To have common code for E/T and P/Q/R/S for reading the timestamp,
+ * we need to juggle with the offset and the bit indices.
+ */
+int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ int tstamp_bit_start, tstamp_bit_end;
+ int timeout = 10;
+ u8 packed_buf[8];
+ u64 update;
+ int rc;
+
+ do {
+ rc = sja1105_spi_send_packed_buf(priv, SPI_READ,
+ regs->ptpegr_ts[port],
+ packed_buf,
+ priv->info->ptpegr_ts_bytes);
+ if (rc < 0)
+ return rc;
+
+ sja1105_unpack(packed_buf, &update, 0, 0,
+ priv->info->ptpegr_ts_bytes);
+ if (update)
+ break;
+
+ usleep_range(10, 50);
+ } while (--timeout);
+
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ /* Point the end bit to the second 32-bit word on P/Q/R/S,
+ * no-op on E/T.
+ */
+ tstamp_bit_end = (priv->info->ptpegr_ts_bytes - 4) * 8;
+ /* Shift the 24-bit timestamp on E/T to be collected from 31:8.
+ * No-op on P/Q/R/S.
+ */
+ tstamp_bit_end += 32 - priv->info->ptp_ts_bits;
+ tstamp_bit_start = tstamp_bit_end + priv->info->ptp_ts_bits - 1;
+
+ *ts = 0;
+
+ sja1105_unpack(packed_buf, ts, tstamp_bit_start, tstamp_bit_end,
+ priv->info->ptpegr_ts_bytes);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sja1105_ptpegr_ts_poll);
+
+int sja1105_ptp_reset(struct sja1105_private *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+ struct sja1105_ptp_cmd cmd = {0};
+ int rc;
+
+ mutex_lock(&priv->ptp_lock);
+
+ cmd.resptp = 1;
+ dev_dbg(ds->dev, "Resetting PTP clock\n");
+ rc = priv->info->ptp_cmd(priv, &cmd);
+
+ timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc,
+ ktime_to_ns(ktime_get_real()));
+
+ mutex_unlock(&priv->ptp_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(sja1105_ptp_reset);
+
+static int sja1105_ptp_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ u64 ns;
+
+ mutex_lock(&priv->ptp_lock);
+ ns = timecounter_read(&priv->tstamp_tc);
+ mutex_unlock(&priv->ptp_lock);
+
+ *ts = ns_to_timespec64(ns);
+
+ return 0;
+}
+
+static int sja1105_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ u64 ns = timespec64_to_ns(ts);
+
+ mutex_lock(&priv->ptp_lock);
+ timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, ns);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+ s64 clkrate;
+
+ clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM;
+ clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM);
+
+ mutex_lock(&priv->ptp_lock);
+
+ /* Force a readout to update the timer *before* changing its frequency.
+ *
+ * This way, its corrected time curve can at all times be modeled
+ * as a linear "A * x + B" function, where:
+ *
+ * - B are past frequency adjustments and offset shifts, all
+ * accumulated into the cycle_last variable.
+ *
+ * - A is the new frequency adjustments we're just about to set.
+ *
+ * Reading now makes B accumulate the correct amount of time,
+ * corrected at the old rate, before changing it.
+ *
+ * Hardware timestamps then become simple points on the curve and
+ * are approximated using the above function. This is still better
+ * than letting the switch take the timestamps using the hardware
+ * rate-corrected clock (PTPCLKVAL) - the comparison in this case would
+ * be that we're shifting the ruler at the same time as we're taking
+ * measurements with it.
+ *
+ * The disadvantage is that it's possible to receive timestamps when
+ * a frequency adjustment took place in the near past.
+ * In this case they will be approximated using the new ppb value
+ * instead of a compound function made of two segments (one at the old
+ * and the other at the new rate) - introducing some inaccuracy.
+ */
+ timecounter_read(&priv->tstamp_tc);
+
+ priv->tstamp_cc.mult = SJA1105_CC_MULT + clkrate;
+
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct sja1105_private *priv = ptp_to_sja1105(ptp);
+
+ mutex_lock(&priv->ptp_lock);
+ timecounter_adjtime(&priv->tstamp_tc, delta);
+ mutex_unlock(&priv->ptp_lock);
+
+ return 0;
+}
+
+static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc)
+{
+ struct sja1105_private *priv = cc_to_sja1105(cc);
+ const struct sja1105_regs *regs = priv->info->regs;
+ u64 ptptsclk = 0;
+ int rc;
+
+ rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptptsclk,
+ &ptptsclk, 8);
+ if (rc < 0)
+ dev_err_ratelimited(priv->ds->dev,
+ "failed to read ptp cycle counter: %d\n",
+ rc);
+ return ptptsclk;
+}
+
+static void sja1105_ptp_overflow_check(struct work_struct *work)
+{
+ struct delayed_work *dw = to_delayed_work(work);
+ struct sja1105_private *priv = dw_to_sja1105(dw);
+ struct timespec64 ts;
+
+ sja1105_ptp_gettime(&priv->ptp_caps, &ts);
+
+ schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
+}
+
+static const struct ptp_clock_info sja1105_ptp_caps = {
+ .owner = THIS_MODULE,
+ .name = "SJA1105 PHC",
+ .adjfine = sja1105_ptp_adjfine,
+ .adjtime = sja1105_ptp_adjtime,
+ .gettime64 = sja1105_ptp_gettime,
+ .settime64 = sja1105_ptp_settime,
+ .max_adj = SJA1105_MAX_ADJ_PPB,
+};
+
+int sja1105_ptp_clock_register(struct sja1105_private *priv)
+{
+ struct dsa_switch *ds = priv->ds;
+
+ /* Set up the cycle counter */
+ priv->tstamp_cc = (struct cyclecounter) {
+ .read = sja1105_ptptsclk_read,
+ .mask = CYCLECOUNTER_MASK(64),
+ .shift = SJA1105_CC_SHIFT,
+ .mult = SJA1105_CC_MULT,
+ };
+ mutex_init(&priv->ptp_lock);
+ INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
+
+ schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
+
+ priv->ptp_caps = sja1105_ptp_caps;
+
+ priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev);
+ if (IS_ERR_OR_NULL(priv->clock))
+ return PTR_ERR(priv->clock);
+
+ return sja1105_ptp_reset(priv);
+}
+EXPORT_SYMBOL_GPL(sja1105_ptp_clock_register);
+
+void sja1105_ptp_clock_unregister(struct sja1105_private *priv)
+{
+ if (IS_ERR_OR_NULL(priv->clock))
+ return;
+
+ ptp_clock_unregister(priv->clock);
+ priv->clock = NULL;
+}
+EXPORT_SYMBOL_GPL(sja1105_ptp_clock_unregister);
+
+MODULE_AUTHOR("Vladimir Oltean <olteanv@gmail.com>");
+MODULE_DESCRIPTION("SJA1105 PHC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h
new file mode 100644
index 000000000000..af456b0a4d27
--- /dev/null
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
+ */
+#ifndef _SJA1105_PTP_H
+#define _SJA1105_PTP_H
+
+#if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP)
+
+int sja1105_ptp_clock_register(struct sja1105_private *priv);
+
+void sja1105_ptp_clock_unregister(struct sja1105_private *priv);
+
+int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts);
+
+int sja1105et_ptp_cmd(const void *ctx, const void *data);
+
+int sja1105pqrs_ptp_cmd(const void *ctx, const void *data);
+
+int sja1105_get_ts_info(struct dsa_switch *ds, int port,
+ struct ethtool_ts_info *ts);
+
+u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now,
+ u64 ts_partial);
+
+int sja1105_ptp_reset(struct sja1105_private *priv);
+
+#else
+
+static inline int sja1105_ptp_clock_register(struct sja1105_private *priv)
+{
+ return 0;
+}
+
+static inline void sja1105_ptp_clock_unregister(struct sja1105_private *priv)
+{
+ return;
+}
+
+static inline int
+sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts)
+{
+ return 0;
+}
+
+static inline u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv,
+ u64 now, u64 ts_partial)
+{
+ return 0;
+}
+
+static inline int sja1105_ptp_reset(struct sja1105_private *priv)
+{
+ return 0;
+}
+
+#define sja1105et_ptp_cmd NULL
+
+#define sja1105pqrs_ptp_cmd NULL
+
+#define sja1105_get_ts_info NULL
+
+#endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) */
+
+#endif /* _SJA1105_PTP_H */
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index b1344ed1697f..f7e51debb930 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -100,6 +100,7 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv,
return 0;
}
+EXPORT_SYMBOL_GPL(sja1105_spi_send_packed_buf);
/* If @rw is:
* - SPI_WRITE: creates and sends an SPI write message at absolute
@@ -135,6 +136,7 @@ int sja1105_spi_send_int(const struct sja1105_private *priv,
return rc;
}
+EXPORT_SYMBOL_GPL(sja1105_spi_send_int);
/* Should be used if a @packed_buf larger than SJA1105_SIZE_SPI_MSG_MAXLEN
* must be sent/received. Splitting the buffer into chunks and assembling
@@ -283,20 +285,22 @@ static int sja1105_cold_reset(const struct sja1105_private *priv)
return priv->info->reset_cmd(priv, &reset);
}
-static int sja1105_inhibit_tx(const struct sja1105_private *priv,
- const unsigned long *port_bitmap)
+int sja1105_inhibit_tx(const struct sja1105_private *priv,
+ unsigned long port_bitmap, bool tx_inhibited)
{
const struct sja1105_regs *regs = priv->info->regs;
u64 inhibit_cmd;
- int port, rc;
+ int rc;
rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
if (rc < 0)
return rc;
- for_each_set_bit(port, port_bitmap, SJA1105_NUM_PORTS)
- inhibit_cmd |= BIT(port);
+ if (tx_inhibited)
+ inhibit_cmd |= port_bitmap;
+ else
+ inhibit_cmd &= ~port_bitmap;
return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control,
&inhibit_cmd, SJA1105_SIZE_PORT_CTRL);
@@ -413,7 +417,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv)
* Tx on all ports and waiting for current packet to drain.
* Otherwise, the PHY will see an unterminated Ethernet packet.
*/
- rc = sja1105_inhibit_tx(priv, &port_bitmap);
+ rc = sja1105_inhibit_tx(priv, port_bitmap, true);
if (rc < 0) {
dev_err(dev, "Failed to inhibit Tx on ports\n");
return -ENXIO;
@@ -478,7 +482,12 @@ int sja1105_static_config_upload(struct sja1105_private *priv)
dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries);
}
+ rc = sja1105_ptp_reset(priv);
+ if (rc < 0)
+ dev_err(dev, "Failed to reset PTP clock: %d\n", rc);
+
dev_info(dev, "Reset switch and programmed static config\n");
+
out:
kfree(config_buf);
return rc;
@@ -491,11 +500,10 @@ static struct sja1105_regs sja1105et_regs = {
.port_control = 0x11,
.config = 0x020000,
.rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- /* UM10944.pdf, Table 86, ACU Register overview */
- .rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -507,6 +515,11 @@ static struct sja1105_regs sja1105et_regs = {
.rgmii_tx_clk = {0x100016, 0x10001D, 0x100024, 0x10002B, 0x100032},
.rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031},
.rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034},
+ .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8},
+ .ptp_control = 0x17,
+ .ptpclk = 0x18, /* Spans 0x18 to 0x19 */
+ .ptpclkrate = 0x1A,
+ .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */
};
static struct sja1105_regs sja1105pqrs_regs = {
@@ -516,11 +529,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
.port_control = 0x12,
.config = 0x020000,
.rgu = 0x100440,
+ /* UM10944.pdf, Table 86, ACU Register overview */
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+ .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
- /* UM10944.pdf, Table 86, ACU Register overview */
- .rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -533,6 +546,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
.rmii_ref_clk = {0x100015, 0x10001B, 0x100021, 0x100027, 0x10002D},
.rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F},
.qlevel = {0x604, 0x614, 0x624, 0x634, 0x644},
+ .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0},
+ .ptp_control = 0x18,
+ .ptpclk = 0x19,
+ .ptpclkrate = 0x1B,
+ .ptptsclk = 0x1C,
};
struct sja1105_info sja1105e_info = {
@@ -540,9 +558,12 @@ struct sja1105_info sja1105e_info = {
.part_no = SJA1105ET_PART_NO,
.static_ops = sja1105e_table_ops,
.dyn_ops = sja1105et_dyn_ops,
+ .ptp_ts_bits = 24,
+ .ptpegr_ts_bytes = 4,
.reset_cmd = sja1105et_reset_cmd,
.fdb_add_cmd = sja1105et_fdb_add,
.fdb_del_cmd = sja1105et_fdb_del,
+ .ptp_cmd = sja1105et_ptp_cmd,
.regs = &sja1105et_regs,
.name = "SJA1105E",
};
@@ -551,9 +572,12 @@ struct sja1105_info sja1105t_info = {
.part_no = SJA1105ET_PART_NO,
.static_ops = sja1105t_table_ops,
.dyn_ops = sja1105et_dyn_ops,
+ .ptp_ts_bits = 24,
+ .ptpegr_ts_bytes = 4,
.reset_cmd = sja1105et_reset_cmd,
.fdb_add_cmd = sja1105et_fdb_add,
.fdb_del_cmd = sja1105et_fdb_del,
+ .ptp_cmd = sja1105et_ptp_cmd,
.regs = &sja1105et_regs,
.name = "SJA1105T",
};
@@ -562,9 +586,13 @@ struct sja1105_info sja1105p_info = {
.part_no = SJA1105P_PART_NO,
.static_ops = sja1105p_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
.fdb_add_cmd = sja1105pqrs_fdb_add,
.fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105P",
};
@@ -573,9 +601,13 @@ struct sja1105_info sja1105q_info = {
.part_no = SJA1105Q_PART_NO,
.static_ops = sja1105q_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
.fdb_add_cmd = sja1105pqrs_fdb_add,
.fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105Q",
};
@@ -584,9 +616,13 @@ struct sja1105_info sja1105r_info = {
.part_no = SJA1105R_PART_NO,
.static_ops = sja1105r_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
.fdb_add_cmd = sja1105pqrs_fdb_add,
.fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.regs = &sja1105pqrs_regs,
.name = "SJA1105R",
};
@@ -596,8 +632,12 @@ struct sja1105_info sja1105s_info = {
.static_ops = sja1105s_table_ops,
.dyn_ops = sja1105pqrs_dyn_ops,
.regs = &sja1105pqrs_regs,
+ .ptp_ts_bits = 32,
+ .ptpegr_ts_bytes = 8,
+ .setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
.reset_cmd = sja1105pqrs_reset_cmd,
.fdb_add_cmd = sja1105pqrs_fdb_add,
.fdb_del_cmd = sja1105pqrs_fdb_del,
+ .ptp_cmd = sja1105pqrs_ptp_cmd,
.name = "SJA1105S",
};
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c
index 6d65a7b09395..58f273eaf1ea 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.c
@@ -35,6 +35,7 @@ void sja1105_pack(void *buf, const u64 *val, int start, int end, size_t len)
}
dump_stack();
}
+EXPORT_SYMBOL_GPL(sja1105_pack);
void sja1105_unpack(const void *buf, u64 *val, int start, int end, size_t len)
{
@@ -52,6 +53,7 @@ void sja1105_unpack(const void *buf, u64 *val, int start, int end, size_t len)
start, end);
dump_stack();
}
+EXPORT_SYMBOL_GPL(sja1105_unpack);
void sja1105_packing(void *buf, u64 *val, int start, int end,
size_t len, enum packing_op op)
@@ -74,6 +76,7 @@ void sja1105_packing(void *buf, u64 *val, int start, int end,
}
dump_stack();
}
+EXPORT_SYMBOL_GPL(sja1105_packing);
/* Little-endian Ethernet CRC32 of data packed as big-endian u32 words */
u32 sja1105_crc32(const void *buf, size_t len)
@@ -91,6 +94,28 @@ u32 sja1105_crc32(const void *buf, size_t len)
return ~crc;
}
+static size_t sja1105et_avb_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY;
+ struct sja1105_avb_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->destmeta, 95, 48, size, op);
+ sja1105_packing(buf, &entry->srcmeta, 47, 0, size, op);
+ return size;
+}
+
+static size_t sja1105pqrs_avb_params_entry_packing(void *buf, void *entry_ptr,
+ enum packing_op op)
+{
+ const size_t size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY;
+ struct sja1105_avb_params_entry *entry = entry_ptr;
+
+ sja1105_packing(buf, &entry->destmeta, 125, 78, size, op);
+ sja1105_packing(buf, &entry->srcmeta, 77, 30, size, op);
+ return size;
+}
+
static size_t sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
@@ -423,6 +448,7 @@ static u64 blk_id_map[BLK_IDX_MAX] = {
[BLK_IDX_MAC_CONFIG] = BLKID_MAC_CONFIG,
[BLK_IDX_L2_LOOKUP_PARAMS] = BLKID_L2_LOOKUP_PARAMS,
[BLK_IDX_L2_FORWARDING_PARAMS] = BLKID_L2_FORWARDING_PARAMS,
+ [BLK_IDX_AVB_PARAMS] = BLKID_AVB_PARAMS,
[BLK_IDX_GENERAL_PARAMS] = BLKID_GENERAL_PARAMS,
[BLK_IDX_XMII_PARAMS] = BLKID_XMII_PARAMS,
};
@@ -624,6 +650,12 @@ struct sja1105_table_ops sja1105e_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105et_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105et_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -682,6 +714,12 @@ struct sja1105_table_ops sja1105t_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105et_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105ET_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105et_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -740,6 +778,12 @@ struct sja1105_table_ops sja1105p_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -798,6 +842,12 @@ struct sja1105_table_ops sja1105q_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -856,6 +906,12 @@ struct sja1105_table_ops sja1105r_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
@@ -914,6 +970,12 @@ struct sja1105_table_ops sja1105s_table_ops[BLK_IDX_MAX] = {
.packed_entry_size = SJA1105_SIZE_L2_FORWARDING_PARAMS_ENTRY,
.max_entry_count = SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT,
},
+ [BLK_IDX_AVB_PARAMS] = {
+ .packing = sja1105pqrs_avb_params_entry_packing,
+ .unpacked_entry_size = sizeof(struct sja1105_avb_params_entry),
+ .packed_entry_size = SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY,
+ .max_entry_count = SJA1105_MAX_AVB_PARAMS_COUNT,
+ },
[BLK_IDX_GENERAL_PARAMS] = {
.packing = sja1105pqrs_general_params_entry_packing,
.unpacked_entry_size = sizeof(struct sja1105_general_params_entry),
diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.h b/drivers/net/dsa/sja1105/sja1105_static_config.h
index d513b1c91b98..a9586d0b4b3b 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.h
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.h
@@ -20,10 +20,12 @@
#define SJA1105ET_SIZE_MAC_CONFIG_ENTRY 28
#define SJA1105ET_SIZE_L2_LOOKUP_PARAMS_ENTRY 4
#define SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY 40
+#define SJA1105ET_SIZE_AVB_PARAMS_ENTRY 12
#define SJA1105PQRS_SIZE_L2_LOOKUP_ENTRY 20
#define SJA1105PQRS_SIZE_MAC_CONFIG_ENTRY 32
#define SJA1105PQRS_SIZE_L2_LOOKUP_PARAMS_ENTRY 16
#define SJA1105PQRS_SIZE_GENERAL_PARAMS_ENTRY 44
+#define SJA1105PQRS_SIZE_AVB_PARAMS_ENTRY 16
/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
enum {
@@ -34,6 +36,7 @@ enum {
BLKID_MAC_CONFIG = 0x09,
BLKID_L2_LOOKUP_PARAMS = 0x0D,
BLKID_L2_FORWARDING_PARAMS = 0x0E,
+ BLKID_AVB_PARAMS = 0x10,
BLKID_GENERAL_PARAMS = 0x11,
BLKID_XMII_PARAMS = 0x4E,
};
@@ -46,6 +49,7 @@ enum sja1105_blk_idx {
BLK_IDX_MAC_CONFIG,
BLK_IDX_L2_LOOKUP_PARAMS,
BLK_IDX_L2_FORWARDING_PARAMS,
+ BLK_IDX_AVB_PARAMS,
BLK_IDX_GENERAL_PARAMS,
BLK_IDX_XMII_PARAMS,
BLK_IDX_MAX,
@@ -64,6 +68,7 @@ enum sja1105_blk_idx {
#define SJA1105_MAX_L2_FORWARDING_PARAMS_COUNT 1
#define SJA1105_MAX_GENERAL_PARAMS_COUNT 1
#define SJA1105_MAX_XMII_PARAMS_COUNT 1
+#define SJA1105_MAX_AVB_PARAMS_COUNT 1
#define SJA1105_MAX_FRAME_MEMORY 929
@@ -179,6 +184,11 @@ struct sja1105_l2_policing_entry {
u64 partition;
};
+struct sja1105_avb_params_entry {
+ u64 destmeta;
+ u64 srcmeta;
+};
+
struct sja1105_mac_config_entry {
u64 top[8];
u64 base[8];