diff mbox series

[net-next,v5] net: macb: Fix several edge cases in validate

Message ID 20211101150422.2811030-1-sean.anderson@seco.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [net-next,v5] net: macb: Fix several edge cases in validate | expand

Checks

Context Check Description
netdev/cover_letter success Single patches do not need cover letters
netdev/fixes_present success Fixes tag not required for -next series
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for net-next
netdev/subject_prefix success Link
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 25 this patch: 25
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success No Fixes tag
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 134 lines checked
netdev/build_allmodconfig_warn success Errors and warnings before: 25 this patch: 25
netdev/header_inline success No static functions without inline keyword in header files

Commit Message

Sean Anderson Nov. 1, 2021, 3:04 p.m. UTC
There were several cases where validate() would return bogus supported
modes with unusual combinations of interfaces and capabilities. For
example, if state->interface was 10GBASER and the macb had HIGH_SPEED
and PCS but not GIGABIT MODE, then 10/100 modes would be set anyway. In
another case, SGMII could be enabled even if the mac was not a GEM
(despite this being checked for later on in mac_config()). These
inconsistencies make it difficult to refactor this function cleanly.

There is still the open question of what exactly the requirements for
SGMII and 10GBASER are, and what SGMII actually supports. If someone
from Cadence (or anyone else with access to the GEM/MACB datasheet)
could comment on this, it would be greatly appreciated. In particular,
what is supported by Cadence vs. vendor extension/limitation?

To address this, the current logic is split into three parts. First, we
determine what we support, then we eliminate unsupported interfaces, and
finally we set the appropriate link modes. There is still some cruft
related to NA, but this can be removed in a future patch.

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
---

Changes in v5:
- Refactor, taking into account Russell's suggestions

Changes in v4:
- Drop cleanup patch
- Refactor to just address logic issues

Changes in v3:
- Order bugfix patch first

Changes in v2:
- New

 drivers/net/ethernet/cadence/macb_main.c | 108 +++++++++++++++--------
 1 file changed, 71 insertions(+), 37 deletions(-)

Comments

Parshuram Raju Thombare Nov. 3, 2021, 10:14 a.m. UTC | #1
Hi Sean,

Thanks for this improvement.

>+	if (!macb_is_gem(bp) ||
>+	    (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>+		have_1g = true;
>+		if (bp->caps & MACB_CAPS_PCS)
>+			have_sgmii = true;
>+		if (bp->caps & MACB_CAPS_HIGH_SPEED)
>+			have_10g = true;

As I understand, MACB_CAPS_GIGABIT_MODE_AVAILABLE is used as a quirk in configs
to prevent giga bit operation support, Nicolas should have more information about this.

macb_is_gem() tells whether giga bit operations is supported by HW, MACB_CAPS_PCS indicate
whether PCS is included in the design (needed for SGMII and 10G operation), MACB_CAPS_HIGH_SPEED
indicate if design supports 10G operation.

I believe this should be

>+	if (macb_is_gem(bp) &&
>+	    (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>+		have_1g = true;
>+		if (bp->caps & MACB_CAPS_PCS)
>+			have_sgmii = true;
>+		if (bp->caps & MACB_CAPS_HIGH_SPEED)
>+			have_10g = true;

Regards,
Parshuram Thombare
Sean Anderson Nov. 4, 2021, 3:08 p.m. UTC | #2
On 11/3/21 6:14 AM, Parshuram Raju Thombare wrote:
> Hi Sean,
> 
> Thanks for this improvement.
> 
>>+	if (!macb_is_gem(bp) ||
>>+	    (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>>+		have_1g = true;
>>+		if (bp->caps & MACB_CAPS_PCS)
>>+			have_sgmii = true;
>>+		if (bp->caps & MACB_CAPS_HIGH_SPEED)
>>+			have_10g = true;
> 
> As I understand, MACB_CAPS_GIGABIT_MODE_AVAILABLE is used as a quirk in configs
> to prevent giga bit operation support, Nicolas should have more information about this.
> 
> macb_is_gem() tells whether giga bit operations is supported by HW, MACB_CAPS_PCS indicate
> whether PCS is included in the design (needed for SGMII and 10G operation), MACB_CAPS_HIGH_SPEED
> indicate if design supports 10G operation.
> 
> I believe this should be
> 
>>+	if (macb_is_gem(bp) &&
>>+	    (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>>+		have_1g = true;
>>+		if (bp->caps & MACB_CAPS_PCS)
>>+			have_sgmii = true;
>>+		if (bp->caps & MACB_CAPS_HIGH_SPEED)
>>+			have_10g = true;

Ah, you are correct. It seems I forgot to invert this condition.

--Sean
Nicolas Ferre Nov. 4, 2021, 3:15 p.m. UTC | #3
On 03/11/2021 at 11:14, Parshuram Raju Thombare wrote:
> Hi Sean,
> 
> Thanks for this improvement.
> 
>> +      if (!macb_is_gem(bp) ||
>> +          (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>> +              have_1g = true;
>> +              if (bp->caps & MACB_CAPS_PCS)
>> +                      have_sgmii = true;
>> +              if (bp->caps & MACB_CAPS_HIGH_SPEED)
>> +                      have_10g = true;
> 
> As I understand, MACB_CAPS_GIGABIT_MODE_AVAILABLE is used as a quirk in configs
> to prevent giga bit operation support, Nicolas should have more information about this.

That's right Parshuram.

> macb_is_gem() tells whether giga bit operations is supported by HW, MACB_CAPS_PCS indicate
> whether PCS is included in the design (needed for SGMII and 10G operation), MACB_CAPS_HIGH_SPEED
> indicate if design supports 10G operation.
> 
> I believe this should be
> 
>> +      if (macb_is_gem(bp) &&
>> +          (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
>> +              have_1g = true;
>> +              if (bp->caps & MACB_CAPS_PCS)
>> +                      have_sgmii = true;
>> +              if (bp->caps & MACB_CAPS_HIGH_SPEED)
>> +                      have_10g = true;


Regards,
   Nicolas
diff mbox series

Patch

diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index 309371abfe23..cb436f758bfa 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -513,29 +513,47 @@  static void macb_validate(struct phylink_config *config,
 	struct net_device *ndev = to_net_dev(config->dev);
 	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
 	struct macb *bp = netdev_priv(ndev);
+	bool have_1g, have_sgmii, have_10g;
 
-	/* We only support MII, RMII, GMII, RGMII & SGMII. */
-	if (state->interface != PHY_INTERFACE_MODE_NA &&
-	    state->interface != PHY_INTERFACE_MODE_MII &&
-	    state->interface != PHY_INTERFACE_MODE_RMII &&
-	    state->interface != PHY_INTERFACE_MODE_GMII &&
-	    state->interface != PHY_INTERFACE_MODE_SGMII &&
-	    state->interface != PHY_INTERFACE_MODE_10GBASER &&
-	    !phy_interface_mode_is_rgmii(state->interface)) {
+	/* Determine what modes are supported */
+	if (!macb_is_gem(bp) ||
+	    (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE)) {
+		have_1g = true;
+		if (bp->caps & MACB_CAPS_PCS)
+			have_sgmii = true;
+		if (bp->caps & MACB_CAPS_HIGH_SPEED)
+			have_10g = true;
+	}
+
+	/* Eliminate unsupported modes */
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_NA:
+	case PHY_INTERFACE_MODE_MII:
+	case PHY_INTERFACE_MODE_RMII:
+		break;
+
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		if (have_1g)
+			break;
 		linkmode_zero(supported);
 		return;
-	}
 
-	if (!macb_is_gem(bp) &&
-	    (state->interface == PHY_INTERFACE_MODE_GMII ||
-	     phy_interface_mode_is_rgmii(state->interface))) {
+	case PHY_INTERFACE_MODE_SGMII:
+		if (have_sgmii)
+			break;
 		linkmode_zero(supported);
 		return;
-	}
 
-	if (state->interface == PHY_INTERFACE_MODE_10GBASER &&
-	    !(bp->caps & MACB_CAPS_HIGH_SPEED &&
-	      bp->caps & MACB_CAPS_PCS)) {
+	case PHY_INTERFACE_MODE_10GBASER:
+		if (have_10g)
+			break;
+		fallthrough;
+
+	default:
 		linkmode_zero(supported);
 		return;
 	}
@@ -544,32 +562,48 @@  static void macb_validate(struct phylink_config *config,
 	phylink_set(mask, Autoneg);
 	phylink_set(mask, Asym_Pause);
 
-	if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE &&
-	    (state->interface == PHY_INTERFACE_MODE_NA ||
-	     state->interface == PHY_INTERFACE_MODE_10GBASER)) {
-		phylink_set_10g_modes(mask);
-		phylink_set(mask, 10000baseKR_Full);
+	/* And set the appropriate mask */
+	switch (state->interface) {
+	case PHY_INTERFACE_MODE_NA:
+	case PHY_INTERFACE_MODE_10GBASER:
+		if (have_10g) {
+			phylink_set_10g_modes(mask);
+			phylink_set(mask, 10000baseKR_Full);
+		}
 		if (state->interface != PHY_INTERFACE_MODE_NA)
-			goto out;
-	}
+			break;
+		fallthrough;
+
+	/* FIXME: Do we actually support 10/100 for SGMII? Half duplex? */
+	case PHY_INTERFACE_MODE_SGMII:
+		if (!have_sgmii && state->interface != PHY_INTERFACE_MODE_NA)
+			break;
+		fallthrough;
 
-	phylink_set(mask, 10baseT_Half);
-	phylink_set(mask, 10baseT_Full);
-	phylink_set(mask, 100baseT_Half);
-	phylink_set(mask, 100baseT_Full);
+	case PHY_INTERFACE_MODE_GMII:
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		if (have_1g) {
+			phylink_set(mask, 1000baseT_Full);
+			phylink_set(mask, 1000baseX_Full);
 
-	if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE &&
-	    (state->interface == PHY_INTERFACE_MODE_NA ||
-	     state->interface == PHY_INTERFACE_MODE_GMII ||
-	     state->interface == PHY_INTERFACE_MODE_SGMII ||
-	     phy_interface_mode_is_rgmii(state->interface))) {
-		phylink_set(mask, 1000baseT_Full);
-		phylink_set(mask, 1000baseX_Full);
+			if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
+				phylink_set(mask, 1000baseT_Half);
+		} else if (state->interface != PHY_INTERFACE_MODE_NA) {
+			break;
+		}
+		fallthrough;
 
-		if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF))
-			phylink_set(mask, 1000baseT_Half);
+	default:
+		phylink_set(mask, 10baseT_Half);
+		phylink_set(mask, 10baseT_Full);
+		phylink_set(mask, 100baseT_Half);
+		phylink_set(mask, 100baseT_Full);
+		break;
 	}
-out:
+
 	linkmode_and(supported, supported, mask);
 	linkmode_and(state->advertising, state->advertising, mask);
 }