@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -93,6 +93,13 @@ config MICREL_PHY
+@@ -93,6 +93,12 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -93,6 +93,13 @@ config MICREL_PHY
+@@ -93,6 +93,12 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -92,6 +92,13 @@ config MICREL_PHY
+@@ -92,6 +92,12 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -92,6 +92,13 @@ config MICREL_PHY
+@@ -92,6 +92,12 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -91,6 +91,13 @@ config MICREL_PHY
+@@ -91,6 +91,12 @@ config MICREL_PHY
---help---
Supports the KSZ9021, VSC8201, KS8001 PHYs.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -8,10 +8,6 @@
This driver supports the FC and M models only. The ADM6996F and L are
completely different chips.
- Support for the FC model is extremely limited at the moment. There is no VLAN
- support as of yet. The driver will not offer an swconfig interface for the FC
- chip.
-
1.1 VLAN IDs
It is possible to define 16 different VLANs. Every VLAN has an identifier, its
@@ -68,7 +64,21 @@
performing a warm reboot might still leave the chip in a "broken" state. Only
a hardware reset will bring it back in the default state.
-2. Technical details on PHYs and the ADM6996
+2. ADM6996FC specific information
+
+ A port can be:
+ - either an untagged member of exactly one VLAN,
+ - or a tagged member of one or more VLANs.
+
+ So a mix of untagged and tagged like the M model supports is not possible.
+ When you isssue a 'vlan X set ports' swconfig command, any existing port
+ membership for the ports will be adjusted to meet these constraints. For
+ clarity and your own sanity, I strongly recommend you obey those constraints
+ yourself while defining membership. 'swconfig dev ethX show' will always show
+ the state that will be set once applied, so there it is What You See Is What
+ You Get.
+
+3. Technical details on PHYs and the ADM6996
From the viewpoint of the Linux kernel, it is common that an Ethernet adapter
can be seen as a separate MAC entity and a separate PHY entity. The PHY entity
@@ -271,6 +271,27 @@
return 0;
};
+/*
+ * Clear VLAN memberships for a port. If @untagged, only clear untagged
+ * memberships. Otherwise clear all.
+ */
+static void
+adm6996_clear_memberships (struct adm6996_priv *priv, int port, bool untagged)
+{
+ int i;
+
+ if (untagged) {
+ for (i = 0; i < ADM_NUM_VLANS; i++)
+ if (!(priv->vlan_tagged[i] & (1 << port)))
+ priv->vlan_table[i] &= ~(1 << port);
+ } else {
+ for (i = 0; i < ADM_NUM_VLANS; i++) {
+ priv->vlan_table[i] &= ~(1 << port);
+ priv->vlan_tagged[i] &= ~(1 << port);
+ }
+ }
+}
+
static int
adm6996_set_ports(struct switch_dev *dev, struct switch_val *val)
{
@@ -294,6 +315,13 @@
""));
#endif
+ if (priv->model == ADM6996FC) {
+ bool untagged_only;
+ untagged_only =
+ p ->flags & (1 << SWITCH_PORT_FLAG_TAGGED);
+ adm6996_clear_memberships (priv, p->id, untagged_only);
+ }
+
if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
*tagged |= (1 << p->id);
@@ -431,6 +459,38 @@
}
}
+/*
+ * Set "Output Tagged" for ports that are tagged members of a VLAN.
+ *
+ * The ADM6996FC seems to need this, but it should not be used for the M
+ * model. The M can support both tagged and untagged on the same port.
+ *
+ * Precondition: reg_mutex must be held
+ */
+static void adm6996_set_tagged_ports (struct adm6996_priv *priv)
+{
+ u8 tagged = 0;
+ u16 reg;
+ int i;
+
+ for (i = 0; i < ADM_NUM_VLANS; i++) {
+ tagged |= priv->vlan_tagged[i];
+ }
+
+ for (i = 0; i < ADM_NUM_PORTS; i++) {
+ reg = r16(priv->phydev, adm_portcfg[i]);
+
+ if (tagged & (1 << i)) {
+ dev_dbg(&priv->phydev->dev, "port %d tagged\n", i);
+ reg |= ADM_PORTCFG_OT;
+ } else {
+ reg &= ~(ADM_PORTCFG_OT);
+ }
+
+ w16(priv->phydev, adm_portcfg[i], reg);
+ }
+}
+
static int
adm6996_hw_apply(struct switch_dev *dev)
{
@@ -456,6 +516,9 @@
adm6996_apply_port_pvids(priv);
adm6996_apply_vlan_filters(priv);
+ if (priv->model == ADM6996FC)
+ adm6996_set_tagged_ports(priv);
+
out:
mutex_unlock(&priv->reg_mutex);
@@ -500,13 +563,11 @@
priv->vlan_tagged[i] = 0;
}
- if (priv->model == ADM6996M) {
- /* Clear VLAN priority map so prio's are unused */
- w16 (priv->phydev, ADM_VLAN_PRIOMAP, 0);
+ /* Clear VLAN priority map so prio's are unused */
+ w16(priv->phydev, ADM_VLAN_PRIOMAP, 0);
- adm6996_disable_vlan(priv);
- adm6996_apply_port_pvids(priv);
- }
+ adm6996_disable_vlan(priv);
+ adm6996_apply_port_pvids(priv);
}
static int
@@ -641,11 +702,9 @@
adm6996_perform_reset (priv);
mutex_unlock(&priv->reg_mutex);
- if (priv->model == ADM6996M) {
- if ((ret = register_switch(swdev, pdev->attached_dev)) < 0) {
- kfree(priv);
- return ret;
- }
+ if ((ret = register_switch(swdev, pdev->attached_dev)) < 0) {
+ kfree(priv);
+ return ret;
}
return 0;
@@ -702,10 +761,10 @@
{
struct adm6996_priv *priv = phy_to_adm(pdev);
- if (priv != NULL && priv->model == ADM6996M)
+ if (priv != NULL) {
unregister_switch(&priv->dev);
-
- kfree(priv);
+ kfree(priv);
+ }
}
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -82,6 +82,13 @@ config LSI_ET1011C_PHY
+@@ -82,6 +82,12 @@ config LSI_ET1011C_PHY
---help---
Supports the LSI ET1011C PHY.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -82,6 +82,13 @@ config LSI_ET1011C_PHY
+@@ -82,6 +82,12 @@ config LSI_ET1011C_PHY
---help---
Supports the LSI ET1011C PHY.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
@@ -1,6 +1,6 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
-@@ -88,6 +88,13 @@ config LSI_ET1011C_PHY
+@@ -88,6 +88,12 @@ config LSI_ET1011C_PHY
---help---
Supports the LSI ET1011C PHY.
@@ -9,7 +9,6 @@
+ select SWCONFIG
+ ---help---
+ Currently supports the ADM6996FC and ADM6996M switches.
-+ Support for FC is very limited.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"