@@ -56,6 +56,74 @@ int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu)
REG_SW_MTU_MASK, frame_size);
}
+static int ksz9477_handle_wake_reason(struct ksz_device *dev, int port)
+{
+ u8 pme_status;
+ int ret;
+
+ ret = ksz_pread8(dev, port, REG_PORT_PME_STATUS, &pme_status);
+ if (ret)
+ return ret;
+
+ if (pme_status)
+ dev_dbg(dev->dev, "Wake event on port %d due to: %s %s %s\n",
+ port,
+ pme_status & PME_WOL_MAGICPKT ? "\"Magic Packet\"" : "",
+ pme_status & PME_WOL_LINKUP ? "\"Link Up\"" : "",
+ pme_status & PME_WOL_ENERGY ? "\"Enery detect\"" : "");
+
+ return ksz_pwrite8(dev, port, REG_PORT_PME_STATUS, pme_status);
+}
+
+void ksz9477_get_wol(struct ksz_device *dev, int port,
+ struct ethtool_wolinfo *wol)
+{
+ u8 pme_ctrl, pme_conf;
+ int ret;
+
+ ret = ksz_read8(dev, REG_SW_PME_CTRL, &pme_conf);
+ if (ret)
+ return;
+
+ if (!(pme_conf & PME_ENABLE))
+ return;
+
+ wol->supported = WAKE_MAGIC;
+
+ ret = ksz_pread8(dev, port, REG_PORT_PME_CTRL, &pme_ctrl);
+ if (ret)
+ return;
+
+ if (pme_ctrl & PME_WOL_MAGICPKT)
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+int ksz9477_set_wol(struct ksz_device *dev, int port,
+ struct ethtool_wolinfo *wol)
+{
+ u8 pme_conf, pme_ctrl = 0;
+ int ret;
+
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+
+ ret = ksz_read8(dev, REG_SW_PME_CTRL, &pme_conf);
+ if (ret)
+ return ret;
+
+ if (!(pme_conf & PME_ENABLE))
+ return -EOPNOTSUPP;
+
+ ret = ksz9477_handle_wake_reason(dev, port);
+ if (ret)
+ return ret;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ pme_ctrl |= PME_WOL_MAGICPKT;
+
+ return ksz_pwrite8(dev, port, REG_PORT_PME_CTRL, pme_ctrl);
+}
+
static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev)
{
unsigned int val;
@@ -1004,6 +1072,9 @@ void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* clear pending interrupts */
if (dev->info->internal_phy[port])
ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
+
+ /* clear pending wake flags */
+ ksz9477_handle_wake_reason(dev, port);
}
void ksz9477_config_cpu_port(struct dsa_switch *ds)
@@ -58,6 +58,10 @@ int ksz9477_dsa_init(struct ksz_device *dev);
int ksz9477_switch_init(struct ksz_device *dev);
void ksz9477_switch_exit(struct ksz_device *dev);
void ksz9477_port_queue_split(struct ksz_device *dev, int port);
+void ksz9477_get_wol(struct ksz_device *dev, int port,
+ struct ethtool_wolinfo *wol);
+int ksz9477_set_wol(struct ksz_device *dev, int port,
+ struct ethtool_wolinfo *wol);
int ksz9477_port_acl_init(struct ksz_device *dev, int port);
int ksz9477_cls_flower_add(struct dsa_switch *ds, int port,
@@ -2819,6 +2819,45 @@ static int ksz_cls_flower_del(struct dsa_switch *ds, int port,
return -EOPNOTSUPP;
}
+static void ksz_get_wol(struct dsa_switch *ds, int port,
+ struct ethtool_wolinfo *wol)
+{
+ struct ksz_device *dev = ds->priv;
+
+ memset(wol, 0, sizeof(*wol));
+
+ switch (dev->chip_id) {
+ case KSZ8563_CHIP_ID:
+ case KSZ9477_CHIP_ID:
+ case KSZ9563_CHIP_ID:
+ case KSZ9567_CHIP_ID:
+ case KSZ9893_CHIP_ID:
+ case KSZ9896_CHIP_ID:
+ case KSZ9897_CHIP_ID:
+ ksz9477_get_wol(dev, port, wol);
+ return;
+ }
+}
+
+static int ksz_set_wol(struct dsa_switch *ds, int port,
+ struct ethtool_wolinfo *wol)
+{
+ struct ksz_device *dev = ds->priv;
+
+ switch (dev->chip_id) {
+ case KSZ8563_CHIP_ID:
+ case KSZ9477_CHIP_ID:
+ case KSZ9563_CHIP_ID:
+ case KSZ9567_CHIP_ID:
+ case KSZ9893_CHIP_ID:
+ case KSZ9896_CHIP_ID:
+ case KSZ9897_CHIP_ID:
+ return ksz9477_set_wol(dev, port, wol);
+ }
+
+ return -EOPNOTSUPP;
+}
+
static void ksz_set_xmii(struct ksz_device *dev, int port,
phy_interface_t interface)
{
@@ -3497,6 +3536,8 @@ static const struct dsa_switch_ops ksz_switch_ops = {
.set_mac_eee = ksz_set_mac_eee,
.cls_flower_add = ksz_cls_flower_add,
.cls_flower_del = ksz_cls_flower_del,
+ .get_wol = ksz_get_wol,
+ .set_wol = ksz_set_wol,
};
struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
Add WoL support for KSZ9477 family of switches. This code was tested on KSZ8563 chip and supports only wake on Magic Packet for now. Other parts needed for fully operational WoL support are in the followup patches. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- drivers/net/dsa/microchip/ksz9477.c | 71 ++++++++++++++++++++++++++ drivers/net/dsa/microchip/ksz9477.h | 4 ++ drivers/net/dsa/microchip/ksz_common.c | 41 +++++++++++++++ 3 files changed, 116 insertions(+)