All of lore.kernel.org
 help / color / mirror / Atom feed
* [Intel-wired-lan] [PATCH iwl-net v1 1/1] e1000e: change k1 exit timeout on MTP and later platforms
@ 2025-02-24 10:12 Vitaly Lifshits
  2025-02-24 13:53 ` Paul Menzel
  0 siblings, 1 reply; 3+ messages in thread
From: Vitaly Lifshits @ 2025-02-24 10:12 UTC (permalink / raw)
  To: intel-wired-lan; +Cc: Vitaly Lifshits

LAN devices starting from Meteorlake the interface between the MAC and
the PHY has a different frequency.
This caused sporadic MDI errors when accessing the PHY and a rare case
of packets corruption. To overcome this introduce a PHY K1 exit timeout
reconfiguration in the init flow. The exit timeout is reverted during
the hardware reset, thus, it is required to be called in a few places.

Fixes: cc23f4f0b6b9 ("e1000e: Add support for Meteor Lake")
Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
---
 drivers/net/ethernet/intel/e1000e/ich8lan.c | 78 +++++++++++++++++++--
 drivers/net/ethernet/intel/e1000e/ich8lan.h |  4 ++
 2 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 2f9655cf5dd9..d3636433938e 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -285,6 +285,46 @@ static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
 	}
 }
 
+/**
+ * e1000_reconfigure_k1_exit_timeout - reconfigure K1 exit timeout to
+ * align to MTP and later platform requirements.
+ * @hw: pointer to the HW structure
+ *
+ * Assuming that PHY semaphore is taken prior to this function call.
+ *
+ * Return: 0 on success, negative on failure
+ */
+static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw)
+{
+	u16 phy_timeout;
+	u32 fextnvm12;
+	s32 ret_val;
+
+	if (hw->mac.type < e1000_pch_mtp)
+		return 0;
+
+	/* Change Kumeran K1 power down state from P0s to P1 */
+	fextnvm12 = er32(FEXTNVM12);
+	fextnvm12 |= BIT(23);
+	fextnvm12 &= ~BIT(22);
+	ew32(FEXTNVM12, fextnvm12);
+
+	/* Wait for the interface the settle */
+	msleep(1);
+
+	/* Change K1 exit timeout */
+	ret_val = e1e_rphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
+				  &phy_timeout);
+	if (ret_val)
+		return ret_val;
+
+	phy_timeout &= ~E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK;
+	phy_timeout |= 0xF00;
+
+	return e1e_wphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
+				  phy_timeout);
+}
+
 /**
  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
  *  @hw: pointer to the HW structure
@@ -327,15 +367,23 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
 	 */
 	switch (hw->mac.type) {
+	case e1000_pch_mtp:
+	case e1000_pch_lnp:
+	case e1000_pch_ptp:
+	case e1000_pch_nvp:
+		/* At this point the PHY might be inaccessible so don't
+		 * propagate the failure
+		 */
+		if (e1000_reconfigure_k1_exit_timeout(hw))
+			break;
+
+		fallthrough;
 	case e1000_pch_lpt:
 	case e1000_pch_spt:
 	case e1000_pch_cnp:
 	case e1000_pch_tgp:
 	case e1000_pch_adp:
-	case e1000_pch_mtp:
-	case e1000_pch_lnp:
-	case e1000_pch_ptp:
-	case e1000_pch_nvp:
+
 		if (e1000_phy_is_accessible_pchlan(hw))
 			break;
 
@@ -421,6 +469,16 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 		ret_val = hw->phy.ops.check_reset_block(hw);
 		if (ret_val)
 			e_err("ME blocked access to PHY after reset\n");
+
+		if (hw->mac.type >= e1000_pch_mtp) {
+			ret_val = hw->phy.ops.acquire(hw);
+			if (ret_val) {
+				e_dbg("Failed to reconfigure K1 exit timeout\n");
+				goto out;
+			}
+			ret_val = e1000_reconfigure_k1_exit_timeout(hw);
+			hw->phy.ops.release(hw);
+		}
 	}
 
 out:
@@ -4888,6 +4946,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
 	u16 i;
 
 	e1000_initialize_hw_bits_ich8lan(hw);
+	if (hw->mac.type >= e1000_pch_mtp) {
+		ret_val = hw->phy.ops.acquire(hw);
+		if (ret_val)
+			return ret_val;
+
+		ret_val = e1000_reconfigure_k1_exit_timeout(hw);
+		if (ret_val) {
+			e_dbg("Error failed to reconfigure K1 exit timeout\n");
+			return ret_val;
+		}
+		hw->phy.ops.release(hw);
+	}
 
 	/* Initialize identification LED */
 	ret_val = mac->ops.id_led_init(hw);
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
index 2504b11c3169..dffc63e89ee2 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -219,6 +219,10 @@
 #define I217_PLL_CLOCK_GATE_REG	PHY_REG(772, 28)
 #define I217_PLL_CLOCK_GATE_MASK	0x07FF
 
+/* PHY Timeouts */
+#define E1000_PHY_TIMEOUTS_REG                   PHY_REG(770, 21)
+#define E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK       0x0FC0
+
 #define SW_FLAG_TIMEOUT		1000	/* SW Semaphore flag timeout in ms */
 
 /* Inband Control */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [Intel-wired-lan] [PATCH iwl-net v1 1/1] e1000e: change k1 exit timeout on MTP and later platforms
  2025-02-24 10:12 [Intel-wired-lan] [PATCH iwl-net v1 1/1] e1000e: change k1 exit timeout on MTP and later platforms Vitaly Lifshits
@ 2025-02-24 13:53 ` Paul Menzel
  2025-02-25 14:33   ` Lifshits, Vitaly
  0 siblings, 1 reply; 3+ messages in thread
From: Paul Menzel @ 2025-02-24 13:53 UTC (permalink / raw)
  To: Vitaly Lifshits; +Cc: intel-wired-lan

Dear Vitaly,


Thank you for your patch.

Am 24.02.25 um 11:12 schrieb Vitaly Lifshits:
> LAN devices starting from Meteorlake the interface between the MAC and

Meteor Lake

> the PHY has a different frequency.

The sentences reads a little strange. Maybe:

Starting with Meteor Lake, the frequency of MAC and PHY of the LAN 
devices differ, cf. datasheet X section Y.

Also, I’d add a blank between paragraphs.

> This caused sporadic MDI errors when accessing the PHY and a rare case

cause*s*

> of packets corruption. To overcome this introduce a PHY K1 exit timeout

Does Linux log these errors and corruptions?

> reconfiguration in the init flow. The exit timeout is reverted during
> the hardware reset, thus, it is required to be called in a few places.

Excuse my ignorance, but what do different frequencies have to do with 
the exit timeout?

How did you test this?

> Fixes: cc23f4f0b6b9 ("e1000e: Add support for Meteor Lake")
> Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
> ---
>   drivers/net/ethernet/intel/e1000e/ich8lan.c | 78 +++++++++++++++++++--
>   drivers/net/ethernet/intel/e1000e/ich8lan.h |  4 ++
>   2 files changed, 78 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
> index 2f9655cf5dd9..d3636433938e 100644
> --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
> +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
> @@ -285,6 +285,46 @@ static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
>   	}
>   }
>   
> +/**
> + * e1000_reconfigure_k1_exit_timeout - reconfigure K1 exit timeout to
> + * align to MTP and later platform requirements.
> + * @hw: pointer to the HW structure
> + *
> + * Assuming that PHY semaphore is taken prior to this function call.
> + *
> + * Return: 0 on success, negative on failure
> + */
> +static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw)

Why limit the variable length?

> +{
> +	u16 phy_timeout;

Please add the unit.

Why limit the variable length?

> +	u32 fextnvm12;
> +	s32 ret_val;
> +
> +	if (hw->mac.type < e1000_pch_mtp)
> +		return 0;
> +
> +	/* Change Kumeran K1 power down state from P0s to P1 */

What is Kumeran?

> +	fextnvm12 = er32(FEXTNVM12);
> +	fextnvm12 |= BIT(23);
> +	fextnvm12 &= ~BIT(22);
> +	ew32(FEXTNVM12, fextnvm12);
> +
> +	/* Wait for the interface the settle */
> +	msleep(1);

Any chance, of polling stuff instead of 1 ms sleep?

> +
> +	/* Change K1 exit timeout */
> +	ret_val = e1e_rphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
> +				  &phy_timeout);
> +	if (ret_val)
> +		return ret_val;
> +
> +	phy_timeout &= ~E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK;
> +	phy_timeout |= 0xF00;
> +
> +	return e1e_wphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
> +				  phy_timeout);
> +}
> +
>   /**
>    *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
>    *  @hw: pointer to the HW structure
> @@ -327,15 +367,23 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
>   	 * LANPHYPC Value bit to force the interconnect to PCIe mode.
>   	 */
>   	switch (hw->mac.type) {
> +	case e1000_pch_mtp:
> +	case e1000_pch_lnp:
> +	case e1000_pch_ptp:
> +	case e1000_pch_nvp:
> +		/* At this point the PHY might be inaccessible so don't
> +		 * propagate the failure
> +		 */
> +		if (e1000_reconfigure_k1_exit_timeout(hw))
> +			break;
> +
> +		fallthrough;
>   	case e1000_pch_lpt:
>   	case e1000_pch_spt:
>   	case e1000_pch_cnp:
>   	case e1000_pch_tgp:
>   	case e1000_pch_adp:
> -	case e1000_pch_mtp:
> -	case e1000_pch_lnp:
> -	case e1000_pch_ptp:
> -	case e1000_pch_nvp:
> +
>   		if (e1000_phy_is_accessible_pchlan(hw))
>   			break;
>   
> @@ -421,6 +469,16 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
>   		ret_val = hw->phy.ops.check_reset_block(hw);
>   		if (ret_val)
>   			e_err("ME blocked access to PHY after reset\n");
> +
> +		if (hw->mac.type >= e1000_pch_mtp) {
> +			ret_val = hw->phy.ops.acquire(hw);
> +			if (ret_val) {
> +				e_dbg("Failed to reconfigure K1 exit timeout\n");
> +				goto out;
> +			}
> +			ret_val = e1000_reconfigure_k1_exit_timeout(hw);
> +			hw->phy.ops.release(hw);
> +		}
>   	}
>   
>   out:
> @@ -4888,6 +4946,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
>   	u16 i;
>   
>   	e1000_initialize_hw_bits_ich8lan(hw);
> +	if (hw->mac.type >= e1000_pch_mtp) {
> +		ret_val = hw->phy.ops.acquire(hw);
> +		if (ret_val)
> +			return ret_val;
> +
> +		ret_val = e1000_reconfigure_k1_exit_timeout(hw);
> +		if (ret_val) {
> +			e_dbg("Error failed to reconfigure K1 exit timeout\n");

This differs from the log above. Use consistent error messages?

> +			return ret_val;
> +		}
> +		hw->phy.ops.release(hw);
> +	}
>   
>   	/* Initialize identification LED */
>   	ret_val = mac->ops.id_led_init(hw);
> diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
> index 2504b11c3169..dffc63e89ee2 100644
> --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
> +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
> @@ -219,6 +219,10 @@
>   #define I217_PLL_CLOCK_GATE_REG	PHY_REG(772, 28)
>   #define I217_PLL_CLOCK_GATE_MASK	0x07FF
>   
> +/* PHY Timeouts */
> +#define E1000_PHY_TIMEOUTS_REG                   PHY_REG(770, 21)
> +#define E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK       0x0FC0
> +
>   #define SW_FLAG_TIMEOUT		1000	/* SW Semaphore flag timeout in ms */
>   
>   /* Inband Control */


Kind regards,

Paul

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Intel-wired-lan] [PATCH iwl-net v1 1/1] e1000e: change k1 exit timeout on MTP and later platforms
  2025-02-24 13:53 ` Paul Menzel
@ 2025-02-25 14:33   ` Lifshits, Vitaly
  0 siblings, 0 replies; 3+ messages in thread
From: Lifshits, Vitaly @ 2025-02-25 14:33 UTC (permalink / raw)
  To: Paul Menzel; +Cc: intel-wired-lan



On 2/24/2025 3:53 PM, Paul Menzel wrote:
> Dear Vitaly,
> 
> 
> Thank you for your patch.
> 
> Am 24.02.25 um 11:12 schrieb Vitaly Lifshits:
>> LAN devices starting from Meteorlake the interface between the MAC and
> 
> Meteor Lake
> 
>> the PHY has a different frequency.
> 
> The sentences reads a little strange. Maybe:
> 
> Starting with Meteor Lake, the frequency of MAC and PHY of the LAN 
> devices differ, cf. datasheet X section Y.

Will be fixed in v2.

> 
> Also, I’d add a blank between paragraphs.
> 
>> This caused sporadic MDI errors when accessing the PHY and a rare case
> 
> cause*s*
> 
>> of packets corruption. To overcome this introduce a PHY K1 exit timeout
> 
> Does Linux log these errors and corruptions?

In some cases yes. When there is packet corruption the user encounters 
packet loss or re-transmissions on the wire. Both result in a lower 
performance.

For MDI errors, yes there are be error prints to the log.

> 
>> reconfiguration in the init flow. The exit timeout is reverted during
>> the hardware reset, thus, it is required to be called in a few places.
> 
> Excuse my ignorance, but what do different frequencies have to do with 
> the exit timeout?

I'll explain this better in the v2 version.

> 
> How did you test this?

Ran the failed flows and made sure that the issues don't reproduce.

> 
>> Fixes: cc23f4f0b6b9 ("e1000e: Add support for Meteor Lake")
>> Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
>> ---
>>   drivers/net/ethernet/intel/e1000e/ich8lan.c | 78 +++++++++++++++++++--
>>   drivers/net/ethernet/intel/e1000e/ich8lan.h |  4 ++
>>   2 files changed, 78 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/ 
>> net/ethernet/intel/e1000e/ich8lan.c
>> index 2f9655cf5dd9..d3636433938e 100644
>> --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
>> +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
>> @@ -285,6 +285,46 @@ static void e1000_toggle_lanphypc_pch_lpt(struct 
>> e1000_hw *hw)
>>       }
>>   }
>> +/**
>> + * e1000_reconfigure_k1_exit_timeout - reconfigure K1 exit timeout to
>> + * align to MTP and later platform requirements.
>> + * @hw: pointer to the HW structure
>> + *
>> + * Assuming that PHY semaphore is taken prior to this function call.
>> + *
>> + * Return: 0 on success, negative on failure
>> + */
>> +static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw)
> 
> Why limit the variable length?
> 
>> +{
>> +    u16 phy_timeout;
> 
> Please add the unit. >
> Why limit the variable length?

I am not sure that I understood your question here.
phy_timeout will hold the data from a PHY register, that has a size of 
uint16.

> 
>> +    u32 fextnvm12;
>> +    s32 ret_val;
>> +
>> +    if (hw->mac.type < e1000_pch_mtp)
>> +        return 0;
>> +
>> +    /* Change Kumeran K1 power down state from P0s to P1*/
> 
> What is Kumeran?

It is the interface between the MAC and the PHY.

> 
>> +    fextnvm12 = er32(FEXTNVM12);
>> +    fextnvm12 |= BIT(23);
>> +    fextnvm12 &= ~BIT(22);
>> +    ew32(FEXTNVM12, fextnvm12);
>> +
>> +    /* Wait for the interface the settle */
>> +    msleep(1);
> 
> Any chance, of polling stuff instead of 1 ms sleep?

No, there is no indication for this.

> 
>> +
>> +    /* Change K1 exit timeout */
>> +    ret_val = e1e_rphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
>> +                  &phy_timeout);
>> +    if (ret_val)
>> +        return ret_val;
>> +
>> +    phy_timeout &= ~E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK;
>> +    phy_timeout |= 0xF00;
>> +
>> +    return e1e_wphy_locked(hw, E1000_PHY_TIMEOUTS_REG,
>> +                  phy_timeout);
>> +}
>> +
>>   /**
>>    *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
>>    *  @hw: pointer to the HW structure
>> @@ -327,15 +367,23 @@ static s32 
>> e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
>>        * LANPHYPC Value bit to force the interconnect to PCIe mode.
>>        */
>>       switch (hw->mac.type) {
>> +    case e1000_pch_mtp:
>> +    case e1000_pch_lnp:
>> +    case e1000_pch_ptp:
>> +    case e1000_pch_nvp:
>> +        /* At this point the PHY might be inaccessible so don't
>> +         * propagate the failure
>> +         */
>> +        if (e1000_reconfigure_k1_exit_timeout(hw))
>> +            break;
>> +
>> +        fallthrough;
>>       case e1000_pch_lpt:
>>       case e1000_pch_spt:
>>       case e1000_pch_cnp:
>>       case e1000_pch_tgp:
>>       case e1000_pch_adp:
>> -    case e1000_pch_mtp:
>> -    case e1000_pch_lnp:
>> -    case e1000_pch_ptp:
>> -    case e1000_pch_nvp:
>> +
>>           if (e1000_phy_is_accessible_pchlan(hw))
>>               break;
>> @@ -421,6 +469,16 @@ static s32 
>> e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
>>           ret_val = hw->phy.ops.check_reset_block(hw);
>>           if (ret_val)
>>               e_err("ME blocked access to PHY after reset\n");
>> +
>> +        if (hw->mac.type >= e1000_pch_mtp) {
>> +            ret_val = hw->phy.ops.acquire(hw);
>> +            if (ret_val) {
>> +                e_dbg("Failed to reconfigure K1 exit timeout\n");
>> +                goto out;
>> +            }
>> +            ret_val = e1000_reconfigure_k1_exit_timeout(hw);
>> +            hw->phy.ops.release(hw);
>> +        }
>>       }
>>   out:
>> @@ -4888,6 +4946,18 @@ static s32 e1000_init_hw_ich8lan(struct 
>> e1000_hw *hw)
>>       u16 i;
>>       e1000_initialize_hw_bits_ich8lan(hw);
>> +    if (hw->mac.type >= e1000_pch_mtp) {
>> +        ret_val = hw->phy.ops.acquire(hw);
>> +        if (ret_val)
>> +            return ret_val;
>> +
>> +        ret_val = e1000_reconfigure_k1_exit_timeout(hw);
>> +        if (ret_val) {
>> +            e_dbg("Error failed to reconfigure K1 exit timeout\n");
> 
> This differs from the log above. Use consistent error messages?

I used here the same convention as in this whole function.
In addition, in the v2 version I changed the e_dbg to e_err so it will 
be printed as an error anyway.

> 
>> +            return ret_val;
>> +        }
>> +        hw->phy.ops.release(hw);
>> +    }
>>       /* Initialize identification LED */
>>       ret_val = mac->ops.id_led_init(hw);
>> diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/ 
>> net/ethernet/intel/e1000e/ich8lan.h
>> index 2504b11c3169..dffc63e89ee2 100644
>> --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
>> +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
>> @@ -219,6 +219,10 @@
>>   #define I217_PLL_CLOCK_GATE_REG    PHY_REG(772, 28)
>>   #define I217_PLL_CLOCK_GATE_MASK    0x07FF
>> +/* PHY Timeouts */
>> +#define E1000_PHY_TIMEOUTS_REG                   PHY_REG(770, 21)
>> +#define E1000_PHY_TIMEOUTS_K1_EXIT_TO_MASK       0x0FC0
>> +
>>   #define SW_FLAG_TIMEOUT       1000    /* SW Semaphore flag timeout 
>> in ms */
>>   /* Inband Control */
> 
> 
> Kind regards,
> 
> Paul


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-02-25 14:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-24 10:12 [Intel-wired-lan] [PATCH iwl-net v1 1/1] e1000e: change k1 exit timeout on MTP and later platforms Vitaly Lifshits
2025-02-24 13:53 ` Paul Menzel
2025-02-25 14:33   ` Lifshits, Vitaly

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.