From 7206a10548e457fc7ef77437b1502267262a493c Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 6 Dec 2015 17:00:48 +0100 Subject: ath79 board support Use full OpenWrt patch for it, as it works better on 4.1.13 kernel. Deduplicate the patches for atheros devices. --- .../4.1.10/0015-phy-add-ar8216-PHY-support.patch | 4513 -------------------- 1 file changed, 4513 deletions(-) delete mode 100644 target/mips/mikrotik-rb4xx/patches/4.1.10/0015-phy-add-ar8216-PHY-support.patch (limited to 'target/mips/mikrotik-rb4xx/patches/4.1.10/0015-phy-add-ar8216-PHY-support.patch') diff --git a/target/mips/mikrotik-rb4xx/patches/4.1.10/0015-phy-add-ar8216-PHY-support.patch b/target/mips/mikrotik-rb4xx/patches/4.1.10/0015-phy-add-ar8216-PHY-support.patch deleted file mode 100644 index 5ac148908..000000000 --- a/target/mips/mikrotik-rb4xx/patches/4.1.10/0015-phy-add-ar8216-PHY-support.patch +++ /dev/null @@ -1,4513 +0,0 @@ -diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8216.c linux-4.1.6/drivers/net/phy/ar8216.c ---- linux-4.1.6.orig/drivers/net/phy/ar8216.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-4.1.6/drivers/net/phy/ar8216.c 2015-09-13 23:19:20.073314441 +0200 -@@ -0,0 +1,2182 @@ -+/* -+ * ar8216.c: AR8216 switch driver -+ * -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ar8216.h" -+ -+extern const struct ar8xxx_chip ar8327_chip; -+extern const struct ar8xxx_chip ar8337_chip; -+ -+#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */ -+ -+#define MIB_DESC(_s , _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+static const struct ar8xxx_mib_desc ar8216_mibs[] = { -+ MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"), -+ MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"), -+ MIB_DESC(1, AR8216_STATS_RXMULTI, "RxMulti"), -+ MIB_DESC(1, AR8216_STATS_RXFCSERR, "RxFcsErr"), -+ MIB_DESC(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"), -+ MIB_DESC(1, AR8216_STATS_RXRUNT, "RxRunt"), -+ MIB_DESC(1, AR8216_STATS_RXFRAGMENT, "RxFragment"), -+ MIB_DESC(1, AR8216_STATS_RX64BYTE, "Rx64Byte"), -+ MIB_DESC(1, AR8216_STATS_RX128BYTE, "Rx128Byte"), -+ MIB_DESC(1, AR8216_STATS_RX256BYTE, "Rx256Byte"), -+ MIB_DESC(1, AR8216_STATS_RX512BYTE, "Rx512Byte"), -+ MIB_DESC(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"), -+ MIB_DESC(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"), -+ MIB_DESC(1, AR8216_STATS_RXTOOLONG, "RxTooLong"), -+ MIB_DESC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"), -+ MIB_DESC(2, AR8216_STATS_RXBADBYTE, "RxBadByte"), -+ MIB_DESC(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"), -+ MIB_DESC(1, AR8216_STATS_FILTERED, "Filtered"), -+ MIB_DESC(1, AR8216_STATS_TXBROAD, "TxBroad"), -+ MIB_DESC(1, AR8216_STATS_TXPAUSE, "TxPause"), -+ MIB_DESC(1, AR8216_STATS_TXMULTI, "TxMulti"), -+ MIB_DESC(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"), -+ MIB_DESC(1, AR8216_STATS_TX64BYTE, "Tx64Byte"), -+ MIB_DESC(1, AR8216_STATS_TX128BYTE, "Tx128Byte"), -+ MIB_DESC(1, AR8216_STATS_TX256BYTE, "Tx256Byte"), -+ MIB_DESC(1, AR8216_STATS_TX512BYTE, "Tx512Byte"), -+ MIB_DESC(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"), -+ MIB_DESC(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"), -+ MIB_DESC(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"), -+ MIB_DESC(2, AR8216_STATS_TXBYTE, "TxByte"), -+ MIB_DESC(1, AR8216_STATS_TXCOLLISION, "TxCollision"), -+ MIB_DESC(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"), -+ MIB_DESC(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"), -+ MIB_DESC(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"), -+ MIB_DESC(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"), -+ MIB_DESC(1, AR8216_STATS_TXDEFER, "TxDefer"), -+ MIB_DESC(1, AR8216_STATS_TXLATECOL, "TxLateCol"), -+}; -+ -+const struct ar8xxx_mib_desc ar8236_mibs[39] = { -+ MIB_DESC(1, AR8236_STATS_RXBROAD, "RxBroad"), -+ MIB_DESC(1, AR8236_STATS_RXPAUSE, "RxPause"), -+ MIB_DESC(1, AR8236_STATS_RXMULTI, "RxMulti"), -+ MIB_DESC(1, AR8236_STATS_RXFCSERR, "RxFcsErr"), -+ MIB_DESC(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"), -+ MIB_DESC(1, AR8236_STATS_RXRUNT, "RxRunt"), -+ MIB_DESC(1, AR8236_STATS_RXFRAGMENT, "RxFragment"), -+ MIB_DESC(1, AR8236_STATS_RX64BYTE, "Rx64Byte"), -+ MIB_DESC(1, AR8236_STATS_RX128BYTE, "Rx128Byte"), -+ MIB_DESC(1, AR8236_STATS_RX256BYTE, "Rx256Byte"), -+ MIB_DESC(1, AR8236_STATS_RX512BYTE, "Rx512Byte"), -+ MIB_DESC(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"), -+ MIB_DESC(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"), -+ MIB_DESC(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"), -+ MIB_DESC(1, AR8236_STATS_RXTOOLONG, "RxTooLong"), -+ MIB_DESC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"), -+ MIB_DESC(2, AR8236_STATS_RXBADBYTE, "RxBadByte"), -+ MIB_DESC(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"), -+ MIB_DESC(1, AR8236_STATS_FILTERED, "Filtered"), -+ MIB_DESC(1, AR8236_STATS_TXBROAD, "TxBroad"), -+ MIB_DESC(1, AR8236_STATS_TXPAUSE, "TxPause"), -+ MIB_DESC(1, AR8236_STATS_TXMULTI, "TxMulti"), -+ MIB_DESC(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"), -+ MIB_DESC(1, AR8236_STATS_TX64BYTE, "Tx64Byte"), -+ MIB_DESC(1, AR8236_STATS_TX128BYTE, "Tx128Byte"), -+ MIB_DESC(1, AR8236_STATS_TX256BYTE, "Tx256Byte"), -+ MIB_DESC(1, AR8236_STATS_TX512BYTE, "Tx512Byte"), -+ MIB_DESC(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"), -+ MIB_DESC(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"), -+ MIB_DESC(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"), -+ MIB_DESC(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"), -+ MIB_DESC(2, AR8236_STATS_TXBYTE, "TxByte"), -+ MIB_DESC(1, AR8236_STATS_TXCOLLISION, "TxCollision"), -+ MIB_DESC(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"), -+ MIB_DESC(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"), -+ MIB_DESC(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"), -+ MIB_DESC(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"), -+ MIB_DESC(1, AR8236_STATS_TXDEFER, "TxDefer"), -+ MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"), -+}; -+ -+static DEFINE_MUTEX(ar8xxx_dev_list_lock); -+static LIST_HEAD(ar8xxx_dev_list); -+ -+/* inspired by phy_poll_reset in drivers/net/phy/phy_device.c */ -+static int -+ar8xxx_phy_poll_reset(struct mii_bus *bus) -+{ -+ unsigned int sleep_msecs = 20; -+ int ret, elapsed, i; -+ -+ for (elapsed = sleep_msecs; elapsed <= 600; -+ elapsed += sleep_msecs) { -+ msleep(sleep_msecs); -+ for (i = 0; i < AR8XXX_NUM_PHYS; i++) { -+ ret = mdiobus_read(bus, i, MII_BMCR); -+ if (ret < 0) -+ return ret; -+ if (ret & BMCR_RESET) -+ break; -+ if (i == AR8XXX_NUM_PHYS - 1) { -+ usleep_range(1000, 2000); -+ return 0; -+ } -+ } -+ } -+ return -ETIMEDOUT; -+} -+ -+static int -+ar8xxx_phy_check_aneg(struct phy_device *phydev) -+{ -+ int ret; -+ -+ if (phydev->autoneg != AUTONEG_ENABLE) -+ return 0; -+ /* -+ * BMCR_ANENABLE might have been cleared -+ * by phy_init_hw in certain kernel versions -+ * therefore check for it -+ */ -+ ret = phy_read(phydev, MII_BMCR); -+ if (ret < 0) -+ return ret; -+ if (ret & BMCR_ANENABLE) -+ return 0; -+ -+ dev_info(&phydev->dev, "ANEG disabled, re-enabling ...\n"); -+ ret |= BMCR_ANENABLE | BMCR_ANRESTART; -+ return phy_write(phydev, MII_BMCR, ret); -+} -+ -+void -+ar8xxx_phy_init(struct ar8xxx_priv *priv) -+{ -+ int i; -+ struct mii_bus *bus; -+ -+ bus = priv->mii_bus; -+ for (i = 0; i < AR8XXX_NUM_PHYS; i++) { -+ if (priv->chip->phy_fixup) -+ priv->chip->phy_fixup(priv, i); -+ -+ /* initialize the port itself */ -+ mdiobus_write(bus, i, MII_ADVERTISE, -+ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); -+ if (ar8xxx_has_gige(priv)) -+ mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); -+ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); -+ } -+ -+ ar8xxx_phy_poll_reset(bus); -+} -+ -+u32 -+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 lo, hi; -+ -+ lo = bus->read(bus, phy_id, regnum); -+ hi = bus->read(bus, phy_id, regnum + 1); -+ -+ return (hi << 16) | lo; -+} -+ -+void -+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 lo, hi; -+ -+ lo = val & 0xffff; -+ hi = (u16) (val >> 16); -+ -+ if (priv->chip->mii_lo_first) -+ { -+ bus->write(bus, phy_id, regnum, lo); -+ bus->write(bus, phy_id, regnum + 1, hi); -+ } else { -+ bus->write(bus, phy_id, regnum + 1, hi); -+ bus->write(bus, phy_id, regnum, lo); -+ } -+} -+ -+u32 -+ar8xxx_read(struct ar8xxx_priv *priv, int reg) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 r1, r2, page; -+ u32 val; -+ -+ split_addr((u32) reg, &r1, &r2, &page); -+ -+ mutex_lock(&bus->mdio_lock); -+ -+ bus->write(bus, 0x18, 0, page); -+ wait_for_page_switch(); -+ val = ar8xxx_mii_read32(priv, 0x10 | r2, r1); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return val; -+} -+ -+void -+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 r1, r2, page; -+ -+ split_addr((u32) reg, &r1, &r2, &page); -+ -+ mutex_lock(&bus->mdio_lock); -+ -+ bus->write(bus, 0x18, 0, page); -+ wait_for_page_switch(); -+ ar8xxx_mii_write32(priv, 0x10 | r2, r1, val); -+ -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+u32 -+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 r1, r2, page; -+ u32 ret; -+ -+ split_addr((u32) reg, &r1, &r2, &page); -+ -+ mutex_lock(&bus->mdio_lock); -+ -+ bus->write(bus, 0x18, 0, page); -+ wait_for_page_switch(); -+ -+ ret = ar8xxx_mii_read32(priv, 0x10 | r2, r1); -+ ret &= ~mask; -+ ret |= val; -+ ar8xxx_mii_write32(priv, 0x10 | r2, r1, ret); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+void -+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, -+ u16 dbg_addr, u16 dbg_data) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ -+ mutex_lock(&bus->mdio_lock); -+ bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr); -+ bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data); -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+void -+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ -+ mutex_lock(&bus->mdio_lock); -+ bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); -+ bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data); -+ mutex_unlock(&bus->mdio_lock); -+} -+ -+u16 -+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 data; -+ -+ mutex_lock(&bus->mdio_lock); -+ bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); -+ data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return data; -+} -+ -+static int -+ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, -+ unsigned timeout) -+{ -+ int i; -+ -+ for (i = 0; i < timeout; i++) { -+ u32 t; -+ -+ t = ar8xxx_read(priv, reg); -+ if ((t & mask) == val) -+ return 0; -+ -+ usleep_range(1000, 2000); -+ } -+ -+ return -ETIMEDOUT; -+} -+ -+static int -+ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op) -+{ -+ unsigned mib_func = priv->chip->mib_func; -+ int ret; -+ -+ lockdep_assert_held(&priv->mib_lock); -+ -+ /* Capture the hardware statistics for all ports */ -+ ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S)); -+ -+ /* Wait for the capturing to complete. */ -+ ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10); -+ if (ret) -+ goto out; -+ -+ ret = 0; -+ -+out: -+ return ret; -+} -+ -+static int -+ar8xxx_mib_capture(struct ar8xxx_priv *priv) -+{ -+ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE); -+} -+ -+static int -+ar8xxx_mib_flush(struct ar8xxx_priv *priv) -+{ -+ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH); -+} -+ -+static void -+ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush) -+{ -+ unsigned int base; -+ u64 *mib_stats; -+ int i; -+ -+ WARN_ON(port >= priv->dev.ports); -+ -+ lockdep_assert_held(&priv->mib_lock); -+ -+ base = priv->chip->reg_port_stats_start + -+ priv->chip->reg_port_stats_length * port; -+ -+ mib_stats = &priv->mib_stats[port * priv->chip->num_mibs]; -+ for (i = 0; i < priv->chip->num_mibs; i++) { -+ const struct ar8xxx_mib_desc *mib; -+ u64 t; -+ -+ mib = &priv->chip->mib_decs[i]; -+ t = ar8xxx_read(priv, base + mib->offset); -+ if (mib->size == 2) { -+ u64 hi; -+ -+ hi = ar8xxx_read(priv, base + mib->offset + 4); -+ t |= hi << 32; -+ } -+ -+ if (flush) -+ mib_stats[i] = 0; -+ else -+ mib_stats[i] += t; -+ } -+} -+ -+static void -+ar8216_read_port_link(struct ar8xxx_priv *priv, int port, -+ struct switch_port_link *link) -+{ -+ u32 status; -+ u32 speed; -+ -+ memset(link, '\0', sizeof(*link)); -+ -+ status = priv->chip->read_port_status(priv, port); -+ -+ link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO); -+ if (link->aneg) { -+ link->link = !!(status & AR8216_PORT_STATUS_LINK_UP); -+ } else { -+ link->link = true; -+ -+ if (priv->get_port_link) { -+ int err; -+ -+ err = priv->get_port_link(port); -+ if (err >= 0) -+ link->link = !!err; -+ } -+ } -+ -+ if (!link->link) -+ return; -+ -+ link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX); -+ link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); -+ link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); -+ -+ if (link->aneg && link->duplex && priv->chip->read_port_eee_status) -+ link->eee = priv->chip->read_port_eee_status(priv, port); -+ -+ speed = (status & AR8216_PORT_STATUS_SPEED) >> -+ AR8216_PORT_STATUS_SPEED_S; -+ -+ switch (speed) { -+ case AR8216_PORT_SPEED_10M: -+ link->speed = SWITCH_PORT_SPEED_10; -+ break; -+ case AR8216_PORT_SPEED_100M: -+ link->speed = SWITCH_PORT_SPEED_100; -+ break; -+ case AR8216_PORT_SPEED_1000M: -+ link->speed = SWITCH_PORT_SPEED_1000; -+ break; -+ default: -+ link->speed = SWITCH_PORT_SPEED_UNKNOWN; -+ break; -+ } -+} -+ -+static struct sk_buff * -+ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb) -+{ -+ struct ar8xxx_priv *priv = dev->phy_ptr; -+ unsigned char *buf; -+ -+ if (unlikely(!priv)) -+ goto error; -+ -+ if (!priv->vlan) -+ goto send; -+ -+ if (unlikely(skb_headroom(skb) < 2)) { -+ if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) -+ goto error; -+ } -+ -+ buf = skb_push(skb, 2); -+ buf[0] = 0x10; -+ buf[1] = 0x80; -+ -+send: -+ return skb; -+ -+error: -+ dev_kfree_skb_any(skb); -+ return NULL; -+} -+ -+static void -+ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) -+{ -+ struct ar8xxx_priv *priv; -+ unsigned char *buf; -+ int port, vlan; -+ -+ priv = dev->phy_ptr; -+ if (!priv) -+ return; -+ -+ /* don't strip the header if vlan mode is disabled */ -+ if (!priv->vlan) -+ return; -+ -+ /* strip header, get vlan id */ -+ buf = skb->data; -+ skb_pull(skb, 2); -+ -+ /* check for vlan header presence */ -+ if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) -+ return; -+ -+ port = buf[0] & 0xf; -+ -+ /* no need to fix up packets coming from a tagged source */ -+ if (priv->vlan_tagged & (1 << port)) -+ return; -+ -+ /* lookup port vid from local table, the switch passes an invalid vlan id */ -+ vlan = priv->vlan_id[priv->pvid[port]]; -+ -+ buf[14 + 2] &= 0xf0; -+ buf[14 + 2] |= vlan >> 8; -+ buf[15 + 2] = vlan & 0xff; -+} -+ -+int -+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val) -+{ -+ int timeout = 20; -+ u32 t = 0; -+ -+ while (1) { -+ t = ar8xxx_read(priv, reg); -+ if ((t & mask) == val) -+ return 0; -+ -+ if (timeout-- <= 0) -+ break; -+ -+ udelay(10); -+ } -+ -+ pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n", -+ (unsigned int) reg, t, mask, val); -+ return -ETIMEDOUT; -+} -+ -+static void -+ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) -+{ -+ if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) -+ return; -+ if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { -+ val &= AR8216_VTUDATA_MEMBER; -+ val |= AR8216_VTUDATA_VALID; -+ ar8xxx_write(priv, AR8216_REG_VTU_DATA, val); -+ } -+ op |= AR8216_VTU_ACTIVE; -+ ar8xxx_write(priv, AR8216_REG_VTU, op); -+} -+ -+static void -+ar8216_vtu_flush(struct ar8xxx_priv *priv) -+{ -+ ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); -+} -+ -+static void -+ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) -+{ -+ u32 op; -+ -+ op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S); -+ ar8216_vtu_op(priv, op, port_mask); -+} -+ -+static int -+ar8216_atu_flush(struct ar8xxx_priv *priv) -+{ -+ int ret; -+ -+ ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); -+ if (!ret) -+ ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | -+ AR8216_ATU_ACTIVE); -+ -+ return ret; -+} -+ -+static int -+ar8216_atu_flush_port(struct ar8xxx_priv *priv, int port) -+{ -+ u32 t; -+ int ret; -+ -+ ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); -+ if (!ret) { -+ t = (port << AR8216_ATU_PORT_NUM_S) | AR8216_ATU_OP_FLUSH_PORT; -+ t |= AR8216_ATU_ACTIVE; -+ ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, t); -+ } -+ -+ return ret; -+} -+ -+static u32 -+ar8216_read_port_status(struct ar8xxx_priv *priv, int port) -+{ -+ return ar8xxx_read(priv, AR8216_REG_PORT_STATUS(port)); -+} -+ -+static void -+ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 members) -+{ -+ u32 header; -+ u32 egress, ingress; -+ u32 pvid; -+ -+ if (priv->vlan) { -+ pvid = priv->vlan_id[priv->pvid[port]]; -+ if (priv->vlan_tagged & (1 << port)) -+ egress = AR8216_OUT_ADD_VLAN; -+ else -+ egress = AR8216_OUT_STRIP_VLAN; -+ ingress = AR8216_IN_SECURE; -+ } else { -+ pvid = port; -+ egress = AR8216_OUT_KEEP; -+ ingress = AR8216_IN_PORT_ONLY; -+ } -+ -+ if (chip_is_ar8216(priv) && priv->vlan && port == AR8216_PORT_CPU) -+ header = AR8216_PORT_CTRL_HEADER; -+ else -+ header = 0; -+ -+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), -+ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | -+ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | -+ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, -+ AR8216_PORT_CTRL_LEARN | header | -+ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | -+ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); -+ -+ ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port), -+ AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | -+ AR8216_PORT_VLAN_DEFAULT_ID, -+ (members << AR8216_PORT_VLAN_DEST_PORTS_S) | -+ (ingress << AR8216_PORT_VLAN_MODE_S) | -+ (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); -+} -+ -+static int -+ar8216_hw_init(struct ar8xxx_priv *priv) -+{ -+ if (priv->initialized) -+ return 0; -+ -+ ar8xxx_phy_init(priv); -+ -+ priv->initialized = true; -+ return 0; -+} -+ -+static void -+ar8216_init_globals(struct ar8xxx_priv *priv) -+{ -+ /* standard atheros magic */ -+ ar8xxx_write(priv, 0x38, 0xc000050e); -+ -+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, -+ AR8216_GCTRL_MTU, 1518 + 8 + 2); -+} -+ -+static void -+ar8216_init_port(struct ar8xxx_priv *priv, int port) -+{ -+ /* Enable port learning and tx */ -+ ar8xxx_write(priv, AR8216_REG_PORT_CTRL(port), -+ AR8216_PORT_CTRL_LEARN | -+ (4 << AR8216_PORT_CTRL_STATE_S)); -+ -+ ar8xxx_write(priv, AR8216_REG_PORT_VLAN(port), 0); -+ -+ if (port == AR8216_PORT_CPU) { -+ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), -+ AR8216_PORT_STATUS_LINK_UP | -+ (ar8xxx_has_gige(priv) ? -+ AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | -+ AR8216_PORT_STATUS_TXMAC | -+ AR8216_PORT_STATUS_RXMAC | -+ (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_RXFLOW : 0) | -+ (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_TXFLOW : 0) | -+ AR8216_PORT_STATUS_DUPLEX); -+ } else { -+ ar8xxx_write(priv, AR8216_REG_PORT_STATUS(port), -+ AR8216_PORT_STATUS_LINK_AUTO); -+ } -+} -+ -+static void -+ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) -+{ -+ int timeout = 20; -+ -+ while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) -+ udelay(10); -+ -+ if (!timeout) -+ pr_err("ar8216: timeout waiting for atu to become ready\n"); -+} -+ -+static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, -+ struct arl_entry *a, u32 *status, enum arl_op op) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 r2, page; -+ u16 r1_func0, r1_func1, r1_func2; -+ u32 t, val0, val1, val2; -+ int i; -+ -+ split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); -+ r2 |= 0x10; -+ -+ r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; -+ r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; -+ -+ switch (op) { -+ case AR8XXX_ARL_INITIALIZE: -+ /* all ATU registers are on the same page -+ * therefore set page only once -+ */ -+ bus->write(bus, 0x18, 0, page); -+ wait_for_page_switch(); -+ -+ ar8216_wait_atu_ready(priv, r2, r1_func0); -+ -+ ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); -+ ar8xxx_mii_write32(priv, r2, r1_func1, 0); -+ ar8xxx_mii_write32(priv, r2, r1_func2, 0); -+ break; -+ case AR8XXX_ARL_GET_NEXT: -+ t = ar8xxx_mii_read32(priv, r2, r1_func0); -+ t |= AR8216_ATU_ACTIVE; -+ ar8xxx_mii_write32(priv, r2, r1_func0, t); -+ ar8216_wait_atu_ready(priv, r2, r1_func0); -+ -+ val0 = ar8xxx_mii_read32(priv, r2, r1_func0); -+ val1 = ar8xxx_mii_read32(priv, r2, r1_func1); -+ val2 = ar8xxx_mii_read32(priv, r2, r1_func2); -+ -+ *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; -+ if (!*status) -+ break; -+ -+ i = 0; -+ t = AR8216_ATU_PORT0; -+ while (!(val2 & t) && ++i < priv->dev.ports) -+ t <<= 1; -+ -+ a->port = i; -+ a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; -+ a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; -+ a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; -+ a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; -+ a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; -+ a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; -+ break; -+ } -+} -+ -+static void -+ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) -+{ -+ u32 egress, ingress; -+ u32 pvid; -+ -+ if (priv->vlan) { -+ pvid = priv->vlan_id[priv->pvid[port]]; -+ if (priv->vlan_tagged & (1 << port)) -+ egress = AR8216_OUT_ADD_VLAN; -+ else -+ egress = AR8216_OUT_STRIP_VLAN; -+ ingress = AR8216_IN_SECURE; -+ } else { -+ pvid = port; -+ egress = AR8216_OUT_KEEP; -+ ingress = AR8216_IN_PORT_ONLY; -+ } -+ -+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port), -+ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | -+ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | -+ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, -+ AR8216_PORT_CTRL_LEARN | -+ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | -+ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); -+ -+ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port), -+ AR8236_PORT_VLAN_DEFAULT_ID, -+ (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S)); -+ -+ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port), -+ AR8236_PORT_VLAN2_VLAN_MODE | -+ AR8236_PORT_VLAN2_MEMBER, -+ (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) | -+ (members << AR8236_PORT_VLAN2_MEMBER_S)); -+} -+ -+static void -+ar8236_init_globals(struct ar8xxx_priv *priv) -+{ -+ /* enable jumbo frames */ -+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, -+ AR8316_GCTRL_MTU, 9018 + 8 + 2); -+ -+ /* enable cpu port to receive arp frames */ -+ ar8xxx_reg_set(priv, AR8216_REG_ATU_CTRL, -+ AR8236_ATU_CTRL_RES); -+ -+ /* enable cpu port to receive multicast and broadcast frames */ -+ ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK, -+ AR8236_FM_CPU_BROADCAST_EN | AR8236_FM_CPU_BCAST_FWD_EN); -+ -+ /* Enable MIB counters */ -+ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, -+ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | -+ AR8236_MIB_EN); -+} -+ -+static int -+ar8316_hw_init(struct ar8xxx_priv *priv) -+{ -+ u32 val, newval; -+ -+ val = ar8xxx_read(priv, AR8316_REG_POSTRIP); -+ -+ if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { -+ if (priv->port4_phy) { -+ /* value taken from Ubiquiti RouterStation Pro */ -+ newval = 0x81461bea; -+ pr_info("ar8316: Using port 4 as PHY\n"); -+ } else { -+ newval = 0x01261be2; -+ pr_info("ar8316: Using port 4 as switch port\n"); -+ } -+ } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { -+ /* value taken from AVM Fritz!Box 7390 sources */ -+ newval = 0x010e5b71; -+ } else { -+ /* no known value for phy interface */ -+ pr_err("ar8316: unsupported mii mode: %d.\n", -+ priv->phy->interface); -+ return -EINVAL; -+ } -+ -+ if (val == newval) -+ goto out; -+ -+ ar8xxx_write(priv, AR8316_REG_POSTRIP, newval); -+ -+ if (priv->port4_phy && -+ priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { -+ /* work around for phy4 rgmii mode */ -+ ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c); -+ /* rx delay */ -+ ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e); -+ /* tx delay */ -+ ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47); -+ msleep(1000); -+ } -+ -+ ar8xxx_phy_init(priv); -+ -+out: -+ priv->initialized = true; -+ return 0; -+} -+ -+static void -+ar8316_init_globals(struct ar8xxx_priv *priv) -+{ -+ /* standard atheros magic */ -+ ar8xxx_write(priv, 0x38, 0xc000050e); -+ -+ /* enable cpu port to receive multicast and broadcast frames */ -+ ar8xxx_write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); -+ -+ /* enable jumbo frames */ -+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL, -+ AR8316_GCTRL_MTU, 9018 + 8 + 2); -+ -+ /* Enable MIB counters */ -+ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN, -+ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) | -+ AR8236_MIB_EN); -+} -+ -+int -+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ priv->vlan = !!val->value.i; -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->vlan; -+ return 0; -+} -+ -+ -+int -+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ /* make sure no invalid PVIDs get set */ -+ -+ if (vlan >= dev->vlans) -+ return -EINVAL; -+ -+ priv->pvid[port] = vlan; -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ *vlan = priv->pvid[port]; -+ return 0; -+} -+ -+static int -+ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ priv->vlan_id[val->port_vlan] = val->value.i; -+ return 0; -+} -+ -+static int -+ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->vlan_id[val->port_vlan]; -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, -+ struct switch_port_link *link) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ ar8216_read_port_link(priv, port, link); -+ return 0; -+} -+ -+static int -+ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ u8 ports = priv->vlan_table[val->port_vlan]; -+ int i; -+ -+ val->len = 0; -+ for (i = 0; i < dev->ports; i++) { -+ struct switch_port *p; -+ -+ if (!(ports & (1 << i))) -+ continue; -+ -+ p = &val->value.ports[val->len++]; -+ p->id = i; -+ if (priv->vlan_tagged & (1 << i)) -+ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); -+ else -+ p->flags = 0; -+ } -+ return 0; -+} -+ -+static int -+ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ u8 *vt = &priv->vlan_table[val->port_vlan]; -+ int i, j; -+ -+ *vt = 0; -+ for (i = 0; i < val->len; i++) { -+ struct switch_port *p = &val->value.ports[i]; -+ -+ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { -+ priv->vlan_tagged |= (1 << p->id); -+ } else { -+ priv->vlan_tagged &= ~(1 << p->id); -+ priv->pvid[p->id] = val->port_vlan; -+ -+ /* make sure that an untagged port does not -+ * appear in other vlans */ -+ for (j = 0; j < AR8X16_MAX_VLANS; j++) { -+ if (j == val->port_vlan) -+ continue; -+ priv->vlan_table[j] &= ~(1 << p->id); -+ } -+ } -+ -+ *vt |= 1 << p->id; -+ } -+ return 0; -+} -+ -+static void -+ar8216_set_mirror_regs(struct ar8xxx_priv *priv) -+{ -+ int port; -+ -+ /* reset all mirror registers */ -+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, -+ AR8216_GLOBAL_CPUPORT_MIRROR_PORT, -+ (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); -+ for (port = 0; port < AR8216_NUM_PORTS; port++) { -+ ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), -+ AR8216_PORT_CTRL_MIRROR_RX); -+ -+ ar8xxx_reg_clear(priv, AR8216_REG_PORT_CTRL(port), -+ AR8216_PORT_CTRL_MIRROR_TX); -+ } -+ -+ /* now enable mirroring if necessary */ -+ if (priv->source_port >= AR8216_NUM_PORTS || -+ priv->monitor_port >= AR8216_NUM_PORTS || -+ priv->source_port == priv->monitor_port) { -+ return; -+ } -+ -+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT, -+ AR8216_GLOBAL_CPUPORT_MIRROR_PORT, -+ (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S)); -+ -+ if (priv->mirror_rx) -+ ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), -+ AR8216_PORT_CTRL_MIRROR_RX); -+ -+ if (priv->mirror_tx) -+ ar8xxx_reg_set(priv, AR8216_REG_PORT_CTRL(priv->source_port), -+ AR8216_PORT_CTRL_MIRROR_TX); -+} -+ -+int -+ar8xxx_sw_hw_apply(struct switch_dev *dev) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ u8 portmask[AR8X16_MAX_PORTS]; -+ int i, j; -+ -+ mutex_lock(&priv->reg_mutex); -+ /* flush all vlan translation unit entries */ -+ priv->chip->vtu_flush(priv); -+ -+ memset(portmask, 0, sizeof(portmask)); -+ if (!priv->init) { -+ /* calculate the port destination masks and load vlans -+ * into the vlan translation unit */ -+ for (j = 0; j < AR8X16_MAX_VLANS; j++) { -+ u8 vp = priv->vlan_table[j]; -+ -+ if (!vp) -+ continue; -+ -+ for (i = 0; i < dev->ports; i++) { -+ u8 mask = (1 << i); -+ if (vp & mask) -+ portmask[i] |= vp & ~mask; -+ } -+ -+ priv->chip->vtu_load_vlan(priv, priv->vlan_id[j], -+ priv->vlan_table[j]); -+ } -+ } else { -+ /* vlan disabled: -+ * isolate all ports, but connect them to the cpu port */ -+ for (i = 0; i < dev->ports; i++) { -+ if (i == AR8216_PORT_CPU) -+ continue; -+ -+ portmask[i] = 1 << AR8216_PORT_CPU; -+ portmask[AR8216_PORT_CPU] |= (1 << i); -+ } -+ } -+ -+ /* update the port destination mask registers and tag settings */ -+ for (i = 0; i < dev->ports; i++) { -+ priv->chip->setup_port(priv, i, portmask[i]); -+ } -+ -+ priv->chip->set_mirror_regs(priv); -+ -+ mutex_unlock(&priv->reg_mutex); -+ return 0; -+} -+ -+int -+ar8xxx_sw_reset_switch(struct switch_dev *dev) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ const struct ar8xxx_chip *chip = priv->chip; -+ int i; -+ -+ mutex_lock(&priv->reg_mutex); -+ memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) - -+ offsetof(struct ar8xxx_priv, vlan)); -+ -+ for (i = 0; i < AR8X16_MAX_VLANS; i++) -+ priv->vlan_id[i] = i; -+ -+ /* Configure all ports */ -+ for (i = 0; i < dev->ports; i++) -+ chip->init_port(priv, i); -+ -+ priv->mirror_rx = false; -+ priv->mirror_tx = false; -+ priv->source_port = 0; -+ priv->monitor_port = 0; -+ -+ chip->init_globals(priv); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ return chip->sw_hw_apply(dev); -+} -+ -+int -+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ unsigned int len; -+ int ret; -+ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return -EOPNOTSUPP; -+ -+ mutex_lock(&priv->mib_lock); -+ -+ len = priv->dev.ports * priv->chip->num_mibs * -+ sizeof(*priv->mib_stats); -+ memset(priv->mib_stats, '\0', len); -+ ret = ar8xxx_mib_flush(priv); -+ if (ret) -+ goto unlock; -+ -+ ret = 0; -+ -+unlock: -+ mutex_unlock(&priv->mib_lock); -+ return ret; -+} -+ -+int -+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ mutex_lock(&priv->reg_mutex); -+ priv->mirror_rx = !!val->value.i; -+ priv->chip->set_mirror_regs(priv); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->mirror_rx; -+ return 0; -+} -+ -+int -+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ mutex_lock(&priv->reg_mutex); -+ priv->mirror_tx = !!val->value.i; -+ priv->chip->set_mirror_regs(priv); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->mirror_tx; -+ return 0; -+} -+ -+int -+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ mutex_lock(&priv->reg_mutex); -+ priv->monitor_port = val->value.i; -+ priv->chip->set_mirror_regs(priv); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->monitor_port; -+ return 0; -+} -+ -+int -+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ -+ mutex_lock(&priv->reg_mutex); -+ priv->source_port = val->value.i; -+ priv->chip->set_mirror_regs(priv); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int -+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ val->value.i = priv->source_port; -+ return 0; -+} -+ -+int -+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ int port; -+ int ret; -+ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return -EOPNOTSUPP; -+ -+ port = val->port_vlan; -+ if (port >= dev->ports) -+ return -EINVAL; -+ -+ mutex_lock(&priv->mib_lock); -+ ret = ar8xxx_mib_capture(priv); -+ if (ret) -+ goto unlock; -+ -+ ar8xxx_mib_fetch_port_stat(priv, port, true); -+ -+ ret = 0; -+ -+unlock: -+ mutex_unlock(&priv->mib_lock); -+ return ret; -+} -+ -+int -+ar8xxx_sw_get_port_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ const struct ar8xxx_chip *chip = priv->chip; -+ u64 *mib_stats; -+ int port; -+ int ret; -+ char *buf = priv->buf; -+ int i, len = 0; -+ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return -EOPNOTSUPP; -+ -+ port = val->port_vlan; -+ if (port >= dev->ports) -+ return -EINVAL; -+ -+ mutex_lock(&priv->mib_lock); -+ ret = ar8xxx_mib_capture(priv); -+ if (ret) -+ goto unlock; -+ -+ ar8xxx_mib_fetch_port_stat(priv, port, false); -+ -+ len += snprintf(buf + len, sizeof(priv->buf) - len, -+ "Port %d MIB counters\n", -+ port); -+ -+ mib_stats = &priv->mib_stats[port * chip->num_mibs]; -+ for (i = 0; i < chip->num_mibs; i++) -+ len += snprintf(buf + len, sizeof(priv->buf) - len, -+ "%-12s: %llu\n", -+ chip->mib_decs[i].name, -+ mib_stats[i]); -+ -+ val->value.s = buf; -+ val->len = len; -+ -+ ret = 0; -+ -+unlock: -+ mutex_unlock(&priv->mib_lock); -+ return ret; -+} -+ -+int -+ar8xxx_sw_get_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ struct mii_bus *bus = priv->mii_bus; -+ const struct ar8xxx_chip *chip = priv->chip; -+ char *buf = priv->arl_buf; -+ int i, j, k, len = 0; -+ struct arl_entry *a, *a1; -+ u32 status; -+ -+ if (!chip->get_arl_entry) -+ return -EOPNOTSUPP; -+ -+ mutex_lock(&priv->reg_mutex); -+ mutex_lock(&bus->mdio_lock); -+ -+ chip->get_arl_entry(priv, NULL, NULL, AR8XXX_ARL_INITIALIZE); -+ -+ for(i = 0; i < AR8XXX_NUM_ARL_RECORDS; ++i) { -+ a = &priv->arl_table[i]; -+ duplicate: -+ chip->get_arl_entry(priv, a, &status, AR8XXX_ARL_GET_NEXT); -+ -+ if (!status) -+ break; -+ -+ /* avoid duplicates -+ * ARL table can include multiple valid entries -+ * per MAC, just with differing status codes -+ */ -+ for (j = 0; j < i; ++j) { -+ a1 = &priv->arl_table[j]; -+ if (a->port == a1->port && !memcmp(a->mac, a1->mac, sizeof(a->mac))) -+ goto duplicate; -+ } -+ } -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, -+ "address resolution table\n"); -+ -+ if (i == AR8XXX_NUM_ARL_RECORDS) -+ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, -+ "Too many entries found, displaying the first %d only!\n", -+ AR8XXX_NUM_ARL_RECORDS); -+ -+ for (j = 0; j < priv->dev.ports; ++j) { -+ for (k = 0; k < i; ++k) { -+ a = &priv->arl_table[k]; -+ if (a->port != j) -+ continue; -+ len += snprintf(buf + len, sizeof(priv->arl_buf) - len, -+ "Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", -+ j, -+ a->mac[5], a->mac[4], a->mac[3], -+ a->mac[2], a->mac[1], a->mac[0]); -+ } -+ } -+ -+ val->value.s = buf; -+ val->len = len; -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int -+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = priv->chip->atu_flush(priv); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+int -+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ int port, ret; -+ -+ port = val->port_vlan; -+ if (port >= dev->ports) -+ return -EINVAL; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = priv->chip->atu_flush_port(priv, port); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static const struct switch_attr ar8xxx_sw_attr_globals[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_vlan", -+ .description = "Enable VLAN mode", -+ .set = ar8xxx_sw_set_vlan, -+ .get = ar8xxx_sw_get_vlan, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "reset_mibs", -+ .description = "Reset all MIB counters", -+ .set = ar8xxx_sw_set_reset_mibs, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_mirror_rx", -+ .description = "Enable mirroring of RX packets", -+ .set = ar8xxx_sw_set_mirror_rx_enable, -+ .get = ar8xxx_sw_get_mirror_rx_enable, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_mirror_tx", -+ .description = "Enable mirroring of TX packets", -+ .set = ar8xxx_sw_set_mirror_tx_enable, -+ .get = ar8xxx_sw_get_mirror_tx_enable, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "mirror_monitor_port", -+ .description = "Mirror monitor port", -+ .set = ar8xxx_sw_set_mirror_monitor_port, -+ .get = ar8xxx_sw_get_mirror_monitor_port, -+ .max = AR8216_NUM_PORTS - 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "mirror_source_port", -+ .description = "Mirror source port", -+ .set = ar8xxx_sw_set_mirror_source_port, -+ .get = ar8xxx_sw_get_mirror_source_port, -+ .max = AR8216_NUM_PORTS - 1 -+ }, -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "arl_table", -+ .description = "Get ARL table", -+ .set = NULL, -+ .get = ar8xxx_sw_get_arl_table, -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "flush_arl_table", -+ .description = "Flush ARL table", -+ .set = ar8xxx_sw_set_flush_arl_table, -+ }, -+}; -+ -+const struct switch_attr ar8xxx_sw_attr_port[] = { -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "reset_mib", -+ .description = "Reset single port MIB counters", -+ .set = ar8xxx_sw_set_port_reset_mib, -+ }, -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "mib", -+ .description = "Get port's MIB counters", -+ .set = NULL, -+ .get = ar8xxx_sw_get_port_mib, -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "flush_arl_table", -+ .description = "Flush port's ARL table entries", -+ .set = ar8xxx_sw_set_flush_port_arl_table, -+ }, -+}; -+ -+const struct switch_attr ar8xxx_sw_attr_vlan[1] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "vid", -+ .description = "VLAN ID (0-4094)", -+ .set = ar8xxx_sw_set_vid, -+ .get = ar8xxx_sw_get_vid, -+ .max = 4094, -+ }, -+}; -+ -+static const struct switch_dev_ops ar8xxx_sw_ops = { -+ .attr_global = { -+ .attr = ar8xxx_sw_attr_globals, -+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals), -+ }, -+ .attr_port = { -+ .attr = ar8xxx_sw_attr_port, -+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port), -+ }, -+ .attr_vlan = { -+ .attr = ar8xxx_sw_attr_vlan, -+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), -+ }, -+ .get_port_pvid = ar8xxx_sw_get_pvid, -+ .set_port_pvid = ar8xxx_sw_set_pvid, -+ .get_vlan_ports = ar8xxx_sw_get_ports, -+ .set_vlan_ports = ar8xxx_sw_set_ports, -+ .apply_config = ar8xxx_sw_hw_apply, -+ .reset_switch = ar8xxx_sw_reset_switch, -+ .get_port_link = ar8xxx_sw_get_port_link, -+}; -+ -+static const struct ar8xxx_chip ar8216_chip = { -+ .caps = AR8XXX_CAP_MIB_COUNTERS, -+ -+ .reg_port_stats_start = 0x19000, -+ .reg_port_stats_length = 0xa0, -+ -+ .name = "Atheros AR8216", -+ .ports = AR8216_NUM_PORTS, -+ .vlans = AR8216_NUM_VLANS, -+ .swops = &ar8xxx_sw_ops, -+ -+ .hw_init = ar8216_hw_init, -+ .init_globals = ar8216_init_globals, -+ .init_port = ar8216_init_port, -+ .setup_port = ar8216_setup_port, -+ .read_port_status = ar8216_read_port_status, -+ .atu_flush = ar8216_atu_flush, -+ .atu_flush_port = ar8216_atu_flush_port, -+ .vtu_flush = ar8216_vtu_flush, -+ .vtu_load_vlan = ar8216_vtu_load_vlan, -+ .set_mirror_regs = ar8216_set_mirror_regs, -+ .get_arl_entry = ar8216_get_arl_entry, -+ .sw_hw_apply = ar8xxx_sw_hw_apply, -+ -+ .num_mibs = ARRAY_SIZE(ar8216_mibs), -+ .mib_decs = ar8216_mibs, -+ .mib_func = AR8216_REG_MIB_FUNC -+}; -+ -+static const struct ar8xxx_chip ar8236_chip = { -+ .caps = AR8XXX_CAP_MIB_COUNTERS, -+ -+ .reg_port_stats_start = 0x20000, -+ .reg_port_stats_length = 0x100, -+ -+ .name = "Atheros AR8236", -+ .ports = AR8216_NUM_PORTS, -+ .vlans = AR8216_NUM_VLANS, -+ .swops = &ar8xxx_sw_ops, -+ -+ .hw_init = ar8216_hw_init, -+ .init_globals = ar8236_init_globals, -+ .init_port = ar8216_init_port, -+ .setup_port = ar8236_setup_port, -+ .read_port_status = ar8216_read_port_status, -+ .atu_flush = ar8216_atu_flush, -+ .atu_flush_port = ar8216_atu_flush_port, -+ .vtu_flush = ar8216_vtu_flush, -+ .vtu_load_vlan = ar8216_vtu_load_vlan, -+ .set_mirror_regs = ar8216_set_mirror_regs, -+ .get_arl_entry = ar8216_get_arl_entry, -+ .sw_hw_apply = ar8xxx_sw_hw_apply, -+ -+ .num_mibs = ARRAY_SIZE(ar8236_mibs), -+ .mib_decs = ar8236_mibs, -+ .mib_func = AR8216_REG_MIB_FUNC -+}; -+ -+static const struct ar8xxx_chip ar8316_chip = { -+ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, -+ -+ .reg_port_stats_start = 0x20000, -+ .reg_port_stats_length = 0x100, -+ -+ .name = "Atheros AR8316", -+ .ports = AR8216_NUM_PORTS, -+ .vlans = AR8X16_MAX_VLANS, -+ .swops = &ar8xxx_sw_ops, -+ -+ .hw_init = ar8316_hw_init, -+ .init_globals = ar8316_init_globals, -+ .init_port = ar8216_init_port, -+ .setup_port = ar8216_setup_port, -+ .read_port_status = ar8216_read_port_status, -+ .atu_flush = ar8216_atu_flush, -+ .atu_flush_port = ar8216_atu_flush_port, -+ .vtu_flush = ar8216_vtu_flush, -+ .vtu_load_vlan = ar8216_vtu_load_vlan, -+ .set_mirror_regs = ar8216_set_mirror_regs, -+ .get_arl_entry = ar8216_get_arl_entry, -+ .sw_hw_apply = ar8xxx_sw_hw_apply, -+ -+ .num_mibs = ARRAY_SIZE(ar8236_mibs), -+ .mib_decs = ar8236_mibs, -+ .mib_func = AR8216_REG_MIB_FUNC -+}; -+ -+static int -+ar8xxx_id_chip(struct ar8xxx_priv *priv) -+{ -+ u32 val; -+ u16 id; -+ int i; -+ -+ val = ar8xxx_read(priv, AR8216_REG_CTRL); -+ if (val == ~0) -+ return -ENODEV; -+ -+ id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); -+ for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { -+ u16 t; -+ -+ val = ar8xxx_read(priv, AR8216_REG_CTRL); -+ if (val == ~0) -+ return -ENODEV; -+ -+ t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); -+ if (t != id) -+ return -ENODEV; -+ } -+ -+ priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S; -+ priv->chip_rev = (id & AR8216_CTRL_REVISION); -+ -+ switch (priv->chip_ver) { -+ case AR8XXX_VER_AR8216: -+ priv->chip = &ar8216_chip; -+ break; -+ case AR8XXX_VER_AR8236: -+ priv->chip = &ar8236_chip; -+ break; -+ case AR8XXX_VER_AR8316: -+ priv->chip = &ar8316_chip; -+ break; -+ case AR8XXX_VER_AR8327: -+ priv->chip = &ar8327_chip; -+ break; -+ case AR8XXX_VER_AR8337: -+ priv->chip = &ar8337_chip; -+ break; -+ default: -+ pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n", -+ priv->chip_ver, priv->chip_rev); -+ -+ return -ENODEV; -+ } -+ -+ return 0; -+} -+ -+static void -+ar8xxx_mib_work_func(struct work_struct *work) -+{ -+ struct ar8xxx_priv *priv; -+ int err; -+ -+ priv = container_of(work, struct ar8xxx_priv, mib_work.work); -+ -+ mutex_lock(&priv->mib_lock); -+ -+ err = ar8xxx_mib_capture(priv); -+ if (err) -+ goto next_port; -+ -+ ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false); -+ -+next_port: -+ priv->mib_next_port++; -+ if (priv->mib_next_port >= priv->dev.ports) -+ priv->mib_next_port = 0; -+ -+ mutex_unlock(&priv->mib_lock); -+ schedule_delayed_work(&priv->mib_work, -+ msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY)); -+} -+ -+static int -+ar8xxx_mib_init(struct ar8xxx_priv *priv) -+{ -+ unsigned int len; -+ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return 0; -+ -+ BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs); -+ -+ len = priv->dev.ports * priv->chip->num_mibs * -+ sizeof(*priv->mib_stats); -+ priv->mib_stats = kzalloc(len, GFP_KERNEL); -+ -+ if (!priv->mib_stats) -+ return -ENOMEM; -+ -+ return 0; -+} -+ -+static void -+ar8xxx_mib_start(struct ar8xxx_priv *priv) -+{ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return; -+ -+ schedule_delayed_work(&priv->mib_work, -+ msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY)); -+} -+ -+static void -+ar8xxx_mib_stop(struct ar8xxx_priv *priv) -+{ -+ if (!ar8xxx_has_mib_counters(priv)) -+ return; -+ -+ cancel_delayed_work(&priv->mib_work); -+} -+ -+static struct ar8xxx_priv * -+ar8xxx_create(void) -+{ -+ struct ar8xxx_priv *priv; -+ -+ priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL); -+ if (priv == NULL) -+ return NULL; -+ -+ mutex_init(&priv->reg_mutex); -+ mutex_init(&priv->mib_lock); -+ INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func); -+ -+ return priv; -+} -+ -+static void -+ar8xxx_free(struct ar8xxx_priv *priv) -+{ -+ if (priv->chip && priv->chip->cleanup) -+ priv->chip->cleanup(priv); -+ -+ kfree(priv->chip_data); -+ kfree(priv->mib_stats); -+ kfree(priv); -+} -+ -+static int -+ar8xxx_probe_switch(struct ar8xxx_priv *priv) -+{ -+ const struct ar8xxx_chip *chip; -+ struct switch_dev *swdev; -+ int ret; -+ -+ ret = ar8xxx_id_chip(priv); -+ if (ret) -+ return ret; -+ -+ chip = priv->chip; -+ -+ swdev = &priv->dev; -+ swdev->cpu_port = AR8216_PORT_CPU; -+ swdev->name = chip->name; -+ swdev->vlans = chip->vlans; -+ swdev->ports = chip->ports; -+ swdev->ops = chip->swops; -+ -+ ret = ar8xxx_mib_init(priv); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int -+ar8xxx_start(struct ar8xxx_priv *priv) -+{ -+ int ret; -+ -+ priv->init = true; -+ -+ ret = priv->chip->hw_init(priv); -+ if (ret) -+ return ret; -+ -+ ret = ar8xxx_sw_reset_switch(&priv->dev); -+ if (ret) -+ return ret; -+ -+ priv->init = false; -+ -+ ar8xxx_mib_start(priv); -+ -+ return 0; -+} -+ -+static int -+ar8xxx_phy_config_init(struct phy_device *phydev) -+{ -+ struct ar8xxx_priv *priv = phydev->priv; -+ struct net_device *dev = phydev->attached_dev; -+ int ret; -+ -+ if (WARN_ON(!priv)) -+ return -ENODEV; -+ -+ if (priv->chip->config_at_probe) -+ return ar8xxx_phy_check_aneg(phydev); -+ -+ priv->phy = phydev; -+ -+ if (phydev->addr != 0) { -+ if (chip_is_ar8316(priv)) { -+ /* switch device has been initialized, reinit */ -+ priv->dev.ports = (AR8216_NUM_PORTS - 1); -+ priv->initialized = false; -+ priv->port4_phy = true; -+ ar8316_hw_init(priv); -+ return 0; -+ } -+ -+ return 0; -+ } -+ -+ ret = ar8xxx_start(priv); -+ if (ret) -+ return ret; -+ -+ /* VID fixup only needed on ar8216 */ -+ if (chip_is_ar8216(priv)) { -+ dev->phy_ptr = priv; -+ dev->priv_flags |= IFF_NO_IP_ALIGN; -+ dev->eth_mangle_rx = ar8216_mangle_rx; -+ dev->eth_mangle_tx = ar8216_mangle_tx; -+ } -+ -+ return 0; -+} -+ -+static bool -+ar8xxx_check_link_states(struct ar8xxx_priv *priv) -+{ -+ bool link_new, changed = false; -+ u32 status; -+ int i; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ for (i = 0; i < priv->dev.ports; i++) { -+ status = priv->chip->read_port_status(priv, i); -+ link_new = !!(status & AR8216_PORT_STATUS_LINK_UP); -+ if (link_new == priv->link_up[i]) -+ continue; -+ -+ priv->link_up[i] = link_new; -+ changed = true; -+ /* flush ARL entries for this port if it went down*/ -+ if (!link_new) -+ priv->chip->atu_flush_port(priv, i); -+ dev_info(&priv->phy->dev, "Port %d is %s\n", -+ i, link_new ? "up" : "down"); -+ } -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ return changed; -+} -+ -+static int -+ar8xxx_phy_read_status(struct phy_device *phydev) -+{ -+ struct ar8xxx_priv *priv = phydev->priv; -+ struct switch_port_link link; -+ -+ /* check for switch port link changes */ -+ if (phydev->state == PHY_CHANGELINK) -+ ar8xxx_check_link_states(priv); -+ -+ if (phydev->addr != 0) -+ return genphy_read_status(phydev); -+ -+ ar8216_read_port_link(priv, phydev->addr, &link); -+ phydev->link = !!link.link; -+ if (!phydev->link) -+ return 0; -+ -+ switch (link.speed) { -+ case SWITCH_PORT_SPEED_10: -+ phydev->speed = SPEED_10; -+ break; -+ case SWITCH_PORT_SPEED_100: -+ phydev->speed = SPEED_100; -+ break; -+ case SWITCH_PORT_SPEED_1000: -+ phydev->speed = SPEED_1000; -+ break; -+ default: -+ phydev->speed = 0; -+ } -+ phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF; -+ -+ phydev->state = PHY_RUNNING; -+ netif_carrier_on(phydev->attached_dev); -+ phydev->adjust_link(phydev->attached_dev); -+ -+ return 0; -+} -+ -+static int -+ar8xxx_phy_config_aneg(struct phy_device *phydev) -+{ -+ if (phydev->addr == 0) -+ return 0; -+ -+ return genphy_config_aneg(phydev); -+} -+ -+static const u32 ar8xxx_phy_ids[] = { -+ 0x004dd033, -+ 0x004dd034, /* AR8327 */ -+ 0x004dd036, /* AR8337 */ -+ 0x004dd041, -+ 0x004dd042, -+ 0x004dd043, /* AR8236 */ -+}; -+ -+static bool -+ar8xxx_phy_match(u32 phy_id) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++) -+ if (phy_id == ar8xxx_phy_ids[i]) -+ return true; -+ -+ return false; -+} -+ -+static bool -+ar8xxx_is_possible(struct mii_bus *bus) -+{ -+ unsigned i; -+ -+ for (i = 0; i < 4; i++) { -+ u32 phy_id; -+ -+ phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16; -+ phy_id |= mdiobus_read(bus, i, MII_PHYSID2); -+ if (!ar8xxx_phy_match(phy_id)) { -+ pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n", -+ dev_name(&bus->dev), i, phy_id); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static int -+ar8xxx_phy_probe(struct phy_device *phydev) -+{ -+ struct ar8xxx_priv *priv; -+ struct switch_dev *swdev; -+ int ret; -+ -+ /* skip PHYs at unused adresses */ -+ if (phydev->addr != 0 && phydev->addr != 4) -+ return -ENODEV; -+ -+ if (!ar8xxx_is_possible(phydev->bus)) -+ return -ENODEV; -+ -+ mutex_lock(&ar8xxx_dev_list_lock); -+ list_for_each_entry(priv, &ar8xxx_dev_list, list) -+ if (priv->mii_bus == phydev->bus) -+ goto found; -+ -+ priv = ar8xxx_create(); -+ if (priv == NULL) { -+ ret = -ENOMEM; -+ goto unlock; -+ } -+ -+ priv->mii_bus = phydev->bus; -+ -+ ret = ar8xxx_probe_switch(priv); -+ if (ret) -+ goto free_priv; -+ -+ swdev = &priv->dev; -+ swdev->alias = dev_name(&priv->mii_bus->dev); -+ ret = register_switch(swdev, NULL); -+ if (ret) -+ goto free_priv; -+ -+ pr_info("%s: %s rev. %u switch registered on %s\n", -+ swdev->devname, swdev->name, priv->chip_rev, -+ dev_name(&priv->mii_bus->dev)); -+ -+found: -+ priv->use_count++; -+ -+ if (phydev->addr == 0) { -+ if (ar8xxx_has_gige(priv)) { -+ phydev->supported = SUPPORTED_1000baseT_Full; -+ phydev->advertising = ADVERTISED_1000baseT_Full; -+ } else { -+ phydev->supported = SUPPORTED_100baseT_Full; -+ phydev->advertising = ADVERTISED_100baseT_Full; -+ } -+ -+ if (priv->chip->config_at_probe) { -+ priv->phy = phydev; -+ -+ ret = ar8xxx_start(priv); -+ if (ret) -+ goto err_unregister_switch; -+ } -+ } else { -+ if (ar8xxx_has_gige(priv)) { -+ phydev->supported |= SUPPORTED_1000baseT_Full; -+ phydev->advertising |= ADVERTISED_1000baseT_Full; -+ } -+ } -+ -+ phydev->priv = priv; -+ -+ list_add(&priv->list, &ar8xxx_dev_list); -+ -+ mutex_unlock(&ar8xxx_dev_list_lock); -+ -+ return 0; -+ -+err_unregister_switch: -+ if (--priv->use_count) -+ goto unlock; -+ -+ unregister_switch(&priv->dev); -+ -+free_priv: -+ ar8xxx_free(priv); -+unlock: -+ mutex_unlock(&ar8xxx_dev_list_lock); -+ return ret; -+} -+ -+static void -+ar8xxx_phy_remove(struct phy_device *phydev) -+{ -+ struct ar8xxx_priv *priv = phydev->priv; -+ -+ if (WARN_ON(!priv)) -+ return; -+ -+ phydev->priv = NULL; -+ if (--priv->use_count > 0) -+ return; -+ -+ mutex_lock(&ar8xxx_dev_list_lock); -+ list_del(&priv->list); -+ mutex_unlock(&ar8xxx_dev_list_lock); -+ -+ unregister_switch(&priv->dev); -+ ar8xxx_mib_stop(priv); -+ ar8xxx_free(priv); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) -+static int -+ar8xxx_phy_soft_reset(struct phy_device *phydev) -+{ -+ /* we don't need an extra reset */ -+ return 0; -+} -+#endif -+ -+static struct phy_driver ar8xxx_phy_driver = { -+ .phy_id = 0x004d0000, -+ .name = "Atheros AR8216/AR8236/AR8316", -+ .phy_id_mask = 0xffff0000, -+ .features = PHY_BASIC_FEATURES, -+ .probe = ar8xxx_phy_probe, -+ .remove = ar8xxx_phy_remove, -+ .config_init = ar8xxx_phy_config_init, -+ .config_aneg = ar8xxx_phy_config_aneg, -+ .read_status = ar8xxx_phy_read_status, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) -+ .soft_reset = ar8xxx_phy_soft_reset, -+#endif -+ .driver = { .owner = THIS_MODULE }, -+}; -+ -+int __init -+ar8xxx_init(void) -+{ -+ return phy_driver_register(&ar8xxx_phy_driver); -+} -+ -+void __exit -+ar8xxx_exit(void) -+{ -+ phy_driver_unregister(&ar8xxx_phy_driver); -+} -+ -+module_init(ar8xxx_init); -+module_exit(ar8xxx_exit); -+MODULE_LICENSE("GPL"); -+ -diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8216.h linux-4.1.6/drivers/net/phy/ar8216.h ---- linux-4.1.6.orig/drivers/net/phy/ar8216.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-4.1.6/drivers/net/phy/ar8216.h 2015-09-13 22:55:18.327374229 +0200 -@@ -0,0 +1,628 @@ -+/* -+ * ar8216.h: AR8216 switch driver -+ * -+ * Copyright (C) 2009 Felix Fietkau -+ * -+ * 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. -+ * -+ * 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 __AR8216_H -+#define __AR8216_H -+ -+#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) -+ -+#define AR8XXX_CAP_GIGE BIT(0) -+#define AR8XXX_CAP_MIB_COUNTERS BIT(1) -+ -+#define AR8XXX_NUM_PHYS 5 -+#define AR8216_PORT_CPU 0 -+#define AR8216_NUM_PORTS 6 -+#define AR8216_NUM_VLANS 16 -+#define AR8316_NUM_VLANS 4096 -+ -+/* size of the vlan table */ -+#define AR8X16_MAX_VLANS 128 -+#define AR8X16_PROBE_RETRIES 10 -+#define AR8X16_MAX_PORTS 8 -+ -+/* Atheros specific MII registers */ -+#define MII_ATH_MMD_ADDR 0x0d -+#define MII_ATH_MMD_DATA 0x0e -+#define MII_ATH_DBG_ADDR 0x1d -+#define MII_ATH_DBG_DATA 0x1e -+ -+#define AR8216_REG_CTRL 0x0000 -+#define AR8216_CTRL_REVISION BITS(0, 8) -+#define AR8216_CTRL_REVISION_S 0 -+#define AR8216_CTRL_VERSION BITS(8, 8) -+#define AR8216_CTRL_VERSION_S 8 -+#define AR8216_CTRL_RESET BIT(31) -+ -+#define AR8216_REG_FLOOD_MASK 0x002C -+#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) -+#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) -+#define AR8236_FM_CPU_BROADCAST_EN BIT(26) -+#define AR8236_FM_CPU_BCAST_FWD_EN BIT(25) -+ -+#define AR8216_REG_GLOBAL_CTRL 0x0030 -+#define AR8216_GCTRL_MTU BITS(0, 11) -+#define AR8236_GCTRL_MTU BITS(0, 14) -+#define AR8316_GCTRL_MTU BITS(0, 14) -+ -+#define AR8216_REG_VTU 0x0040 -+#define AR8216_VTU_OP BITS(0, 3) -+#define AR8216_VTU_OP_NOOP 0x0 -+#define AR8216_VTU_OP_FLUSH 0x1 -+#define AR8216_VTU_OP_LOAD 0x2 -+#define AR8216_VTU_OP_PURGE 0x3 -+#define AR8216_VTU_OP_REMOVE_PORT 0x4 -+#define AR8216_VTU_ACTIVE BIT(3) -+#define AR8216_VTU_FULL BIT(4) -+#define AR8216_VTU_PORT BITS(8, 4) -+#define AR8216_VTU_PORT_S 8 -+#define AR8216_VTU_VID BITS(16, 12) -+#define AR8216_VTU_VID_S 16 -+#define AR8216_VTU_PRIO BITS(28, 3) -+#define AR8216_VTU_PRIO_S 28 -+#define AR8216_VTU_PRIO_EN BIT(31) -+ -+#define AR8216_REG_VTU_DATA 0x0044 -+#define AR8216_VTUDATA_MEMBER BITS(0, 10) -+#define AR8236_VTUDATA_MEMBER BITS(0, 7) -+#define AR8216_VTUDATA_VALID BIT(11) -+ -+#define AR8216_REG_ATU_FUNC0 0x0050 -+#define AR8216_ATU_OP BITS(0, 3) -+#define AR8216_ATU_OP_NOOP 0x0 -+#define AR8216_ATU_OP_FLUSH 0x1 -+#define AR8216_ATU_OP_LOAD 0x2 -+#define AR8216_ATU_OP_PURGE 0x3 -+#define AR8216_ATU_OP_FLUSH_UNLOCKED 0x4 -+#define AR8216_ATU_OP_FLUSH_PORT 0x5 -+#define AR8216_ATU_OP_GET_NEXT 0x6 -+#define AR8216_ATU_ACTIVE BIT(3) -+#define AR8216_ATU_PORT_NUM BITS(8, 4) -+#define AR8216_ATU_PORT_NUM_S 8 -+#define AR8216_ATU_FULL_VIO BIT(12) -+#define AR8216_ATU_ADDR5 BITS(16, 8) -+#define AR8216_ATU_ADDR5_S 16 -+#define AR8216_ATU_ADDR4 BITS(24, 8) -+#define AR8216_ATU_ADDR4_S 24 -+ -+#define AR8216_REG_ATU_FUNC1 0x0054 -+#define AR8216_ATU_ADDR3 BITS(0, 8) -+#define AR8216_ATU_ADDR3_S 0 -+#define AR8216_ATU_ADDR2 BITS(8, 8) -+#define AR8216_ATU_ADDR2_S 8 -+#define AR8216_ATU_ADDR1 BITS(16, 8) -+#define AR8216_ATU_ADDR1_S 16 -+#define AR8216_ATU_ADDR0 BITS(24, 8) -+#define AR8216_ATU_ADDR0_S 24 -+ -+#define AR8216_REG_ATU_FUNC2 0x0058 -+#define AR8216_ATU_PORTS BITS(0, 6) -+#define AR8216_ATU_PORT0 BIT(0) -+#define AR8216_ATU_PORT1 BIT(1) -+#define AR8216_ATU_PORT2 BIT(2) -+#define AR8216_ATU_PORT3 BIT(3) -+#define AR8216_ATU_PORT4 BIT(4) -+#define AR8216_ATU_PORT5 BIT(5) -+#define AR8216_ATU_STATUS BITS(16, 4) -+#define AR8216_ATU_STATUS_S 16 -+ -+#define AR8216_REG_ATU_CTRL 0x005C -+#define AR8216_ATU_CTRL_AGE_EN BIT(17) -+#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) -+#define AR8216_ATU_CTRL_AGE_TIME_S 0 -+#define AR8236_ATU_CTRL_RES BIT(20) -+ -+#define AR8216_REG_MIB_FUNC 0x0080 -+#define AR8216_MIB_TIMER BITS(0, 16) -+#define AR8216_MIB_AT_HALF_EN BIT(16) -+#define AR8216_MIB_BUSY BIT(17) -+#define AR8216_MIB_FUNC BITS(24, 3) -+#define AR8216_MIB_FUNC_S 24 -+#define AR8216_MIB_FUNC_NO_OP 0x0 -+#define AR8216_MIB_FUNC_FLUSH 0x1 -+#define AR8216_MIB_FUNC_CAPTURE 0x3 -+#define AR8236_MIB_EN BIT(30) -+ -+#define AR8216_REG_GLOBAL_CPUPORT 0x0078 -+#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4) -+#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4 -+ -+#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) -+#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) -+#define AR8216_PORT_STATUS_SPEED BITS(0,2) -+#define AR8216_PORT_STATUS_SPEED_S 0 -+#define AR8216_PORT_STATUS_TXMAC BIT(2) -+#define AR8216_PORT_STATUS_RXMAC BIT(3) -+#define AR8216_PORT_STATUS_TXFLOW BIT(4) -+#define AR8216_PORT_STATUS_RXFLOW BIT(5) -+#define AR8216_PORT_STATUS_DUPLEX BIT(6) -+#define AR8216_PORT_STATUS_LINK_UP BIT(8) -+#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) -+#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) -+ -+#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) -+ -+/* port forwarding state */ -+#define AR8216_PORT_CTRL_STATE BITS(0, 3) -+#define AR8216_PORT_CTRL_STATE_S 0 -+ -+#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) -+ -+/* egress 802.1q mode */ -+#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) -+#define AR8216_PORT_CTRL_VLAN_MODE_S 8 -+ -+#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) -+#define AR8216_PORT_CTRL_HEADER BIT(11) -+#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) -+#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) -+#define AR8216_PORT_CTRL_LEARN BIT(14) -+#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) -+#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) -+ -+#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) -+ -+#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) -+#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 -+ -+#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) -+#define AR8216_PORT_VLAN_DEST_PORTS_S 16 -+ -+/* bit0 added to the priority field of egress frames */ -+#define AR8216_PORT_VLAN_TX_PRIO BIT(27) -+ -+/* port default priority */ -+#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) -+#define AR8216_PORT_VLAN_PRIORITY_S 28 -+ -+/* ingress 802.1q mode */ -+#define AR8216_PORT_VLAN_MODE BITS(30, 2) -+#define AR8216_PORT_VLAN_MODE_S 30 -+ -+#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) -+#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) -+ -+#define AR8216_STATS_RXBROAD 0x00 -+#define AR8216_STATS_RXPAUSE 0x04 -+#define AR8216_STATS_RXMULTI 0x08 -+#define AR8216_STATS_RXFCSERR 0x0c -+#define AR8216_STATS_RXALIGNERR 0x10 -+#define AR8216_STATS_RXRUNT 0x14 -+#define AR8216_STATS_RXFRAGMENT 0x18 -+#define AR8216_STATS_RX64BYTE 0x1c -+#define AR8216_STATS_RX128BYTE 0x20 -+#define AR8216_STATS_RX256BYTE 0x24 -+#define AR8216_STATS_RX512BYTE 0x28 -+#define AR8216_STATS_RX1024BYTE 0x2c -+#define AR8216_STATS_RXMAXBYTE 0x30 -+#define AR8216_STATS_RXTOOLONG 0x34 -+#define AR8216_STATS_RXGOODBYTE 0x38 -+#define AR8216_STATS_RXBADBYTE 0x40 -+#define AR8216_STATS_RXOVERFLOW 0x48 -+#define AR8216_STATS_FILTERED 0x4c -+#define AR8216_STATS_TXBROAD 0x50 -+#define AR8216_STATS_TXPAUSE 0x54 -+#define AR8216_STATS_TXMULTI 0x58 -+#define AR8216_STATS_TXUNDERRUN 0x5c -+#define AR8216_STATS_TX64BYTE 0x60 -+#define AR8216_STATS_TX128BYTE 0x64 -+#define AR8216_STATS_TX256BYTE 0x68 -+#define AR8216_STATS_TX512BYTE 0x6c -+#define AR8216_STATS_TX1024BYTE 0x70 -+#define AR8216_STATS_TXMAXBYTE 0x74 -+#define AR8216_STATS_TXOVERSIZE 0x78 -+#define AR8216_STATS_TXBYTE 0x7c -+#define AR8216_STATS_TXCOLLISION 0x84 -+#define AR8216_STATS_TXABORTCOL 0x88 -+#define AR8216_STATS_TXMULTICOL 0x8c -+#define AR8216_STATS_TXSINGLECOL 0x90 -+#define AR8216_STATS_TXEXCDEFER 0x94 -+#define AR8216_STATS_TXDEFER 0x98 -+#define AR8216_STATS_TXLATECOL 0x9c -+ -+#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008) -+#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12) -+#define AR8236_PORT_VLAN_DEFAULT_ID_S 16 -+#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3) -+#define AR8236_PORT_VLAN_PRIORITY_S 28 -+ -+#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c) -+#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7) -+#define AR8236_PORT_VLAN2_MEMBER_S 16 -+#define AR8236_PORT_VLAN2_TX_PRIO BIT(23) -+#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2) -+#define AR8236_PORT_VLAN2_VLAN_MODE_S 30 -+ -+#define AR8236_STATS_RXBROAD 0x00 -+#define AR8236_STATS_RXPAUSE 0x04 -+#define AR8236_STATS_RXMULTI 0x08 -+#define AR8236_STATS_RXFCSERR 0x0c -+#define AR8236_STATS_RXALIGNERR 0x10 -+#define AR8236_STATS_RXRUNT 0x14 -+#define AR8236_STATS_RXFRAGMENT 0x18 -+#define AR8236_STATS_RX64BYTE 0x1c -+#define AR8236_STATS_RX128BYTE 0x20 -+#define AR8236_STATS_RX256BYTE 0x24 -+#define AR8236_STATS_RX512BYTE 0x28 -+#define AR8236_STATS_RX1024BYTE 0x2c -+#define AR8236_STATS_RX1518BYTE 0x30 -+#define AR8236_STATS_RXMAXBYTE 0x34 -+#define AR8236_STATS_RXTOOLONG 0x38 -+#define AR8236_STATS_RXGOODBYTE 0x3c -+#define AR8236_STATS_RXBADBYTE 0x44 -+#define AR8236_STATS_RXOVERFLOW 0x4c -+#define AR8236_STATS_FILTERED 0x50 -+#define AR8236_STATS_TXBROAD 0x54 -+#define AR8236_STATS_TXPAUSE 0x58 -+#define AR8236_STATS_TXMULTI 0x5c -+#define AR8236_STATS_TXUNDERRUN 0x60 -+#define AR8236_STATS_TX64BYTE 0x64 -+#define AR8236_STATS_TX128BYTE 0x68 -+#define AR8236_STATS_TX256BYTE 0x6c -+#define AR8236_STATS_TX512BYTE 0x70 -+#define AR8236_STATS_TX1024BYTE 0x74 -+#define AR8236_STATS_TX1518BYTE 0x78 -+#define AR8236_STATS_TXMAXBYTE 0x7c -+#define AR8236_STATS_TXOVERSIZE 0x80 -+#define AR8236_STATS_TXBYTE 0x84 -+#define AR8236_STATS_TXCOLLISION 0x8c -+#define AR8236_STATS_TXABORTCOL 0x90 -+#define AR8236_STATS_TXMULTICOL 0x94 -+#define AR8236_STATS_TXSINGLECOL 0x98 -+#define AR8236_STATS_TXEXCDEFER 0x9c -+#define AR8236_STATS_TXDEFER 0xa0 -+#define AR8236_STATS_TXLATECOL 0xa4 -+ -+#define AR8316_REG_POSTRIP 0x0008 -+#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0) -+#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1) -+#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2) -+#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3) -+#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4) -+#define AR8316_POSTRIP_RTL_MODE BIT(5) -+#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6) -+#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7) -+#define AR8316_POSTRIP_SERDES_EN BIT(8) -+#define AR8316_POSTRIP_SEL_ANA_RST BIT(9) -+#define AR8316_POSTRIP_GATE_25M_EN BIT(10) -+#define AR8316_POSTRIP_SEL_CLK25M BIT(11) -+#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12) -+#define AR8316_POSTRIP_DBG_MODE_I BIT(13) -+#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14) -+#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15) -+#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16) -+#define AR8316_POSTRIP_LPW_STATE_EN BIT(17) -+#define AR8316_POSTRIP_MAN_EN BIT(18) -+#define AR8316_POSTRIP_PHY_PLL_ON BIT(19) -+#define AR8316_POSTRIP_LPW_EXIT BIT(20) -+#define AR8316_POSTRIP_TXDELAY_S0 BIT(21) -+#define AR8316_POSTRIP_TXDELAY_S1 BIT(22) -+#define AR8316_POSTRIP_RXDELAY_S0 BIT(23) -+#define AR8316_POSTRIP_LED_OPEN_EN BIT(24) -+#define AR8316_POSTRIP_SPI_EN BIT(25) -+#define AR8316_POSTRIP_RXDELAY_S1 BIT(26) -+#define AR8316_POSTRIP_POWER_ON_SEL BIT(31) -+ -+/* port speed */ -+enum { -+ AR8216_PORT_SPEED_10M = 0, -+ AR8216_PORT_SPEED_100M = 1, -+ AR8216_PORT_SPEED_1000M = 2, -+ AR8216_PORT_SPEED_ERR = 3, -+}; -+ -+/* ingress 802.1q mode */ -+enum { -+ AR8216_IN_PORT_ONLY = 0, -+ AR8216_IN_PORT_FALLBACK = 1, -+ AR8216_IN_VLAN_ONLY = 2, -+ AR8216_IN_SECURE = 3 -+}; -+ -+/* egress 802.1q mode */ -+enum { -+ AR8216_OUT_KEEP = 0, -+ AR8216_OUT_STRIP_VLAN = 1, -+ AR8216_OUT_ADD_VLAN = 2 -+}; -+ -+/* port forwarding state */ -+enum { -+ AR8216_PORT_STATE_DISABLED = 0, -+ AR8216_PORT_STATE_BLOCK = 1, -+ AR8216_PORT_STATE_LISTEN = 2, -+ AR8216_PORT_STATE_LEARN = 3, -+ AR8216_PORT_STATE_FORWARD = 4 -+}; -+ -+enum { -+ AR8XXX_VER_AR8216 = 0x01, -+ AR8XXX_VER_AR8236 = 0x03, -+ AR8XXX_VER_AR8316 = 0x10, -+ AR8XXX_VER_AR8327 = 0x12, -+ AR8XXX_VER_AR8337 = 0x13, -+}; -+ -+#define AR8XXX_NUM_ARL_RECORDS 100 -+ -+enum arl_op { -+ AR8XXX_ARL_INITIALIZE, -+ AR8XXX_ARL_GET_NEXT -+}; -+ -+struct arl_entry { -+ u8 port; -+ u8 mac[6]; -+}; -+ -+struct ar8xxx_priv; -+ -+struct ar8xxx_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+struct ar8xxx_chip { -+ unsigned long caps; -+ bool config_at_probe; -+ bool mii_lo_first; -+ -+ /* parameters to calculate REG_PORT_STATS_BASE */ -+ unsigned reg_port_stats_start; -+ unsigned reg_port_stats_length; -+ -+ int (*hw_init)(struct ar8xxx_priv *priv); -+ void (*cleanup)(struct ar8xxx_priv *priv); -+ -+ const char *name; -+ int vlans; -+ int ports; -+ const struct switch_dev_ops *swops; -+ -+ void (*init_globals)(struct ar8xxx_priv *priv); -+ void (*init_port)(struct ar8xxx_priv *priv, int port); -+ void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); -+ u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); -+ u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); -+ int (*atu_flush)(struct ar8xxx_priv *priv); -+ int (*atu_flush_port)(struct ar8xxx_priv *priv, int port); -+ void (*vtu_flush)(struct ar8xxx_priv *priv); -+ void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); -+ void (*phy_fixup)(struct ar8xxx_priv *priv, int phy); -+ void (*set_mirror_regs)(struct ar8xxx_priv *priv); -+ void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a, -+ u32 *status, enum arl_op op); -+ int (*sw_hw_apply)(struct switch_dev *dev); -+ -+ const struct ar8xxx_mib_desc *mib_decs; -+ unsigned num_mibs; -+ unsigned mib_func; -+}; -+ -+struct ar8xxx_priv { -+ struct switch_dev dev; -+ struct mii_bus *mii_bus; -+ struct phy_device *phy; -+ -+ int (*get_port_link)(unsigned port); -+ -+ const struct net_device_ops *ndo_old; -+ struct net_device_ops ndo; -+ struct mutex reg_mutex; -+ u8 chip_ver; -+ u8 chip_rev; -+ const struct ar8xxx_chip *chip; -+ void *chip_data; -+ bool initialized; -+ bool port4_phy; -+ char buf[2048]; -+ struct arl_entry arl_table[AR8XXX_NUM_ARL_RECORDS]; -+ char arl_buf[AR8XXX_NUM_ARL_RECORDS * 32 + 256]; -+ bool link_up[AR8X16_MAX_PORTS]; -+ -+ bool init; -+ -+ struct mutex mib_lock; -+ struct delayed_work mib_work; -+ int mib_next_port; -+ u64 *mib_stats; -+ -+ struct list_head list; -+ unsigned int use_count; -+ -+ /* all fields below are cleared on reset */ -+ bool vlan; -+ u16 vlan_id[AR8X16_MAX_VLANS]; -+ u8 vlan_table[AR8X16_MAX_VLANS]; -+ u8 vlan_tagged; -+ u16 pvid[AR8X16_MAX_PORTS]; -+ -+ /* mirroring */ -+ bool mirror_rx; -+ bool mirror_tx; -+ int source_port; -+ int monitor_port; -+}; -+ -+u32 -+ar8xxx_mii_read32(struct ar8xxx_priv *priv, int phy_id, int regnum); -+void -+ar8xxx_mii_write32(struct ar8xxx_priv *priv, int phy_id, int regnum, u32 val); -+u32 -+ar8xxx_read(struct ar8xxx_priv *priv, int reg); -+void -+ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val); -+u32 -+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); -+ -+void -+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, -+ u16 dbg_addr, u16 dbg_data); -+void -+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data); -+u16 -+ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr); -+void -+ar8xxx_phy_init(struct ar8xxx_priv *priv); -+int -+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan); -+int -+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan); -+int -+ar8xxx_sw_hw_apply(struct switch_dev *dev); -+int -+ar8xxx_sw_reset_switch(struct switch_dev *dev); -+int -+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port, -+ struct switch_port_link *link); -+int -+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_port_mib(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_get_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_flush_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8xxx_sw_set_flush_port_arl_table(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val); -+int -+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val); -+ -+static inline struct ar8xxx_priv * -+swdev_to_ar8xxx(struct switch_dev *swdev) -+{ -+ return container_of(swdev, struct ar8xxx_priv, dev); -+} -+ -+static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv) -+{ -+ return priv->chip->caps & AR8XXX_CAP_GIGE; -+} -+ -+static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv) -+{ -+ return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS; -+} -+ -+static inline bool chip_is_ar8216(struct ar8xxx_priv *priv) -+{ -+ return priv->chip_ver == AR8XXX_VER_AR8216; -+} -+ -+static inline bool chip_is_ar8236(struct ar8xxx_priv *priv) -+{ -+ return priv->chip_ver == AR8XXX_VER_AR8236; -+} -+ -+static inline bool chip_is_ar8316(struct ar8xxx_priv *priv) -+{ -+ return priv->chip_ver == AR8XXX_VER_AR8316; -+} -+ -+static inline bool chip_is_ar8327(struct ar8xxx_priv *priv) -+{ -+ return priv->chip_ver == AR8XXX_VER_AR8327; -+} -+ -+static inline bool chip_is_ar8337(struct ar8xxx_priv *priv) -+{ -+ return priv->chip_ver == AR8XXX_VER_AR8337; -+} -+ -+static inline void -+ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val) -+{ -+ ar8xxx_rmw(priv, reg, 0, val); -+} -+ -+static inline void -+ar8xxx_reg_clear(struct ar8xxx_priv *priv, int reg, u32 val) -+{ -+ ar8xxx_rmw(priv, reg, val, 0); -+} -+ -+static inline void -+split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) -+{ -+ regaddr >>= 1; -+ *r1 = regaddr & 0x1e; -+ -+ regaddr >>= 5; -+ *r2 = regaddr & 0x7; -+ -+ regaddr >>= 3; -+ *page = regaddr & 0x1ff; -+} -+ -+static inline void -+wait_for_page_switch(void) -+{ -+ udelay(5); -+} -+ -+#endif -diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8327.c linux-4.1.6/drivers/net/phy/ar8327.c ---- linux-4.1.6.orig/drivers/net/phy/ar8327.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-4.1.6/drivers/net/phy/ar8327.c 2015-09-13 22:55:18.331373990 +0200 -@@ -0,0 +1,1268 @@ -+/* -+ * ar8327.c: AR8216 switch driver -+ * -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * -+ * 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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ar8216.h" -+#include "ar8327.h" -+ -+extern const struct ar8xxx_mib_desc ar8236_mibs[39]; -+extern const struct switch_attr ar8xxx_sw_attr_vlan[1]; -+ -+static u32 -+ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) -+{ -+ u32 t; -+ -+ if (!cfg) -+ return 0; -+ -+ t = 0; -+ switch (cfg->mode) { -+ case AR8327_PAD_NC: -+ break; -+ -+ case AR8327_PAD_MAC2MAC_MII: -+ t = AR8327_PAD_MAC_MII_EN; -+ if (cfg->rxclk_sel) -+ t |= AR8327_PAD_MAC_MII_RXCLK_SEL; -+ if (cfg->txclk_sel) -+ t |= AR8327_PAD_MAC_MII_TXCLK_SEL; -+ break; -+ -+ case AR8327_PAD_MAC2MAC_GMII: -+ t = AR8327_PAD_MAC_GMII_EN; -+ if (cfg->rxclk_sel) -+ t |= AR8327_PAD_MAC_GMII_RXCLK_SEL; -+ if (cfg->txclk_sel) -+ t |= AR8327_PAD_MAC_GMII_TXCLK_SEL; -+ break; -+ -+ case AR8327_PAD_MAC_SGMII: -+ t = AR8327_PAD_SGMII_EN; -+ -+ /* -+ * WAR for the QUalcomm Atheros AP136 board. -+ * It seems that RGMII TX/RX delay settings needs to be -+ * applied for SGMII mode as well, The ethernet is not -+ * reliable without this. -+ */ -+ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; -+ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; -+ if (cfg->rxclk_delay_en) -+ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; -+ if (cfg->txclk_delay_en) -+ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; -+ -+ if (cfg->sgmii_delay_en) -+ t |= AR8327_PAD_SGMII_DELAY_EN; -+ -+ break; -+ -+ case AR8327_PAD_MAC2PHY_MII: -+ t = AR8327_PAD_PHY_MII_EN; -+ if (cfg->rxclk_sel) -+ t |= AR8327_PAD_PHY_MII_RXCLK_SEL; -+ if (cfg->txclk_sel) -+ t |= AR8327_PAD_PHY_MII_TXCLK_SEL; -+ break; -+ -+ case AR8327_PAD_MAC2PHY_GMII: -+ t = AR8327_PAD_PHY_GMII_EN; -+ if (cfg->pipe_rxclk_sel) -+ t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL; -+ if (cfg->rxclk_sel) -+ t |= AR8327_PAD_PHY_GMII_RXCLK_SEL; -+ if (cfg->txclk_sel) -+ t |= AR8327_PAD_PHY_GMII_TXCLK_SEL; -+ break; -+ -+ case AR8327_PAD_MAC_RGMII: -+ t = AR8327_PAD_RGMII_EN; -+ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S; -+ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S; -+ if (cfg->rxclk_delay_en) -+ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN; -+ if (cfg->txclk_delay_en) -+ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN; -+ break; -+ -+ case AR8327_PAD_PHY_GMII: -+ t = AR8327_PAD_PHYX_GMII_EN; -+ break; -+ -+ case AR8327_PAD_PHY_RGMII: -+ t = AR8327_PAD_PHYX_RGMII_EN; -+ break; -+ -+ case AR8327_PAD_PHY_MII: -+ t = AR8327_PAD_PHYX_MII_EN; -+ break; -+ } -+ -+ if (cfg->mac06_exchange_en) -+ t |= AR8337_PAD_MAC06_EXCHANGE_EN; -+ -+ return t; -+} -+ -+static void -+ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy) -+{ -+ switch (priv->chip_rev) { -+ case 1: -+ /* For 100M waveform */ -+ ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea); -+ /* Turn on Gigabit clock */ -+ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0); -+ break; -+ -+ case 2: -+ ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c); -+ ar8xxx_phy_mmd_write(priv, phy, 0x4007, 0x0); -+ /* fallthrough */ -+ case 4: -+ ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d); -+ ar8xxx_phy_mmd_write(priv, phy, 0x4003, 0x803f); -+ -+ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860); -+ ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46); -+ ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000); -+ break; -+ } -+} -+ -+static u32 -+ar8327_get_port_init_status(struct ar8327_port_cfg *cfg) -+{ -+ u32 t; -+ -+ if (!cfg->force_link) -+ return AR8216_PORT_STATUS_LINK_AUTO; -+ -+ t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC; -+ t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0; -+ t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0; -+ t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0; -+ -+ switch (cfg->speed) { -+ case AR8327_PORT_SPEED_10: -+ t |= AR8216_PORT_SPEED_10M; -+ break; -+ case AR8327_PORT_SPEED_100: -+ t |= AR8216_PORT_SPEED_100M; -+ break; -+ case AR8327_PORT_SPEED_1000: -+ t |= AR8216_PORT_SPEED_1000M; -+ break; -+ } -+ -+ return t; -+} -+ -+#define AR8327_LED_ENTRY(_num, _reg, _shift) \ -+ [_num] = { .reg = (_reg), .shift = (_shift) } -+ -+static const struct ar8327_led_entry -+ar8327_led_map[AR8327_NUM_LEDS] = { -+ AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14), -+ AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14), -+ AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14), -+ -+ AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8), -+ AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10), -+ AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12), -+ -+ AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14), -+ AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16), -+ AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18), -+ -+ AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20), -+ AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22), -+ AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24), -+ -+ AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30), -+ AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30), -+ AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30), -+}; -+ -+static void -+ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num, -+ enum ar8327_led_pattern pattern) -+{ -+ const struct ar8327_led_entry *entry; -+ -+ entry = &ar8327_led_map[led_num]; -+ ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg), -+ (3 << entry->shift), pattern << entry->shift); -+} -+ -+static void -+ar8327_led_work_func(struct work_struct *work) -+{ -+ struct ar8327_led *aled; -+ u8 pattern; -+ -+ aled = container_of(work, struct ar8327_led, led_work); -+ -+ spin_lock(&aled->lock); -+ pattern = aled->pattern; -+ spin_unlock(&aled->lock); -+ -+ ar8327_set_led_pattern(aled->sw_priv, aled->led_num, -+ pattern); -+} -+ -+static void -+ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern) -+{ -+ if (aled->pattern == pattern) -+ return; -+ -+ aled->pattern = pattern; -+ schedule_work(&aled->led_work); -+} -+ -+static inline struct ar8327_led * -+led_cdev_to_ar8327_led(struct led_classdev *led_cdev) -+{ -+ return container_of(led_cdev, struct ar8327_led, cdev); -+} -+ -+static int -+ar8327_led_blink_set(struct led_classdev *led_cdev, -+ unsigned long *delay_on, -+ unsigned long *delay_off) -+{ -+ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); -+ -+ if (*delay_on == 0 && *delay_off == 0) { -+ *delay_on = 125; -+ *delay_off = 125; -+ } -+ -+ if (*delay_on != 125 || *delay_off != 125) { -+ /* -+ * The hardware only supports blinking at 4Hz. Fall back -+ * to software implementation in other cases. -+ */ -+ return -EINVAL; -+ } -+ -+ spin_lock(&aled->lock); -+ -+ aled->enable_hw_mode = false; -+ ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK); -+ -+ spin_unlock(&aled->lock); -+ -+ return 0; -+} -+ -+static void -+ar8327_led_set_brightness(struct led_classdev *led_cdev, -+ enum led_brightness brightness) -+{ -+ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); -+ u8 pattern; -+ bool active; -+ -+ active = (brightness != LED_OFF); -+ active ^= aled->active_low; -+ -+ pattern = (active) ? AR8327_LED_PATTERN_ON : -+ AR8327_LED_PATTERN_OFF; -+ -+ spin_lock(&aled->lock); -+ -+ aled->enable_hw_mode = false; -+ ar8327_led_schedule_change(aled, pattern); -+ -+ spin_unlock(&aled->lock); -+} -+ -+static ssize_t -+ar8327_led_enable_hw_mode_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct led_classdev *led_cdev = dev_get_drvdata(dev); -+ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); -+ ssize_t ret = 0; -+ -+ spin_lock(&aled->lock); -+ ret += sprintf(buf, "%d\n", aled->enable_hw_mode); -+ spin_unlock(&aled->lock); -+ -+ return ret; -+} -+ -+static ssize_t -+ar8327_led_enable_hw_mode_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, -+ size_t size) -+{ -+ struct led_classdev *led_cdev = dev_get_drvdata(dev); -+ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev); -+ u8 pattern; -+ u8 value; -+ int ret; -+ -+ ret = kstrtou8(buf, 10, &value); -+ if (ret < 0) -+ return -EINVAL; -+ -+ spin_lock(&aled->lock); -+ -+ aled->enable_hw_mode = !!value; -+ if (aled->enable_hw_mode) -+ pattern = AR8327_LED_PATTERN_RULE; -+ else -+ pattern = AR8327_LED_PATTERN_OFF; -+ -+ ar8327_led_schedule_change(aled, pattern); -+ -+ spin_unlock(&aled->lock); -+ -+ return size; -+} -+ -+static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR, -+ ar8327_led_enable_hw_mode_show, -+ ar8327_led_enable_hw_mode_store); -+ -+static int -+ar8327_led_register(struct ar8327_led *aled) -+{ -+ int ret; -+ -+ ret = led_classdev_register(NULL, &aled->cdev); -+ if (ret < 0) -+ return ret; -+ -+ if (aled->mode == AR8327_LED_MODE_HW) { -+ ret = device_create_file(aled->cdev.dev, -+ &dev_attr_enable_hw_mode); -+ if (ret) -+ goto err_unregister; -+ } -+ -+ return 0; -+ -+err_unregister: -+ led_classdev_unregister(&aled->cdev); -+ return ret; -+} -+ -+static void -+ar8327_led_unregister(struct ar8327_led *aled) -+{ -+ if (aled->mode == AR8327_LED_MODE_HW) -+ device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode); -+ -+ led_classdev_unregister(&aled->cdev); -+ cancel_work_sync(&aled->led_work); -+} -+ -+static int -+ar8327_led_create(struct ar8xxx_priv *priv, -+ const struct ar8327_led_info *led_info) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ struct ar8327_led *aled; -+ int ret; -+ -+ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) -+ return 0; -+ -+ if (!led_info->name) -+ return -EINVAL; -+ -+ if (led_info->led_num >= AR8327_NUM_LEDS) -+ return -EINVAL; -+ -+ aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1, -+ GFP_KERNEL); -+ if (!aled) -+ return -ENOMEM; -+ -+ aled->sw_priv = priv; -+ aled->led_num = led_info->led_num; -+ aled->active_low = led_info->active_low; -+ aled->mode = led_info->mode; -+ -+ if (aled->mode == AR8327_LED_MODE_HW) -+ aled->enable_hw_mode = true; -+ -+ aled->name = (char *)(aled + 1); -+ strcpy(aled->name, led_info->name); -+ -+ aled->cdev.name = aled->name; -+ aled->cdev.brightness_set = ar8327_led_set_brightness; -+ aled->cdev.blink_set = ar8327_led_blink_set; -+ aled->cdev.default_trigger = led_info->default_trigger; -+ -+ spin_lock_init(&aled->lock); -+ mutex_init(&aled->mutex); -+ INIT_WORK(&aled->led_work, ar8327_led_work_func); -+ -+ ret = ar8327_led_register(aled); -+ if (ret) -+ goto err_free; -+ -+ data->leds[data->num_leds++] = aled; -+ -+ return 0; -+ -+err_free: -+ kfree(aled); -+ return ret; -+} -+ -+static void -+ar8327_led_destroy(struct ar8327_led *aled) -+{ -+ ar8327_led_unregister(aled); -+ kfree(aled); -+} -+ -+static void -+ar8327_leds_init(struct ar8xxx_priv *priv) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ unsigned i; -+ -+ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) -+ return; -+ -+ for (i = 0; i < data->num_leds; i++) { -+ struct ar8327_led *aled; -+ -+ aled = data->leds[i]; -+ -+ if (aled->enable_hw_mode) -+ aled->pattern = AR8327_LED_PATTERN_RULE; -+ else -+ aled->pattern = AR8327_LED_PATTERN_OFF; -+ -+ ar8327_set_led_pattern(priv, aled->led_num, aled->pattern); -+ } -+} -+ -+static void -+ar8327_leds_cleanup(struct ar8xxx_priv *priv) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ unsigned i; -+ -+ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS)) -+ return; -+ -+ for (i = 0; i < data->num_leds; i++) { -+ struct ar8327_led *aled; -+ -+ aled = data->leds[i]; -+ ar8327_led_destroy(aled); -+ } -+ -+ kfree(data->leds); -+} -+ -+static int -+ar8327_hw_config_pdata(struct ar8xxx_priv *priv, -+ struct ar8327_platform_data *pdata) -+{ -+ struct ar8327_led_cfg *led_cfg; -+ struct ar8327_data *data = priv->chip_data; -+ u32 pos, new_pos; -+ u32 t; -+ -+ if (!pdata) -+ return -EINVAL; -+ -+ priv->get_port_link = pdata->get_port_link; -+ -+ data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg); -+ data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg); -+ -+ t = ar8327_get_pad_cfg(pdata->pad0_cfg); -+ ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t); -+ t = ar8327_get_pad_cfg(pdata->pad5_cfg); -+ ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t); -+ t = ar8327_get_pad_cfg(pdata->pad6_cfg); -+ ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t); -+ -+ pos = ar8xxx_read(priv, AR8327_REG_POWER_ON_STRIP); -+ new_pos = pos; -+ -+ led_cfg = pdata->led_cfg; -+ if (led_cfg) { -+ if (led_cfg->open_drain) -+ new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN; -+ else -+ new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN; -+ -+ ar8xxx_write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0); -+ ar8xxx_write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1); -+ ar8xxx_write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2); -+ ar8xxx_write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3); -+ -+ if (new_pos != pos) -+ new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL; -+ } -+ -+ if (pdata->sgmii_cfg) { -+ t = pdata->sgmii_cfg->sgmii_ctrl; -+ if (priv->chip_rev == 1) -+ t |= AR8327_SGMII_CTRL_EN_PLL | -+ AR8327_SGMII_CTRL_EN_RX | -+ AR8327_SGMII_CTRL_EN_TX; -+ else -+ t &= ~(AR8327_SGMII_CTRL_EN_PLL | -+ AR8327_SGMII_CTRL_EN_RX | -+ AR8327_SGMII_CTRL_EN_TX); -+ -+ ar8xxx_write(priv, AR8327_REG_SGMII_CTRL, t); -+ -+ if (pdata->sgmii_cfg->serdes_aen) -+ new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN; -+ else -+ new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN; -+ } -+ -+ ar8xxx_write(priv, AR8327_REG_POWER_ON_STRIP, new_pos); -+ -+ if (pdata->leds && pdata->num_leds) { -+ int i; -+ -+ data->leds = kzalloc(pdata->num_leds * sizeof(void *), -+ GFP_KERNEL); -+ if (!data->leds) -+ return -ENOMEM; -+ -+ for (i = 0; i < pdata->num_leds; i++) -+ ar8327_led_create(priv, &pdata->leds[i]); -+ } -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static int -+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ const __be32 *paddr; -+ int len; -+ int i; -+ -+ paddr = of_get_property(np, "qca,ar8327-initvals", &len); -+ if (!paddr || len < (2 * sizeof(*paddr))) -+ return -EINVAL; -+ -+ len /= sizeof(*paddr); -+ -+ for (i = 0; i < len - 1; i += 2) { -+ u32 reg; -+ u32 val; -+ -+ reg = be32_to_cpup(paddr + i); -+ val = be32_to_cpup(paddr + i + 1); -+ -+ switch (reg) { -+ case AR8327_REG_PORT_STATUS(0): -+ data->port0_status = val; -+ break; -+ case AR8327_REG_PORT_STATUS(6): -+ data->port6_status = val; -+ break; -+ default: -+ ar8xxx_write(priv, reg, val); -+ break; -+ } -+ } -+ -+ return 0; -+} -+#else -+static inline int -+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np) -+{ -+ return -EINVAL; -+} -+#endif -+ -+static int -+ar8327_hw_init(struct ar8xxx_priv *priv) -+{ -+ int ret; -+ -+ priv->chip_data = kzalloc(sizeof(struct ar8327_data), GFP_KERNEL); -+ if (!priv->chip_data) -+ return -ENOMEM; -+ -+ if (priv->phy->dev.of_node) -+ ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node); -+ else -+ ret = ar8327_hw_config_pdata(priv, -+ priv->phy->dev.platform_data); -+ -+ if (ret) -+ return ret; -+ -+ ar8327_leds_init(priv); -+ -+ ar8xxx_phy_init(priv); -+ -+ return 0; -+} -+ -+static void -+ar8327_cleanup(struct ar8xxx_priv *priv) -+{ -+ ar8327_leds_cleanup(priv); -+} -+ -+static void -+ar8327_init_globals(struct ar8xxx_priv *priv) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ u32 t; -+ int i; -+ -+ /* enable CPU port and disable mirror port */ -+ t = AR8327_FWD_CTRL0_CPU_PORT_EN | -+ AR8327_FWD_CTRL0_MIRROR_PORT; -+ ar8xxx_write(priv, AR8327_REG_FWD_CTRL0, t); -+ -+ /* forward multicast and broadcast frames to CPU */ -+ t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) | -+ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) | -+ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S); -+ ar8xxx_write(priv, AR8327_REG_FWD_CTRL1, t); -+ -+ /* enable jumbo frames */ -+ ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE, -+ AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2); -+ -+ /* Enable MIB counters */ -+ ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN, -+ AR8327_MODULE_EN_MIB); -+ -+ /* Disable EEE on all phy's due to stability issues */ -+ for (i = 0; i < AR8XXX_NUM_PHYS; i++) -+ data->eee[i] = false; -+} -+ -+static void -+ar8327_init_port(struct ar8xxx_priv *priv, int port) -+{ -+ struct ar8327_data *data = priv->chip_data; -+ u32 t; -+ -+ if (port == AR8216_PORT_CPU) -+ t = data->port0_status; -+ else if (port == 6) -+ t = data->port6_status; -+ else -+ t = AR8216_PORT_STATUS_LINK_AUTO; -+ -+ ar8xxx_write(priv, AR8327_REG_PORT_STATUS(port), t); -+ ar8xxx_write(priv, AR8327_REG_PORT_HEADER(port), 0); -+ -+ t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S; -+ t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); -+ -+ t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); -+ -+ t = AR8327_PORT_LOOKUP_LEARN; -+ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); -+} -+ -+static u32 -+ar8327_read_port_status(struct ar8xxx_priv *priv, int port) -+{ -+ u32 t; -+ -+ t = ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); -+ /* map the flow control autoneg result bits to the flow control bits -+ * used in forced mode to allow ar8216_read_port_link detect -+ * flow control properly if autoneg is used -+ */ -+ if (t & AR8216_PORT_STATUS_LINK_UP && -+ t & AR8216_PORT_STATUS_LINK_AUTO) { -+ t &= ~(AR8216_PORT_STATUS_TXFLOW | AR8216_PORT_STATUS_RXFLOW); -+ if (t & AR8327_PORT_STATUS_TXFLOW_AUTO) -+ t |= AR8216_PORT_STATUS_TXFLOW; -+ if (t & AR8327_PORT_STATUS_RXFLOW_AUTO) -+ t |= AR8216_PORT_STATUS_RXFLOW; -+ } -+ -+ return t; -+} -+ -+static u32 -+ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) -+{ -+ int phy; -+ u16 t; -+ -+ if (port >= priv->dev.ports) -+ return 0; -+ -+ if (port == 0 || port == 6) -+ return 0; -+ -+ phy = port - 1; -+ -+ /* EEE Ability Auto-negotiation Result */ -+ ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x8000); -+ t = ar8xxx_phy_mmd_read(priv, phy, 0x4007); -+ -+ return mmd_eee_adv_to_ethtool_adv_t(t); -+} -+ -+static int -+ar8327_atu_flush(struct ar8xxx_priv *priv) -+{ -+ int ret; -+ -+ ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, -+ AR8327_ATU_FUNC_BUSY, 0); -+ if (!ret) -+ ar8xxx_write(priv, AR8327_REG_ATU_FUNC, -+ AR8327_ATU_FUNC_OP_FLUSH | -+ AR8327_ATU_FUNC_BUSY); -+ -+ return ret; -+} -+ -+static int -+ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port) -+{ -+ u32 t; -+ int ret; -+ -+ ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC, -+ AR8327_ATU_FUNC_BUSY, 0); -+ if (!ret) { -+ t = (port << AR8327_ATU_PORT_NUM_S); -+ t |= AR8327_ATU_FUNC_OP_FLUSH_PORT; -+ t |= AR8327_ATU_FUNC_BUSY; -+ ar8xxx_write(priv, AR8327_REG_ATU_FUNC, t); -+ } -+ -+ return ret; -+} -+ -+static void -+ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val) -+{ -+ if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1, -+ AR8327_VTU_FUNC1_BUSY, 0)) -+ return; -+ -+ if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD) -+ ar8xxx_write(priv, AR8327_REG_VTU_FUNC0, val); -+ -+ op |= AR8327_VTU_FUNC1_BUSY; -+ ar8xxx_write(priv, AR8327_REG_VTU_FUNC1, op); -+} -+ -+static void -+ar8327_vtu_flush(struct ar8xxx_priv *priv) -+{ -+ ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0); -+} -+ -+static void -+ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask) -+{ -+ u32 op; -+ u32 val; -+ int i; -+ -+ op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S); -+ val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL; -+ for (i = 0; i < AR8327_NUM_PORTS; i++) { -+ u32 mode; -+ -+ if ((port_mask & BIT(i)) == 0) -+ mode = AR8327_VTU_FUNC0_EG_MODE_NOT; -+ else if (priv->vlan == 0) -+ mode = AR8327_VTU_FUNC0_EG_MODE_KEEP; -+ else if ((priv->vlan_tagged & BIT(i)) || (priv->vlan_id[priv->pvid[i]] != vid)) -+ mode = AR8327_VTU_FUNC0_EG_MODE_TAG; -+ else -+ mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG; -+ -+ val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i); -+ } -+ ar8327_vtu_op(priv, op, val); -+} -+ -+static void -+ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 members) -+{ -+ u32 t; -+ u32 egress, ingress; -+ u32 pvid = priv->vlan_id[priv->pvid[port]]; -+ -+ if (priv->vlan) { -+ egress = AR8327_PORT_VLAN1_OUT_MODE_UNMOD; -+ ingress = AR8216_IN_SECURE; -+ } else { -+ egress = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH; -+ ingress = AR8216_IN_PORT_ONLY; -+ } -+ -+ t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S; -+ t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_VLAN0(port), t); -+ -+ t = AR8327_PORT_VLAN1_PORT_VLAN_PROP; -+ t |= egress << AR8327_PORT_VLAN1_OUT_MODE_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_VLAN1(port), t); -+ -+ t = members; -+ t |= AR8327_PORT_LOOKUP_LEARN; -+ t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S; -+ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S; -+ ar8xxx_write(priv, AR8327_REG_PORT_LOOKUP(port), t); -+} -+ -+static int -+ar8327_sw_get_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ u8 ports = priv->vlan_table[val->port_vlan]; -+ int i; -+ -+ val->len = 0; -+ for (i = 0; i < dev->ports; i++) { -+ struct switch_port *p; -+ -+ if (!(ports & (1 << i))) -+ continue; -+ -+ p = &val->value.ports[val->len++]; -+ p->id = i; -+ if ((priv->vlan_tagged & (1 << i)) || (priv->pvid[i] != val->port_vlan)) -+ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); -+ else -+ p->flags = 0; -+ } -+ return 0; -+} -+ -+static int -+ar8327_sw_set_ports(struct switch_dev *dev, struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ u8 *vt = &priv->vlan_table[val->port_vlan]; -+ int i; -+ -+ *vt = 0; -+ for (i = 0; i < val->len; i++) { -+ struct switch_port *p = &val->value.ports[i]; -+ -+ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) { -+ if (val->port_vlan == priv->pvid[p->id]) { -+ priv->vlan_tagged |= (1 << p->id); -+ } -+ } else { -+ priv->vlan_tagged &= ~(1 << p->id); -+ priv->pvid[p->id] = val->port_vlan; -+ } -+ -+ *vt |= 1 << p->id; -+ } -+ return 0; -+} -+ -+static void -+ar8327_set_mirror_regs(struct ar8xxx_priv *priv) -+{ -+ int port; -+ -+ /* reset all mirror registers */ -+ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, -+ AR8327_FWD_CTRL0_MIRROR_PORT, -+ (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S)); -+ for (port = 0; port < AR8327_NUM_PORTS; port++) { -+ ar8xxx_reg_clear(priv, AR8327_REG_PORT_LOOKUP(port), -+ AR8327_PORT_LOOKUP_ING_MIRROR_EN); -+ -+ ar8xxx_reg_clear(priv, AR8327_REG_PORT_HOL_CTRL1(port), -+ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); -+ } -+ -+ /* now enable mirroring if necessary */ -+ if (priv->source_port >= AR8327_NUM_PORTS || -+ priv->monitor_port >= AR8327_NUM_PORTS || -+ priv->source_port == priv->monitor_port) { -+ return; -+ } -+ -+ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0, -+ AR8327_FWD_CTRL0_MIRROR_PORT, -+ (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S)); -+ -+ if (priv->mirror_rx) -+ ar8xxx_reg_set(priv, AR8327_REG_PORT_LOOKUP(priv->source_port), -+ AR8327_PORT_LOOKUP_ING_MIRROR_EN); -+ -+ if (priv->mirror_tx) -+ ar8xxx_reg_set(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port), -+ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN); -+} -+ -+static int -+ar8327_sw_set_eee(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ struct ar8327_data *data = priv->chip_data; -+ int port = val->port_vlan; -+ int phy; -+ -+ if (port >= dev->ports) -+ return -EINVAL; -+ if (port == 0 || port == 6) -+ return -EOPNOTSUPP; -+ -+ phy = port - 1; -+ -+ data->eee[phy] = !!(val->value.i); -+ -+ return 0; -+} -+ -+static int -+ar8327_sw_get_eee(struct switch_dev *dev, -+ const struct switch_attr *attr, -+ struct switch_val *val) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ const struct ar8327_data *data = priv->chip_data; -+ int port = val->port_vlan; -+ int phy; -+ -+ if (port >= dev->ports) -+ return -EINVAL; -+ if (port == 0 || port == 6) -+ return -EOPNOTSUPP; -+ -+ phy = port - 1; -+ -+ val->value.i = data->eee[phy]; -+ -+ return 0; -+} -+ -+static void -+ar8327_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) -+{ -+ int timeout = 20; -+ -+ while (ar8xxx_mii_read32(priv, r2, r1) & AR8327_ATU_FUNC_BUSY && --timeout) -+ udelay(10); -+ -+ if (!timeout) -+ pr_err("ar8327: timeout waiting for atu to become ready\n"); -+} -+ -+static void ar8327_get_arl_entry(struct ar8xxx_priv *priv, -+ struct arl_entry *a, u32 *status, enum arl_op op) -+{ -+ struct mii_bus *bus = priv->mii_bus; -+ u16 r2, page; -+ u16 r1_data0, r1_data1, r1_data2, r1_func; -+ u32 t, val0, val1, val2; -+ int i; -+ -+ split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page); -+ r2 |= 0x10; -+ -+ r1_data1 = (AR8327_REG_ATU_DATA1 >> 1) & 0x1e; -+ r1_data2 = (AR8327_REG_ATU_DATA2 >> 1) & 0x1e; -+ r1_func = (AR8327_REG_ATU_FUNC >> 1) & 0x1e; -+ -+ switch (op) { -+ case AR8XXX_ARL_INITIALIZE: -+ /* all ATU registers are on the same page -+ * therefore set page only once -+ */ -+ bus->write(bus, 0x18, 0, page); -+ wait_for_page_switch(); -+ -+ ar8327_wait_atu_ready(priv, r2, r1_func); -+ -+ ar8xxx_mii_write32(priv, r2, r1_data0, 0); -+ ar8xxx_mii_write32(priv, r2, r1_data1, 0); -+ ar8xxx_mii_write32(priv, r2, r1_data2, 0); -+ break; -+ case AR8XXX_ARL_GET_NEXT: -+ ar8xxx_mii_write32(priv, r2, r1_func, -+ AR8327_ATU_FUNC_OP_GET_NEXT | -+ AR8327_ATU_FUNC_BUSY); -+ ar8327_wait_atu_ready(priv, r2, r1_func); -+ -+ val0 = ar8xxx_mii_read32(priv, r2, r1_data0); -+ val1 = ar8xxx_mii_read32(priv, r2, r1_data1); -+ val2 = ar8xxx_mii_read32(priv, r2, r1_data2); -+ -+ *status = val2 & AR8327_ATU_STATUS; -+ if (!*status) -+ break; -+ -+ i = 0; -+ t = AR8327_ATU_PORT0; -+ while (!(val1 & t) && ++i < AR8327_NUM_PORTS) -+ t <<= 1; -+ -+ a->port = i; -+ a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S; -+ a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S; -+ a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S; -+ a->mac[3] = (val0 & AR8327_ATU_ADDR3) >> AR8327_ATU_ADDR3_S; -+ a->mac[4] = (val1 & AR8327_ATU_ADDR4) >> AR8327_ATU_ADDR4_S; -+ a->mac[5] = (val1 & AR8327_ATU_ADDR5) >> AR8327_ATU_ADDR5_S; -+ break; -+ } -+} -+ -+static int -+ar8327_sw_hw_apply(struct switch_dev *dev) -+{ -+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); -+ const struct ar8327_data *data = priv->chip_data; -+ int ret, i; -+ -+ ret = ar8xxx_sw_hw_apply(dev); -+ if (ret) -+ return ret; -+ -+ for (i=0; i < AR8XXX_NUM_PHYS; i++) { -+ if (data->eee[i]) -+ ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL, -+ AR8327_EEE_CTRL_DISABLE_PHY(i)); -+ else -+ ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL, -+ AR8327_EEE_CTRL_DISABLE_PHY(i)); -+ } -+ -+ return 0; -+} -+ -+static const struct switch_attr ar8327_sw_attr_globals[] = { -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_vlan", -+ .description = "Enable VLAN mode", -+ .set = ar8xxx_sw_set_vlan, -+ .get = ar8xxx_sw_get_vlan, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "reset_mibs", -+ .description = "Reset all MIB counters", -+ .set = ar8xxx_sw_set_reset_mibs, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_mirror_rx", -+ .description = "Enable mirroring of RX packets", -+ .set = ar8xxx_sw_set_mirror_rx_enable, -+ .get = ar8xxx_sw_get_mirror_rx_enable, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_mirror_tx", -+ .description = "Enable mirroring of TX packets", -+ .set = ar8xxx_sw_set_mirror_tx_enable, -+ .get = ar8xxx_sw_get_mirror_tx_enable, -+ .max = 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "mirror_monitor_port", -+ .description = "Mirror monitor port", -+ .set = ar8xxx_sw_set_mirror_monitor_port, -+ .get = ar8xxx_sw_get_mirror_monitor_port, -+ .max = AR8327_NUM_PORTS - 1 -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "mirror_source_port", -+ .description = "Mirror source port", -+ .set = ar8xxx_sw_set_mirror_source_port, -+ .get = ar8xxx_sw_get_mirror_source_port, -+ .max = AR8327_NUM_PORTS - 1 -+ }, -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "arl_table", -+ .description = "Get ARL table", -+ .set = NULL, -+ .get = ar8xxx_sw_get_arl_table, -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "flush_arl_table", -+ .description = "Flush ARL table", -+ .set = ar8xxx_sw_set_flush_arl_table, -+ }, -+}; -+ -+static const struct switch_attr ar8327_sw_attr_port[] = { -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "reset_mib", -+ .description = "Reset single port MIB counters", -+ .set = ar8xxx_sw_set_port_reset_mib, -+ }, -+ { -+ .type = SWITCH_TYPE_STRING, -+ .name = "mib", -+ .description = "Get port's MIB counters", -+ .set = NULL, -+ .get = ar8xxx_sw_get_port_mib, -+ }, -+ { -+ .type = SWITCH_TYPE_INT, -+ .name = "enable_eee", -+ .description = "Enable EEE PHY sleep mode", -+ .set = ar8327_sw_set_eee, -+ .get = ar8327_sw_get_eee, -+ .max = 1, -+ }, -+ { -+ .type = SWITCH_TYPE_NOVAL, -+ .name = "flush_arl_table", -+ .description = "Flush port's ARL table entries", -+ .set = ar8xxx_sw_set_flush_port_arl_table, -+ }, -+}; -+ -+static const struct switch_dev_ops ar8327_sw_ops = { -+ .attr_global = { -+ .attr = ar8327_sw_attr_globals, -+ .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals), -+ }, -+ .attr_port = { -+ .attr = ar8327_sw_attr_port, -+ .n_attr = ARRAY_SIZE(ar8327_sw_attr_port), -+ }, -+ .attr_vlan = { -+ .attr = ar8xxx_sw_attr_vlan, -+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan), -+ }, -+ .get_port_pvid = ar8xxx_sw_get_pvid, -+ .set_port_pvid = ar8xxx_sw_set_pvid, -+ .get_vlan_ports = ar8327_sw_get_ports, -+ .set_vlan_ports = ar8327_sw_set_ports, -+ .apply_config = ar8327_sw_hw_apply, -+ .reset_switch = ar8xxx_sw_reset_switch, -+ .get_port_link = ar8xxx_sw_get_port_link, -+}; -+ -+const struct ar8xxx_chip ar8327_chip = { -+ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, -+ .config_at_probe = true, -+ .mii_lo_first = true, -+ -+ .name = "Atheros AR8327", -+ .ports = AR8327_NUM_PORTS, -+ .vlans = AR8X16_MAX_VLANS, -+ .swops = &ar8327_sw_ops, -+ -+ .reg_port_stats_start = 0x1000, -+ .reg_port_stats_length = 0x100, -+ -+ .hw_init = ar8327_hw_init, -+ .cleanup = ar8327_cleanup, -+ .init_globals = ar8327_init_globals, -+ .init_port = ar8327_init_port, -+ .setup_port = ar8327_setup_port, -+ .read_port_status = ar8327_read_port_status, -+ .read_port_eee_status = ar8327_read_port_eee_status, -+ .atu_flush = ar8327_atu_flush, -+ .atu_flush_port = ar8327_atu_flush_port, -+ .vtu_flush = ar8327_vtu_flush, -+ .vtu_load_vlan = ar8327_vtu_load_vlan, -+ .phy_fixup = ar8327_phy_fixup, -+ .set_mirror_regs = ar8327_set_mirror_regs, -+ .get_arl_entry = ar8327_get_arl_entry, -+ .sw_hw_apply = ar8327_sw_hw_apply, -+ -+ .num_mibs = ARRAY_SIZE(ar8236_mibs), -+ .mib_decs = ar8236_mibs, -+ .mib_func = AR8327_REG_MIB_FUNC -+}; -+ -+const struct ar8xxx_chip ar8337_chip = { -+ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS, -+ .config_at_probe = true, -+ .mii_lo_first = true, -+ -+ .name = "Atheros AR8337", -+ .ports = AR8327_NUM_PORTS, -+ .vlans = AR8X16_MAX_VLANS, -+ .swops = &ar8327_sw_ops, -+ -+ .reg_port_stats_start = 0x1000, -+ .reg_port_stats_length = 0x100, -+ -+ .hw_init = ar8327_hw_init, -+ .cleanup = ar8327_cleanup, -+ .init_globals = ar8327_init_globals, -+ .init_port = ar8327_init_port, -+ .setup_port = ar8327_setup_port, -+ .read_port_status = ar8327_read_port_status, -+ .read_port_eee_status = ar8327_read_port_eee_status, -+ .atu_flush = ar8327_atu_flush, -+ .atu_flush_port = ar8327_atu_flush_port, -+ .vtu_flush = ar8327_vtu_flush, -+ .vtu_load_vlan = ar8327_vtu_load_vlan, -+ .phy_fixup = ar8327_phy_fixup, -+ .set_mirror_regs = ar8327_set_mirror_regs, -+ .get_arl_entry = ar8327_get_arl_entry, -+ .sw_hw_apply = ar8327_sw_hw_apply, -+ -+ .num_mibs = ARRAY_SIZE(ar8236_mibs), -+ .mib_decs = ar8236_mibs, -+ .mib_func = AR8327_REG_MIB_FUNC -+}; -+ -diff -Nur linux-4.1.6.orig/drivers/net/phy/ar8327.h linux-4.1.6/drivers/net/phy/ar8327.h ---- linux-4.1.6.orig/drivers/net/phy/ar8327.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-4.1.6/drivers/net/phy/ar8327.h 2015-09-13 22:55:18.331373990 +0200 -@@ -0,0 +1,252 @@ -+/* -+ * ar8327.h: AR8216 switch driver -+ * -+ * Copyright (C) 2009 Felix Fietkau -+ * -+ * 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. -+ * -+ * 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 __AR8327_H -+#define __AR8327_H -+ -+#define AR8327_NUM_PORTS 7 -+#define AR8327_NUM_LEDS 15 -+#define AR8327_PORTS_ALL 0x7f -+#define AR8327_NUM_LED_CTRL_REGS 4 -+ -+#define AR8327_REG_MASK 0x000 -+ -+#define AR8327_REG_PAD0_MODE 0x004 -+#define AR8327_REG_PAD5_MODE 0x008 -+#define AR8327_REG_PAD6_MODE 0x00c -+#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0) -+#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1) -+#define AR8327_PAD_MAC_MII_EN BIT(2) -+#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4) -+#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5) -+#define AR8327_PAD_MAC_GMII_EN BIT(6) -+#define AR8327_PAD_SGMII_EN BIT(7) -+#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8) -+#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9) -+#define AR8327_PAD_PHY_MII_EN BIT(10) -+#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11) -+#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12) -+#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13) -+#define AR8327_PAD_PHY_GMII_EN BIT(14) -+#define AR8327_PAD_PHYX_GMII_EN BIT(16) -+#define AR8327_PAD_PHYX_RGMII_EN BIT(17) -+#define AR8327_PAD_PHYX_MII_EN BIT(18) -+#define AR8327_PAD_SGMII_DELAY_EN BIT(19) -+#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2) -+#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20 -+#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2) -+#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22 -+#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24) -+#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25) -+#define AR8327_PAD_RGMII_EN BIT(26) -+ -+#define AR8327_REG_POWER_ON_STRIP 0x010 -+#define AR8327_POWER_ON_STRIP_POWER_ON_SEL BIT(31) -+#define AR8327_POWER_ON_STRIP_LED_OPEN_EN BIT(24) -+#define AR8327_POWER_ON_STRIP_SERDES_AEN BIT(7) -+ -+#define AR8327_REG_INT_STATUS0 0x020 -+#define AR8327_INT0_VT_DONE BIT(20) -+ -+#define AR8327_REG_INT_STATUS1 0x024 -+#define AR8327_REG_INT_MASK0 0x028 -+#define AR8327_REG_INT_MASK1 0x02c -+ -+#define AR8327_REG_MODULE_EN 0x030 -+#define AR8327_MODULE_EN_MIB BIT(0) -+ -+#define AR8327_REG_MIB_FUNC 0x034 -+#define AR8327_MIB_CPU_KEEP BIT(20) -+ -+#define AR8327_REG_SERVICE_TAG 0x048 -+#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4) -+#define AR8327_REG_LED_CTRL0 0x050 -+#define AR8327_REG_LED_CTRL1 0x054 -+#define AR8327_REG_LED_CTRL2 0x058 -+#define AR8327_REG_LED_CTRL3 0x05c -+#define AR8327_REG_MAC_ADDR0 0x060 -+#define AR8327_REG_MAC_ADDR1 0x064 -+ -+#define AR8327_REG_MAX_FRAME_SIZE 0x078 -+#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14) -+ -+#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) -+#define AR8327_PORT_STATUS_TXFLOW_AUTO BIT(10) -+#define AR8327_PORT_STATUS_RXFLOW_AUTO BIT(11) -+ -+#define AR8327_REG_HEADER_CTRL 0x098 -+#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4) -+ -+#define AR8327_REG_SGMII_CTRL 0x0e0 -+#define AR8327_SGMII_CTRL_EN_PLL BIT(1) -+#define AR8327_SGMII_CTRL_EN_RX BIT(2) -+#define AR8327_SGMII_CTRL_EN_TX BIT(3) -+ -+#define AR8327_REG_EEE_CTRL 0x100 -+#define AR8327_EEE_CTRL_DISABLE_PHY(_i) BIT(4 + (_i) * 2) -+ -+#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8) -+#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12) -+#define AR8327_PORT_VLAN0_DEF_SVID_S 0 -+#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12) -+#define AR8327_PORT_VLAN0_DEF_CVID_S 16 -+ -+#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8) -+#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6) -+#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2) -+#define AR8327_PORT_VLAN1_OUT_MODE_S 12 -+#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0 -+#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1 -+#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2 -+#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3 -+ -+#define AR8327_REG_ATU_DATA0 0x600 -+#define AR8327_ATU_ADDR0 BITS(0, 8) -+#define AR8327_ATU_ADDR0_S 0 -+#define AR8327_ATU_ADDR1 BITS(8, 8) -+#define AR8327_ATU_ADDR1_S 8 -+#define AR8327_ATU_ADDR2 BITS(16, 8) -+#define AR8327_ATU_ADDR2_S 16 -+#define AR8327_ATU_ADDR3 BITS(24, 8) -+#define AR8327_ATU_ADDR3_S 24 -+#define AR8327_REG_ATU_DATA1 0x604 -+#define AR8327_ATU_ADDR4 BITS(0, 8) -+#define AR8327_ATU_ADDR4_S 0 -+#define AR8327_ATU_ADDR5 BITS(8, 8) -+#define AR8327_ATU_ADDR5_S 8 -+#define AR8327_ATU_PORTS BITS(16, 7) -+#define AR8327_ATU_PORT0 BIT(16) -+#define AR8327_ATU_PORT1 BIT(17) -+#define AR8327_ATU_PORT2 BIT(18) -+#define AR8327_ATU_PORT3 BIT(19) -+#define AR8327_ATU_PORT4 BIT(20) -+#define AR8327_ATU_PORT5 BIT(21) -+#define AR8327_ATU_PORT6 BIT(22) -+#define AR8327_REG_ATU_DATA2 0x608 -+#define AR8327_ATU_STATUS BITS(0, 4) -+ -+#define AR8327_REG_ATU_FUNC 0x60c -+#define AR8327_ATU_FUNC_OP BITS(0, 4) -+#define AR8327_ATU_FUNC_OP_NOOP 0x0 -+#define AR8327_ATU_FUNC_OP_FLUSH 0x1 -+#define AR8327_ATU_FUNC_OP_LOAD 0x2 -+#define AR8327_ATU_FUNC_OP_PURGE 0x3 -+#define AR8327_ATU_FUNC_OP_FLUSH_UNLOCKED 0x4 -+#define AR8327_ATU_FUNC_OP_FLUSH_PORT 0x5 -+#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6 -+#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7 -+#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8 -+#define AR8327_ATU_PORT_NUM BITS(8, 4) -+#define AR8327_ATU_PORT_NUM_S 8 -+#define AR8327_ATU_FUNC_BUSY BIT(31) -+ -+#define AR8327_REG_VTU_FUNC0 0x0610 -+#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14) -+#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) -+#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0 -+#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1 -+#define AR8327_VTU_FUNC0_EG_MODE_TAG 2 -+#define AR8327_VTU_FUNC0_EG_MODE_NOT 3 -+#define AR8327_VTU_FUNC0_IVL BIT(19) -+#define AR8327_VTU_FUNC0_VALID BIT(20) -+ -+#define AR8327_REG_VTU_FUNC1 0x0614 -+#define AR8327_VTU_FUNC1_OP BITS(0, 3) -+#define AR8327_VTU_FUNC1_OP_NOOP 0 -+#define AR8327_VTU_FUNC1_OP_FLUSH 1 -+#define AR8327_VTU_FUNC1_OP_LOAD 2 -+#define AR8327_VTU_FUNC1_OP_PURGE 3 -+#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4 -+#define AR8327_VTU_FUNC1_OP_GET_NEXT 5 -+#define AR8327_VTU_FUNC1_OP_GET_ONE 6 -+#define AR8327_VTU_FUNC1_FULL BIT(4) -+#define AR8327_VTU_FUNC1_PORT BIT(8, 4) -+#define AR8327_VTU_FUNC1_PORT_S 8 -+#define AR8327_VTU_FUNC1_VID BIT(16, 12) -+#define AR8327_VTU_FUNC1_VID_S 16 -+#define AR8327_VTU_FUNC1_BUSY BIT(31) -+ -+#define AR8327_REG_FWD_CTRL0 0x620 -+#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10) -+#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4) -+#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4 -+ -+#define AR8327_REG_FWD_CTRL1 0x624 -+#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7) -+#define AR8327_FWD_CTRL1_UC_FLOOD_S 0 -+#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7) -+#define AR8327_FWD_CTRL1_MC_FLOOD_S 8 -+#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7) -+#define AR8327_FWD_CTRL1_BC_FLOOD_S 16 -+#define AR8327_FWD_CTRL1_IGMP BITS(24, 7) -+#define AR8327_FWD_CTRL1_IGMP_S 24 -+ -+#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc) -+#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7) -+#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2) -+#define AR8327_PORT_LOOKUP_IN_MODE_S 8 -+#define AR8327_PORT_LOOKUP_STATE BITS(16, 3) -+#define AR8327_PORT_LOOKUP_STATE_S 16 -+#define AR8327_PORT_LOOKUP_LEARN BIT(20) -+#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25) -+ -+#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc) -+ -+#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) -+#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) -+ -+#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31) -+ -+enum ar8327_led_pattern { -+ AR8327_LED_PATTERN_OFF = 0, -+ AR8327_LED_PATTERN_BLINK, -+ AR8327_LED_PATTERN_ON, -+ AR8327_LED_PATTERN_RULE, -+}; -+ -+struct ar8327_led_entry { -+ unsigned reg; -+ unsigned shift; -+}; -+ -+struct ar8327_led { -+ struct led_classdev cdev; -+ struct ar8xxx_priv *sw_priv; -+ -+ char *name; -+ bool active_low; -+ u8 led_num; -+ enum ar8327_led_mode mode; -+ -+ struct mutex mutex; -+ spinlock_t lock; -+ struct work_struct led_work; -+ bool enable_hw_mode; -+ enum ar8327_led_pattern pattern; -+}; -+ -+struct ar8327_data { -+ u32 port0_status; -+ u32 port6_status; -+ -+ struct ar8327_led **leds; -+ unsigned int num_leds; -+ -+ /* all fields below are cleared on reset */ -+ bool eee[AR8XXX_NUM_PHYS]; -+}; -+ -+#endif -diff -Nur linux-4.1.6.orig/drivers/net/phy/Kconfig linux-4.1.6/drivers/net/phy/Kconfig ---- linux-4.1.6.orig/drivers/net/phy/Kconfig 2015-08-17 05:52:51.000000000 +0200 -+++ linux-4.1.6/drivers/net/phy/Kconfig 2015-09-13 22:33:30.867723129 +0200 -@@ -119,6 +119,15 @@ - ---help--- - Supports the KSZ9021, VSC8201, KS8001 PHYs. - -+config AR8216_PHY -+ tristate "Driver for Atheros AR8216 switches" -+ select ETHERNET_PACKET_MANGLE -+ select SWCONFIG -+ -+config AR8216_PHY_LEDS -+ bool "Atheros AR8216 switch LED support" -+ depends on (AR8216_PHY && LEDS_CLASS) -+ - config FIXED_PHY - tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" - depends on PHYLIB -diff -Nur linux-4.1.6.orig/drivers/net/phy/Makefile linux-4.1.6/drivers/net/phy/Makefile ---- linux-4.1.6.orig/drivers/net/phy/Makefile 2015-08-17 05:52:51.000000000 +0200 -+++ linux-4.1.6/drivers/net/phy/Makefile 2015-09-13 22:55:35.466351180 +0200 -@@ -16,6 +16,7 @@ - obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o - obj-$(CONFIG_ICPLUS_PHY) += icplus.o - obj-$(CONFIG_REALTEK_PHY) += realtek.o -+obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o - obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o - obj-$(CONFIG_FIXED_PHY) += fixed_phy.o - obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o -diff -Nur linux-4.1.6.orig/include/linux/ar8216_platform.h linux-4.1.6/include/linux/ar8216_platform.h ---- linux-4.1.6.orig/include/linux/ar8216_platform.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-4.1.6/include/linux/ar8216_platform.h 2015-09-13 22:33:30.871722898 +0200 -@@ -0,0 +1,133 @@ -+/* -+ * AR8216 switch driver platform data -+ * -+ * Copyright (C) 2012 Gabor Juhos -+ * -+ * 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. -+ * -+ * 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 AR8216_PLATFORM_H -+#define AR8216_PLATFORM_H -+ -+enum ar8327_pad_mode { -+ AR8327_PAD_NC = 0, -+ AR8327_PAD_MAC2MAC_MII, -+ AR8327_PAD_MAC2MAC_GMII, -+ AR8327_PAD_MAC_SGMII, -+ AR8327_PAD_MAC2PHY_MII, -+ AR8327_PAD_MAC2PHY_GMII, -+ AR8327_PAD_MAC_RGMII, -+ AR8327_PAD_PHY_GMII, -+ AR8327_PAD_PHY_RGMII, -+ AR8327_PAD_PHY_MII, -+}; -+ -+enum ar8327_clk_delay_sel { -+ AR8327_CLK_DELAY_SEL0 = 0, -+ AR8327_CLK_DELAY_SEL1, -+ AR8327_CLK_DELAY_SEL2, -+ AR8327_CLK_DELAY_SEL3, -+}; -+ -+struct ar8327_pad_cfg { -+ enum ar8327_pad_mode mode; -+ bool rxclk_sel; -+ bool txclk_sel; -+ bool pipe_rxclk_sel; -+ bool txclk_delay_en; -+ bool rxclk_delay_en; -+ bool sgmii_delay_en; -+ enum ar8327_clk_delay_sel txclk_delay_sel; -+ enum ar8327_clk_delay_sel rxclk_delay_sel; -+ bool mac06_exchange_en; -+}; -+ -+enum ar8327_port_speed { -+ AR8327_PORT_SPEED_10 = 0, -+ AR8327_PORT_SPEED_100, -+ AR8327_PORT_SPEED_1000, -+}; -+ -+struct ar8327_port_cfg { -+ int force_link:1; -+ enum ar8327_port_speed speed; -+ int txpause:1; -+ int rxpause:1; -+ int duplex:1; -+}; -+ -+struct ar8327_sgmii_cfg { -+ u32 sgmii_ctrl; -+ bool serdes_aen; -+}; -+ -+struct ar8327_led_cfg { -+ u32 led_ctrl0; -+ u32 led_ctrl1; -+ u32 led_ctrl2; -+ u32 led_ctrl3; -+ bool open_drain; -+}; -+ -+enum ar8327_led_num { -+ AR8327_LED_PHY0_0 = 0, -+ AR8327_LED_PHY0_1, -+ AR8327_LED_PHY0_2, -+ AR8327_LED_PHY1_0, -+ AR8327_LED_PHY1_1, -+ AR8327_LED_PHY1_2, -+ AR8327_LED_PHY2_0, -+ AR8327_LED_PHY2_1, -+ AR8327_LED_PHY2_2, -+ AR8327_LED_PHY3_0, -+ AR8327_LED_PHY3_1, -+ AR8327_LED_PHY3_2, -+ AR8327_LED_PHY4_0, -+ AR8327_LED_PHY4_1, -+ AR8327_LED_PHY4_2, -+}; -+ -+enum ar8327_led_mode { -+ AR8327_LED_MODE_HW = 0, -+ AR8327_LED_MODE_SW, -+}; -+ -+struct ar8327_led_info { -+ const char *name; -+ const char *default_trigger; -+ bool active_low; -+ enum ar8327_led_num led_num; -+ enum ar8327_led_mode mode; -+}; -+ -+#define AR8327_LED_INFO(_led, _mode, _name) { \ -+ .name = (_name), \ -+ .led_num = AR8327_LED_ ## _led, \ -+ .mode = AR8327_LED_MODE_ ## _mode \ -+} -+ -+struct ar8327_platform_data { -+ struct ar8327_pad_cfg *pad0_cfg; -+ struct ar8327_pad_cfg *pad5_cfg; -+ struct ar8327_pad_cfg *pad6_cfg; -+ struct ar8327_sgmii_cfg *sgmii_cfg; -+ struct ar8327_port_cfg port0_cfg; -+ struct ar8327_port_cfg port6_cfg; -+ struct ar8327_led_cfg *led_cfg; -+ -+ int (*get_port_link)(unsigned port); -+ -+ unsigned num_leds; -+ const struct ar8327_led_info *leds; -+}; -+ -+#endif /* AR8216_PLATFORM_H */ -+ -- cgit v1.2.3