em(4) reset I210 wake status

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

em(4) reset I210 wake status

Nathanael Rensen-3
When I boot an APU2 using wake-on-lan and then attempt to power off with
shutdown -hp it wakes itself up again. To prevent this it is necessary to
clear the I210 PME_STATUS flag. This is described in section 5.6.2 of the
I210 datasheet:

  The PE_WAKE_N remains asserted until the operating system either writes
  a 1b to the PMCSR.PME_Status bit or writes a 0b to the PMCSR.PME_En bit.

In addition the WUS (wake up status) register is not automatically cleared,
as described in section 8.2.13 of the i210 datasheet:

  This register is not cleared when PE_RST_N is asserted. It is only
  cleared when LAN_PWR_GOOD is deasserted or when cleared by the software
  device driver.

Nathanael

Index: sys/dev/pci/if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.344
diff -u -p -r1.344 if_em.c
--- sys/dev/pci/if_em.c 4 Feb 2020 10:59:23 -0000 1.344
+++ sys/dev/pci/if_em.c 5 Feb 2020 14:01:34 -0000
@@ -561,6 +561,9 @@ em_attach(struct device *parent, struct
 #endif
  printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
 
+ if (sc->hw.wus)
+ printf("%s wakeup: %d\n", sc->sc_dev.dv_xname, sc->hw.wus);
+
  /* Indicate SOL/IDER usage */
  if (em_check_phy_reset_block(&sc->hw))
  printf("%s: PHY reset is blocked due to SOL/IDER session.\n",
Index: sys/dev/pci/if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.106
diff -u -p -r1.106 if_em_hw.c
--- sys/dev/pci/if_em_hw.c 4 Feb 2020 10:59:23 -0000 1.106
+++ sys/dev/pci/if_em_hw.c 5 Feb 2020 14:01:34 -0000
@@ -1678,6 +1678,12 @@ em_init_hw(struct em_hw *hw)
  ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) |
     E1000_TXDCTL_FULL_TX_DESC_WB;
  E1000_WRITE_REG(hw, TXDCTL(1), ctrl);
+ hw->wus = E1000_READ_REG(hw, WUS);
+ if (hw->wus)
+ E1000_WRITE_REG(hw, WUS, reg_data);
+ reg_data = E1000_READ_REG(hw, WUC);
+ if (reg_data & E1000_WUC_PME_STATUS)
+ E1000_WRITE_REG(hw, WUC, reg_data);
  break;
  }
 
Index: sys/dev/pci/if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.80
diff -u -p -r1.80 if_em_hw.h
--- sys/dev/pci/if_em_hw.h 4 Feb 2020 10:59:23 -0000 1.80
+++ sys/dev/pci/if_em_hw.h 5 Feb 2020 14:01:34 -0000
@@ -1482,6 +1482,7 @@ struct em_hw {
     uint16_t swfw;
     boolean_t eee_enable;
     int sw_flag;
+    int wus;
 };
 
 #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */

Reply | Threaded
Open this post in threaded view
|

Re: em(4) reset I210 wake status

Claudio Jeker
On Wed, Feb 05, 2020 at 10:32:09PM +0800, Nathanael Rensen wrote:

> When I boot an APU2 using wake-on-lan and then attempt to power off with
> shutdown -hp it wakes itself up again. To prevent this it is necessary to
> clear the I210 PME_STATUS flag. This is described in section 5.6.2 of the
> I210 datasheet:
>
>   The PE_WAKE_N remains asserted until the operating system either writes
>   a 1b to the PMCSR.PME_Status bit or writes a 0b to the PMCSR.PME_En bit.
>
> In addition the WUS (wake up status) register is not automatically cleared,
> as described in section 8.2.13 of the i210 datasheet:
>
>   This register is not cleared when PE_RST_N is asserted. It is only
>   cleared when LAN_PWR_GOOD is deasserted or when cleared by the software
>   device driver.
>
> Nathanael
>
> Index: sys/dev/pci/if_em.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_em.c,v
> retrieving revision 1.344
> diff -u -p -r1.344 if_em.c
> --- sys/dev/pci/if_em.c 4 Feb 2020 10:59:23 -0000 1.344
> +++ sys/dev/pci/if_em.c 5 Feb 2020 14:01:34 -0000
> @@ -561,6 +561,9 @@ em_attach(struct device *parent, struct
>  #endif
>   printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
>  
> + if (sc->hw.wus)
> + printf("%s wakeup: %d\n", sc->sc_dev.dv_xname, sc->hw.wus);
> +

Why do you need that? Is there a point to know which device got the
wakeup? In any case this should be folded into the regular device dmesg
line and not be a new line. e.g
em0 at pci1 dev 0 function 0 "Intel I210" rev 0x03: msi, address XX:YY, wakeup

Not sure if any other driver prints a message for a wakeup event.
So maybe hw.wus is not needed and then only the if_em_hw.c part of the
diff is needed.

>   /* Indicate SOL/IDER usage */
>   if (em_check_phy_reset_block(&sc->hw))
>   printf("%s: PHY reset is blocked due to SOL/IDER session.\n",
> Index: sys/dev/pci/if_em_hw.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
> retrieving revision 1.106
> diff -u -p -r1.106 if_em_hw.c
> --- sys/dev/pci/if_em_hw.c 4 Feb 2020 10:59:23 -0000 1.106
> +++ sys/dev/pci/if_em_hw.c 5 Feb 2020 14:01:34 -0000
> @@ -1678,6 +1678,12 @@ em_init_hw(struct em_hw *hw)
>   ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) |
>      E1000_TXDCTL_FULL_TX_DESC_WB;
>   E1000_WRITE_REG(hw, TXDCTL(1), ctrl);
> + hw->wus = E1000_READ_REG(hw, WUS);
> + if (hw->wus)
> + E1000_WRITE_REG(hw, WUS, reg_data);

What is reg_data? Guess you want to write back hw->wus or 0 to clear it.

> + reg_data = E1000_READ_REG(hw, WUC);
> + if (reg_data & E1000_WUC_PME_STATUS)
> + E1000_WRITE_REG(hw, WUC, reg_data);
>   break;
>   }
>  
> Index: sys/dev/pci/if_em_hw.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
> retrieving revision 1.80
> diff -u -p -r1.80 if_em_hw.h
> --- sys/dev/pci/if_em_hw.h 4 Feb 2020 10:59:23 -0000 1.80
> +++ sys/dev/pci/if_em_hw.h 5 Feb 2020 14:01:34 -0000
> @@ -1482,6 +1482,7 @@ struct em_hw {
>      uint16_t swfw;
>      boolean_t eee_enable;
>      int sw_flag;
> +    int wus;
>  };
>  
>  #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
>

--
:wq Claudio