Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: dsa: microchip: Ensure Stable PME Pin State for Wake-on-LAN

Ensures a stable PME (Power Management Event) pin state by disabling PME
on system start and enabling it on shutdown only if WoL (Wake-on-LAN) is
configured. This is needed to avoid issues with some PMICs (Power
Management ICs).

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://lore.kernel.org/r/20231026051051.2316937-6-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Oleksij Rempel and committed by
Jakub Kicinski
8afb91ac 77c819cb

+55 -1
+46
drivers/net/dsa/microchip/ksz9477.c
··· 197 197 return 0; 198 198 } 199 199 200 + /** 201 + * ksz9477_wol_pre_shutdown - Prepares the switch device for shutdown while 202 + * considering Wake-on-LAN (WoL) settings. 203 + * @dev: The switch device structure. 204 + * @wol_enabled: Pointer to a boolean which will be set to true if WoL is 205 + * enabled on any port. 206 + * 207 + * This function prepares the switch device for a safe shutdown while taking 208 + * into account the Wake-on-LAN (WoL) settings on the user ports. It updates 209 + * the wol_enabled flag accordingly to reflect whether WoL is active on any 210 + * port. 211 + */ 212 + void ksz9477_wol_pre_shutdown(struct ksz_device *dev, bool *wol_enabled) 213 + { 214 + struct dsa_port *dp; 215 + int ret; 216 + 217 + *wol_enabled = false; 218 + 219 + if (!dev->wakeup_source) 220 + return; 221 + 222 + dsa_switch_for_each_user_port(dp, dev->ds) { 223 + u8 pme_ctrl = 0; 224 + 225 + ret = ksz_pread8(dev, dp->index, REG_PORT_PME_CTRL, &pme_ctrl); 226 + if (!ret && pme_ctrl) 227 + *wol_enabled = true; 228 + 229 + /* make sure there are no pending wake events which would 230 + * prevent the device from going to sleep/shutdown. 231 + */ 232 + ksz9477_handle_wake_reason(dev, dp->index); 233 + } 234 + 235 + /* Now we are save to enable PME pin. */ 236 + if (*wol_enabled) 237 + ksz_write8(dev, REG_SW_PME_CTRL, PME_ENABLE); 238 + } 239 + 200 240 static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev) 201 241 { 202 242 unsigned int val; ··· 1316 1276 1317 1277 /* enable global MIB counter freeze function */ 1318 1278 ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true); 1279 + 1280 + /* Make sure PME (WoL) is not enabled. If requested, it will be 1281 + * enabled by ksz9477_wol_pre_shutdown(). Otherwise, some PMICs do not 1282 + * like PME events changes before shutdown. 1283 + */ 1284 + ksz_write8(dev, REG_SW_PME_CTRL, 0); 1319 1285 1320 1286 return 0; 1321 1287 }
+1
drivers/net/dsa/microchip/ksz9477.h
··· 62 62 struct ethtool_wolinfo *wol); 63 63 int ksz9477_set_wol(struct ksz_device *dev, int port, 64 64 struct ethtool_wolinfo *wol); 65 + void ksz9477_wol_pre_shutdown(struct ksz_device *dev, bool *wol_enabled); 65 66 66 67 int ksz9477_port_acl_init(struct ksz_device *dev, int port); 67 68 void ksz9477_port_acl_free(struct ksz_device *dev, int port);
+7 -1
drivers/net/dsa/microchip/ksz_common.c
··· 321 321 .phylink_mac_link_up = ksz9477_phylink_mac_link_up, 322 322 .get_wol = ksz9477_get_wol, 323 323 .set_wol = ksz9477_set_wol, 324 + .wol_pre_shutdown = ksz9477_wol_pre_shutdown, 324 325 .config_cpu_port = ksz9477_config_cpu_port, 325 326 .tc_cbs_set_cinc = ksz9477_tc_cbs_set_cinc, 326 327 .enable_stp_addr = ksz9477_enable_stp_addr, ··· 3858 3857 */ 3859 3858 void ksz_switch_shutdown(struct ksz_device *dev) 3860 3859 { 3861 - if (dev->dev_ops->reset) 3860 + bool wol_enabled = false; 3861 + 3862 + if (dev->dev_ops->wol_pre_shutdown) 3863 + dev->dev_ops->wol_pre_shutdown(dev, &wol_enabled); 3864 + 3865 + if (dev->dev_ops->reset && !wol_enabled) 3862 3866 dev->dev_ops->reset(dev); 3863 3867 3864 3868 dsa_switch_shutdown(dev->ds);
+1
drivers/net/dsa/microchip/ksz_common.h
··· 378 378 struct ethtool_wolinfo *wol); 379 379 int (*set_wol)(struct ksz_device *dev, int port, 380 380 struct ethtool_wolinfo *wol); 381 + void (*wol_pre_shutdown)(struct ksz_device *dev, bool *wol_enabled); 381 382 void (*config_cpu_port)(struct dsa_switch *ds); 382 383 int (*enable_stp_addr)(struct ksz_device *dev); 383 384 int (*reset)(struct ksz_device *dev);