From: Sean Anderson <hidden> Date: 2021-10-04 19:15:52
This series adds experimental support for Xilinx PCS devices. It is
experimental because while I believe I have the Linux side mostly
sorted, I have yet to achieve any data transfer. Adding support for this
device has required some plumbing work related to PCSs in general, and I
would appreciate feedback in that area. In general, I have not tested
these changes outside of my particular setup, though I do have the
ability to test the macb changes using the internal PCS in the future.
Sean Anderson (16):
dt-bindings: net: Add pcs property
dt-bindings: net: Add binding for Xilinx PCS
net: sfp: Fix typo in state machine debug string
net: phylink: Move phylink_set_pcs before phylink_create
net: phylink: Automatically attach PCS devices
net: phylink: Add function for optionally adding a PCS
net: phylink: Add helpers for c22 registers without MDIO
net: macb: Clean up macb_validate
net: macb: Move most of mac_prepare to mac_config
net: macb: Move PCS settings to PCS callbacks
net: macb: Support restarting PCS autonegotiation
net: macb: Support external PCSs
net: phy: Export get_phy_c22_id
net: mdio: Add helper functions for accessing MDIO devices
net: pcs: Add Xilinx PCS driver
net: sfp: Add quirk to ignore PHYs
.../bindings/net/ethernet-controller.yaml | 5 +
.../devicetree/bindings/net/xilinx,pcs.yaml | 83 ++++
MAINTAINERS | 6 +
drivers/net/ethernet/cadence/macb_main.c | 375 +++++++++++-------
drivers/net/pcs/Kconfig | 19 +
drivers/net/pcs/Makefile | 1 +
drivers/net/pcs/pcs-xilinx.c | 326 +++++++++++++++
drivers/net/phy/phy_device.c | 3 +-
drivers/net/phy/phylink.c | 335 ++++++++++++----
drivers/net/phy/sfp-bus.c | 12 +-
drivers/net/phy/sfp.c | 5 +-
include/linux/mdio.h | 17 +
include/linux/phy.h | 1 +
include/linux/phylink.h | 17 +-
14 files changed, 963 insertions(+), 242 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/xilinx,pcs.yaml
create mode 100644 drivers/net/pcs/pcs-xilinx.c
--
2.25.1
From: Sean Anderson <hidden> Date: 2021-10-04 19:15:58
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
Signed-off-by: Sean Anderson <redacted>
---
.../devicetree/bindings/net/ethernet-controller.yaml | 5 +++++
1 file changed, 5 insertions(+)
@@ -116,6 +116,11 @@ properties:$ref:"#/properties/phy-handle"deprecated:true+pcs:+$ref:/schemas/types.yaml#definitions/phandle+description:+Specifies a reference to a node representing a PCS device.+rx-fifo-depth:$ref:/schemas/types.yaml#/definitions/uint32description:
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 09:39:46
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
We actually already have LX2160A platforms using "pcs-handle", (see
Documentation/devicetree/bindings/net/fsl,qoriq-mc-dpmac.yaml) so we're
in danger of ending up with multiple property names describing the same
thing.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-05 16:19:03
On 10/5/21 5:39 AM, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
quoted
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
We actually already have LX2160A platforms using "pcs-handle", (see
Documentation/devicetree/bindings/net/fsl,qoriq-mc-dpmac.yaml) so we're
in danger of ending up with multiple property names describing the same
thing.
From: Rob Herring <robh@kernel.org> Date: 2021-10-12 13:16:49
On Tue, Oct 05, 2021 at 10:39:36AM +0100, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
quoted
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
On 1G and up ethernet, we have 2 PHYs. There's the external (typically)
ethernet PHY which is what the above properties are for. Then there's
the on-chip serdes PHY similar to SATA, PCIe, etc. which includes the
PCS part. For this part, we should use the generic PHY binding. I think
we already have bindings doing that.
Rob
From: Sean Anderson <hidden> Date: 2021-10-12 16:18:47
Hi Rob,
On 10/12/21 9:16 AM, Rob Herring wrote:
On Tue, Oct 05, 2021 at 10:39:36AM +0100, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
quoted
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
On 1G and up ethernet, we have 2 PHYs. There's the external (typically)
ethernet PHY which is what the above properties are for. Then there's
the on-chip serdes PHY similar to SATA, PCIe, etc. which includes the
PCS part. For this part, we should use the generic PHY binding. I think
we already have bindings doing that.
In the 802.3 models, there are several components which convert between
the MII (from the MAC) and the MDI (the physical protocol on the wire).
These are the Physical Coding Sublayer (PCS), Physical Medium Attachment
(PMA) sublayer, and Physical Medium Dependent (PMD) sublayer. The PMD
converts between the physical layer signaling and the on-chip (or
on-board) signalling. The PMA performs clock recovery and converts the
serial data from the PMD into parallel data for the PCS. The PCS handles
autonegotiation, CSMA/CD, and conversion to the apripriate MII for
communicating with the MAC.
In the above model, generic serdes devices generally correspond to the
PMA/PMD sublayers. The PCS is generally a separate device, both
on the hardware and software level. It provides an ethernet-specific
layer on top of the more generic underlying encoding. For this reason,
the PCS should be modeled as its own device, which may then contain a
reference to the appropriate serdes.
The above model describes physical layers such as 1000BASE-X or
10GBASE-X where the PCS/PMA/PMD is the last layer before the physical
medium. In that case, the PCS could be modeled as a traditional PHY.
However, when using (e.g.) SGMII, it is common for the "MDI" to be
SGMII, and for another PHY to convert to 1000BASE-T. To model this
correctly, the PCS/PMA/PMD layer must be considered independently from
the PHY which will ultimately convert the MII to the MDI.
--Sean
From: Rob Herring <robh@kernel.org> Date: 2021-10-12 16:44:40
On Tue, Oct 12, 2021 at 11:18 AM Sean Anderson [off-list ref] wrote:
Hi Rob,
On 10/12/21 9:16 AM, Rob Herring wrote:
quoted
On Tue, Oct 05, 2021 at 10:39:36AM +0100, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
quoted
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
On 1G and up ethernet, we have 2 PHYs. There's the external (typically)
ethernet PHY which is what the above properties are for. Then there's
the on-chip serdes PHY similar to SATA, PCIe, etc. which includes the
PCS part. For this part, we should use the generic PHY binding. I think
we already have bindings doing that.
In the 802.3 models, there are several components which convert between
the MII (from the MAC) and the MDI (the physical protocol on the wire).
These are the Physical Coding Sublayer (PCS), Physical Medium Attachment
(PMA) sublayer, and Physical Medium Dependent (PMD) sublayer. The PMD
converts between the physical layer signaling and the on-chip (or
on-board) signalling. The PMA performs clock recovery and converts the
serial data from the PMD into parallel data for the PCS. The PCS handles
autonegotiation, CSMA/CD, and conversion to the apripriate MII for
communicating with the MAC.
In the above model, generic serdes devices generally correspond to the
PMA/PMD sublayers. The PCS is generally a separate device, both
on the hardware and software level. It provides an ethernet-specific
layer on top of the more generic underlying encoding. For this reason,
the PCS should be modeled as its own device, which may then contain a
reference to the appropriate serdes.
On the h/w I've worked on, PCS was an additional block instantiated
within the PHY, so it looked like one block to s/w. But that's been
almost 10 years ago now.
If you do have 2 h/w blocks, one option is doing something like this:
phys = <&pcs_phy>, <&sgmii_phy>;
I'm okay with 'pcs-handle', but just want to make sure we're not using
it where 'phys' would work.
The above model describes physical layers such as 1000BASE-X or
10GBASE-X where the PCS/PMA/PMD is the last layer before the physical
medium. In that case, the PCS could be modeled as a traditional PHY.
However, when using (e.g.) SGMII, it is common for the "MDI" to be
SGMII, and for another PHY to convert to 1000BASE-T. To model this
correctly, the PCS/PMA/PMD layer must be considered independently from
the PHY which will ultimately convert the MII to the MDI.
From: Sean Anderson <hidden> Date: 2021-10-12 17:03:14
On 10/12/21 12:44 PM, Rob Herring wrote:
On Tue, Oct 12, 2021 at 11:18 AM Sean Anderson [off-list ref] wrote:
quoted
Hi Rob,
On 10/12/21 9:16 AM, Rob Herring wrote:
quoted
On Tue, Oct 05, 2021 at 10:39:36AM +0100, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:12PM -0400, Sean Anderson wrote:
quoted
Add a property for associating PCS devices with ethernet controllers.
Because PCS has no generic analogue like PHY, I have left off the
-handle suffix.
For PHYs, we used to have phy and phy-device as property names, but the
modern name is "phy-handle". I think we should do the same here, so I
would suggest using "pcs-handle".
On 1G and up ethernet, we have 2 PHYs. There's the external (typically)
ethernet PHY which is what the above properties are for. Then there's
the on-chip serdes PHY similar to SATA, PCIe, etc. which includes the
PCS part. For this part, we should use the generic PHY binding. I think
we already have bindings doing that.
In the 802.3 models, there are several components which convert between
the MII (from the MAC) and the MDI (the physical protocol on the wire).
These are the Physical Coding Sublayer (PCS), Physical Medium Attachment
(PMA) sublayer, and Physical Medium Dependent (PMD) sublayer. The PMD
converts between the physical layer signaling and the on-chip (or
on-board) signalling. The PMA performs clock recovery and converts the
serial data from the PMD into parallel data for the PCS. The PCS handles
autonegotiation, CSMA/CD, and conversion to the apripriate MII for
communicating with the MAC.
In the above model, generic serdes devices generally correspond to the
PMA/PMD sublayers. The PCS is generally a separate device, both
on the hardware and software level. It provides an ethernet-specific
layer on top of the more generic underlying encoding. For this reason,
the PCS should be modeled as its own device, which may then contain a
reference to the appropriate serdes.
On the h/w I've worked on, PCS was an additional block instantiated
within the PHY, so it looked like one block to s/w. But that's been
almost 10 years ago now.
Well, perhaps the line is not as clear as I made it seem above. The
PCS/PMA/PMD separation is mostly a logical one, so different platforms
divide up the work differently. In addition, the naming may not align
with ethernet's idea of what a PCS or PMA is. For example, on the
ZynqMP, the serdes (GTH) contains its own PCS and PMD (as shown on the
datasheet). However, these blocks both correspond to the PMA layer from
ethernet's POV. The ethernet PCS is a block controlled via registers
within the MAC's address space.
If you do have 2 h/w blocks, one option is doing something like this:
phys = <&pcs_phy>, <&sgmii_phy>;
Generally, PCSs don't export the same interface as PHYs (see e.g.
drivers/net/pcs and include/linux/phylink.h). IMO it would be an abuse
of the phys property to use it for a PCS as well.
I'm okay with 'pcs-handle', but just want to make sure we're not using
it where 'phys' would work.
quoted
The above model describes physical layers such as 1000BASE-X or
10GBASE-X where the PCS/PMA/PMD is the last layer before the physical
medium. In that case, the PCS could be modeled as a traditional PHY.
However, when using (e.g.) SGMII, it is common for the "MDI" to be
SGMII, and for another PHY to convert to 1000BASE-T. To model this
correctly, the PCS/PMA/PMD layer must be considered independently from
the PHY which will ultimately convert the MII to the MDI.
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:02
This adds a binding for the Xilinx 1G/2.5G Ethernet PCS/PMA or SGMII
LogiCORE IP. This device is a soft device typically used to adapt between
GMII and SGMII or 1000BASE-X (in combination with a suitable SERDES). The
standard property is roughly analogous to the interface property of
ethernet controllers, except that it has an additional value used to
indicate that dynamic switching is supported. Note that switching is
supported only between SGMII and 1000BASE-X, and only if the appropriate
parameter is set when the device is synthesized. The property name was
chosen to align with the terminology in the datasheet. I also considered
"mdi", but that is a bit of a misnomer in the case of SGMII.
Signed-off-by: Sean Anderson <redacted>
---
.../devicetree/bindings/net/xilinx,pcs.yaml | 83 +++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/xilinx,pcs.yaml
@@ -0,0 +1,83 @@+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)+%YAML1.2+---+$id:http://devicetree.org/schemas/net/xilinx,pcs.yaml#+$schema:http://devicetree.org/meta-schemas/core.yaml#++title:Xilinx 1G/2.5G Ethernet PCS/PMA or SGMII LogiCORE IP++maintainers:+-Sean Anderson <sean.anderson@seco.com>++description:+This is a soft device which converts between GMII and SGMII, 2.5G SGMII,+1000BASE-X, or 2500BASE-X. It may have an attached SERDES, or may talk+directly to LVDS.++allOf:+-$ref:"ethernet-controller.yaml#"++properties:+compatible:+contains:+const:+-xilinx,pcs-16.2++reg:+maxItems:1++clocks:+maxItems:1+items:+-description:The reference clock for the PMD, which is typically a+SERDES but may be a direct interface to LVDS I/Os.+Depending on your setup, this may be the gtrefclk, refclk,+or clk125m signal.++clock-names:+const:refclk++resets:+maxItems:1++reset-names:+const:pcs++standard:+description:+The interface standard that the PCS supports. The sgmii/1000base-x+setting indicates that the PCS supports dynamically switching between+SGMII and 1000BASE-X.+enum:+-sgmii+-1000base-x+-sgmii/1000base-x+-2500base-x++required:+-compatible+-reg+-clocks+-clock-names+-resets+-reset-names+-standard++additionalProperties:false++examples:+-|+mdio {+#address-cells = <1>;+#size-cells = <0>;++pcs0:ethernet-pcs@0 {+compatible = "xlnx,pcs-16.2";+reg = <0>;+clocks = <&si570>;+clock-names = "refclk";+resets = <&pcs_reset 1>;+reset-names = "pcs";+standard = "sgmii/1000base-x";+};+};
From: Rob Herring <robh@kernel.org> Date: 2021-10-05 12:27:07
On Mon, 04 Oct 2021 15:15:13 -0400, Sean Anderson wrote:
This adds a binding for the Xilinx 1G/2.5G Ethernet PCS/PMA or SGMII
LogiCORE IP. This device is a soft device typically used to adapt between
GMII and SGMII or 1000BASE-X (in combination with a suitable SERDES). The
standard property is roughly analogous to the interface property of
ethernet controllers, except that it has an additional value used to
indicate that dynamic switching is supported. Note that switching is
supported only between SGMII and 1000BASE-X, and only if the appropriate
parameter is set when the device is synthesized. The property name was
chosen to align with the terminology in the datasheet. I also considered
"mdi", but that is a bit of a misnomer in the case of SGMII.
Signed-off-by: Sean Anderson <redacted>
---
.../devicetree/bindings/net/xilinx,pcs.yaml | 83 +++++++++++++++++++
1 file changed, 83 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/xilinx,pcs.yaml
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/xilinx,pcs.yaml: properties:compatible:contains:const: ['xilinx,pcs-16.2'] is not of type 'string'
from schema $id: http://devicetree.org/meta-schemas/string-array.yaml#
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/xilinx,pcs.yaml: properties:clocks: {'maxItems': 1, 'items': [{'description': 'The reference clock for the PMD, which is typically a SERDES but may be a direct interface to LVDS I/Os. Depending on your setup, this may be the gtrefclk, refclk, or clk125m signal.'}]} should not be valid under {'required': ['maxItems']}
hint: "maxItems" is not needed with an "items" list
from schema $id: http://devicetree.org/meta-schemas/items.yaml#
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/xilinx,pcs.yaml: properties:clocks: 'oneOf' conditional failed, one must be fixed:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/xilinx,pcs.yaml: properties:clocks: 'anyOf' conditional failed, one must be fixed:
'items' is not one of ['maxItems', 'description', 'deprecated']
hint: Only "maxItems" is required for a single entry if there are no constraints defined for the values.
'maxItems' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref']
'items' is not one of ['description', 'deprecated', 'const', 'enum', 'minimum', 'maximum', 'multipleOf', 'default', '$ref']
1 is less than the minimum of 2
hint: Arrays must be described with a combination of minItems/maxItems/items
hint: cell array properties must define how many entries and what the entries are when there is more than one entry.
from schema $id: http://devicetree.org/meta-schemas/clocks.yaml#
'maxItems' is not one of ['type', 'description', 'dependencies', 'properties', 'patternProperties', 'additionalProperties', 'unevaluatedProperties', 'deprecated', 'required', 'allOf', 'anyOf', 'oneOf', '$ref']
'items' is not one of ['type', 'description', 'dependencies', 'properties', 'patternProperties', 'additionalProperties', 'unevaluatedProperties', 'deprecated', 'required', 'allOf', 'anyOf', 'oneOf', '$ref']
'type' is a required property
hint: DT nodes ("object" type in schemas) can only use a subset of json-schema keywords
from schema $id: http://devicetree.org/meta-schemas/clocks.yaml#
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/xilinx,pcs.yaml: ignoring, error in schema: properties: compatible: contains: const
warning: no schema found in file: ./Documentation/devicetree/bindings/net/xilinx,pcs.yaml
Documentation/devicetree/bindings/net/xilinx,pcs.example.dt.yaml:0:0: /example-0/mdio/ethernet-pcs@0: failed to match any schema with compatible: ['xlnx,pcs-16.2']
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/1536331
This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit.
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:07
The string should be "tx_disable" to match the state enum.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/sfp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-10-04 21:31:29
On Mon, Oct 04, 2021 at 03:15:14PM -0400, Sean Anderson wrote:
quoted hunk
The string should be "tx_disable" to match the state enum.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/sfp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Hi Sean
This is a bug fix. Please separate it out and base it on net, not
net-next.
Fixes: 4005a7cb4f55 ("net: phy: sftp: print debug message with text, not numbers")
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:23
This adds support for automatically attaching PCS devices when creating
a phylink. To do this, drivers must first register with
phylink_register_pcs. After that, new phylinks will attach the PCS
device specified by the "pcs" property.
At the moment there is no support for specifying the interface used to
talk to the PCS. The MAC driver is expected to know how to talk to the
PCS. This is not a change, but it is perhaps an area for improvement.
I believe this is mostly correct with regard to registering/
unregistering. However I am not too familiar with the guts of Linux's
device subsystem. It is possible (likely, even) that the current system
is insufficient to prevent removing PCS devices which are still in-use.
I would really appreciate any feedback, or suggestions of subsystems to
use as reference. In particular: do I need to manually create device
links? Should I instead add an entry to of_supplier_bindings? Do I need
a call to try_module_get?
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/phylink.c | 115 ++++++++++++++++++++++++++++++++++++--
include/linux/phylink.h | 11 +++-
2 files changed, 120 insertions(+), 6 deletions(-)
@@ -795,6 +795,42 @@ static int phylink_register_sfp(struct phylink *pl,returnret;}+staticLIST_HEAD(pcs_devices);+staticDEFINE_MUTEX(pcs_mutex);++/**+*phylink_register_pcs()-registeranewPCS+*@pcs:thePCStoregister+*+*RegistersanewPCSwhichcanbeautomaticallyattachedtoaphylink.+*+*Return:0onsuccess,or-errnoonerror+*/+intphylink_register_pcs(structphylink_pcs*pcs)+{+if(!pcs->dev||!pcs->ops)+return-EINVAL;++INIT_LIST_HEAD(&pcs->list);+mutex_lock(&pcs_mutex);+list_add(&pcs->list,&pcs_devices);+mutex_unlock(&pcs_mutex);+return0;+}+EXPORT_SYMBOL_GPL(phylink_register_pcs);++/**+*phylink_unregister_pcs()-unregisteraPCS+*@pcs:aPCSpreviouslyregisteredwithphylink_register_pcs()+*/+voidphylink_unregister_pcs(structphylink_pcs*pcs)+{+mutex_lock(&pcs_mutex);+list_del(&pcs->list);+mutex_unlock(&pcs_mutex);+}+EXPORT_SYMBOL_GPL(phylink_unregister_pcs);+/***phylink_set_pcs()-setthecurrentPCSforphylinktouse*@pl:apointertoa&structphylinkreturnedfromphylink_create()
@@ -808,14 +844,72 @@ static int phylink_register_sfp(struct phylink *pl,*callbackifaPCSispresent(denotinganewersetup)soremovingaPCS*isnotsupported,andifaPCSisgoingtobeused,itmustberegistered*bycallingphylink_set_pcs()atthelatestinthefirstmac_config()call.+*+*Context:maysleep.+*Return:0onsuccessor-errnoonfailure.*/-voidphylink_set_pcs(structphylink*pl,structphylink_pcs*pcs)+intphylink_set_pcs(structphylink*pl,structphylink_pcs*pcs){+if(pl->pcs&&pl->pcs->dev)+device_link_remove(pl->dev,pl->pcs->dev);++if(pcs->dev){+structdevice_link*dl=+device_link_add(pl->dev,pcs->dev,0);++if(IS_ERR(dl)){+dev_err(pl->dev,+"failed to create device link to %s\n",+dev_name(pcs->dev));+returnPTR_ERR(dl);+}+}+pl->pcs=pcs;pl->pcs_ops=pcs->ops;+return0;}EXPORT_SYMBOL_GPL(phylink_set_pcs);+staticstructphylink_pcs*phylink_find_pcs(structfwnode_handle*fwnode)+{+structphylink_pcs*pcs;++mutex_lock(&pcs_mutex);+list_for_each_entry(pcs,&pcs_devices,list){+if(pcs->dev&&pcs->dev->fwnode==fwnode){+mutex_unlock(&pcs_mutex);+returnpcs;+}+}+mutex_unlock(&pcs_mutex);++returnNULL;+}++staticintphylink_attach_pcs(structphylink*pl,structfwnode_handle*fwnode)+{+intret;+structphylink_pcs*pcs;+structfwnode_reference_argsref;++ret=fwnode_property_get_reference_args(fwnode,"pcs",NULL,+0,0,&ref);+if(ret==-ENOENT)+return0;+elseif(ret)+returnret;++pcs=phylink_find_pcs(ref.fwnode);+if(pcs)+ret=phylink_set_pcs(pl,pcs);+else+ret=-EPROBE_DEFER;++fwnode_handle_put(ref.fwnode);+returnret;+}+/***phylink_create()-createaphylinkinstance*@config:apointertothetarget&structphylink_config
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 09:48:18
On Mon, Oct 04, 2021 at 03:15:16PM -0400, Sean Anderson wrote:
This adds support for automatically attaching PCS devices when creating
a phylink. To do this, drivers must first register with
phylink_register_pcs. After that, new phylinks will attach the PCS
device specified by the "pcs" property.
At the moment there is no support for specifying the interface used to
talk to the PCS. The MAC driver is expected to know how to talk to the
PCS. This is not a change, but it is perhaps an area for improvement.
I believe this is mostly correct with regard to registering/
unregistering. However I am not too familiar with the guts of Linux's
device subsystem. It is possible (likely, even) that the current system
is insufficient to prevent removing PCS devices which are still in-use.
I would really appreciate any feedback, or suggestions of subsystems to
use as reference. In particular: do I need to manually create device
links? Should I instead add an entry to of_supplier_bindings? Do I need
a call to try_module_get?
I think this is an area that needs to be thought about carefully.
Things are not trivial here.
The first mistake I see below is the use of device links. pl->dev is
the "struct device" embedded within "struct net_device". This doesn't
have a driver associated with it, and so using device links is likely
ineffectual.
Even with the right device, I think careful thought is needed - we have
network drivers where one "struct device" contains multiple network
interfaces. Should the removal of a PCS from one network interface take
out all of them?
Alternatively, could we instead use phylink to "unplug" the PCS and
mark the link down - would that be a better approach than trying to
use device links?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-05 16:43:05
On 10/5/21 5:48 AM, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:16PM -0400, Sean Anderson wrote:
quoted
This adds support for automatically attaching PCS devices when creating
a phylink. To do this, drivers must first register with
phylink_register_pcs. After that, new phylinks will attach the PCS
device specified by the "pcs" property.
At the moment there is no support for specifying the interface used to
talk to the PCS. The MAC driver is expected to know how to talk to the
PCS. This is not a change, but it is perhaps an area for improvement.
I believe this is mostly correct with regard to registering/
unregistering. However I am not too familiar with the guts of Linux's
device subsystem. It is possible (likely, even) that the current system
is insufficient to prevent removing PCS devices which are still in-use.
I would really appreciate any feedback, or suggestions of subsystems to
use as reference. In particular: do I need to manually create device
links? Should I instead add an entry to of_supplier_bindings? Do I need
a call to try_module_get?
I think this is an area that needs to be thought about carefully.
Things are not trivial here.
The first mistake I see below is the use of device links. pl->dev is
the "struct device" embedded within "struct net_device". This doesn't
have a driver associated with it, and so using device links is likely
ineffectual.
So what can the device in net_device be used for?
Even with the right device, I think careful thought is needed - we have
network drivers where one "struct device" contains multiple network
interfaces. Should the removal of a PCS from one network interface take
out all of them?
Well, it's more of the other way around. We need to prevent removing the
PCS while it is still in-use.
Alternatively, could we instead use phylink to "unplug" the PCS and
mark the link down - would that be a better approach than trying to
use device links?
So here, I think the logic should be: allow phylink to "unplug" the PCS
only when the link is down.
--Sean
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-07 10:23:48
On Tue, Oct 05, 2021 at 12:42:53PM -0400, Sean Anderson wrote:
On 10/5/21 5:48 AM, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:16PM -0400, Sean Anderson wrote:
quoted
This adds support for automatically attaching PCS devices when creating
a phylink. To do this, drivers must first register with
phylink_register_pcs. After that, new phylinks will attach the PCS
device specified by the "pcs" property.
At the moment there is no support for specifying the interface used to
talk to the PCS. The MAC driver is expected to know how to talk to the
PCS. This is not a change, but it is perhaps an area for improvement.
I believe this is mostly correct with regard to registering/
unregistering. However I am not too familiar with the guts of Linux's
device subsystem. It is possible (likely, even) that the current system
is insufficient to prevent removing PCS devices which are still in-use.
I would really appreciate any feedback, or suggestions of subsystems to
use as reference. In particular: do I need to manually create device
links? Should I instead add an entry to of_supplier_bindings? Do I need
a call to try_module_get?
I think this is an area that needs to be thought about carefully.
Things are not trivial here.
The first mistake I see below is the use of device links. pl->dev is
the "struct device" embedded within "struct net_device". This doesn't
have a driver associated with it, and so using device links is likely
ineffectual.
So what can the device in net_device be used for?
That is used for the class device that is commonly found in
/sys/devices/$pathtothedevice/net/$interfacename
quoted
Even with the right device, I think careful thought is needed - we have
network drivers where one "struct device" contains multiple network
interfaces. Should the removal of a PCS from one network interface take
out all of them?
Well, it's more of the other way around. We need to prevent removing the
PCS while it is still in-use.
devlinks don't do that - if the "producer" device goes away, they force
the "consumer" device to be unbound.
As I mention above, the "consumer" device, which would be the device
providing the network interface(s) could have more than one interface
and unbinding it could have drastic consequences for the platform.
quoted
Alternatively, could we instead use phylink to "unplug" the PCS and
mark the link down - would that be a better approach than trying to
use device links?
So here, I think the logic should be: allow phylink to "unplug" the PCS
only when the link is down.
When a device is unbound from its driver, the driver has no say in
whether that goes ahead or not. Think about it as grabbing that USB
stick plugged into your computer and you yanking it out. None of the
software gets a look in to say "don't do that".
phylink (or any other subsystem) does not have the power to say
"I don't want XYZ to be removed".
Yes, it's harder to do that with PCS, but my point is that if one asks
the driver model to unbind the PCS driver from the PCS device, then
the driver model will do that whether the PCS driver wants to allow it
at that moment or not. It isn't something the PCS driver can prevent.
One can tell the driver model not to expose the bind/unbind attributes
for the driver, but that doesn't stop the unbind happening should the
struct device actually go away.
So, IMHO, it's better to design assuming that components will go away
at an inconvenient time and deal with it gracefully.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-08 00:14:53
On 10/7/21 6:23 AM, Russell King (Oracle) wrote:
On Tue, Oct 05, 2021 at 12:42:53PM -0400, Sean Anderson wrote:
quoted
On 10/5/21 5:48 AM, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:16PM -0400, Sean Anderson wrote:
quoted
This adds support for automatically attaching PCS devices when creating
a phylink. To do this, drivers must first register with
phylink_register_pcs. After that, new phylinks will attach the PCS
device specified by the "pcs" property.
At the moment there is no support for specifying the interface used to
talk to the PCS. The MAC driver is expected to know how to talk to the
PCS. This is not a change, but it is perhaps an area for improvement.
I believe this is mostly correct with regard to registering/
unregistering. However I am not too familiar with the guts of Linux's
device subsystem. It is possible (likely, even) that the current system
is insufficient to prevent removing PCS devices which are still in-use.
I would really appreciate any feedback, or suggestions of subsystems to
use as reference. In particular: do I need to manually create device
links? Should I instead add an entry to of_supplier_bindings? Do I need
a call to try_module_get?
I think this is an area that needs to be thought about carefully.
Things are not trivial here.
The first mistake I see below is the use of device links. pl->dev is
the "struct device" embedded within "struct net_device". This doesn't
have a driver associated with it, and so using device links is likely
ineffectual.
Ok, so the 'real' device is actually the parent of pl->netdev->dev?
quoted
So what can the device in net_device be used for?
That is used for the class device that is commonly found in
/sys/devices/$pathtothedevice/net/$interfacename
By the way, why don't we set pl->dev = config->dev->parent in
phylink_create() when config->type == PHYLINK_NETDEV?
quoted
quoted
Even with the right device, I think careful thought is needed - we have
network drivers where one "struct device" contains multiple network
interfaces. Should the removal of a PCS from one network interface take
out all of them?
Well, it's more of the other way around. We need to prevent removing the
PCS while it is still in-use.
devlinks don't do that - if the "producer" device goes away, they force
the "consumer" device to be unbound.
Ah, I didn't realize that was the relationship being modeled.
As I mention above, the "consumer" device, which would be the device
providing the network interface(s) could have more than one interface
and unbinding it could have drastic consequences for the platform.
Well, then don't unbind the PCS ;)
After reviewing several other subsystems, I think the correct way to
approach this is to add an entry to of_supplier_bindings, which will
help out with ordering, and get the module when looking up the PCS. That
is, something like
int phylink_get_pcs(fwnode, struct phylink_pcs **pcs)
{
int ret;
struct fwnode_reference_args ref;
ret = fwnode_property_get_reference_args(fwnode, "pcs-handle", NULL,
0, 0, &ref);
if (ret)
return ret;
*pcs = phylink_find_pcs(ref.fwnode);
fwnode_handle_put(ref.fwnode);
if (!*pcs)
return -EPROBE_DEFER;
if (!try_module_get(*pcs->owner))
return -EBUSY;
return 0;
}
phylink_put_pcs(pcs)
{
module_put(pcs->owner);
}
and keep phylink_set as-is (the above should be considered along with my comments on patch 10).
Realistically, the only time a PCS is optional is if there isn't a PCS
reference in the device tree.
quoted
quoted
Alternatively, could we instead use phylink to "unplug" the PCS and
mark the link down - would that be a better approach than trying to
use device links?
So here, I think the logic should be: allow phylink to "unplug" the PCS
only when the link is down.
When a device is unbound from its driver, the driver has no say in
whether that goes ahead or not. Think about it as grabbing that USB
stick plugged into your computer and you yanking it out. None of the
software gets a look in to say "don't do that".
I suspect the vast majority of PCSs will be DEVICE_FIXED.
phylink (or any other subsystem) does not have the power to say
"I don't want XYZ to be removed".
However, we do have the power to say "I don't want XYZ's module to be
removed", which should cover most of the situations where a device is
removed after boot.
Yes, it's harder to do that with PCS, but my point is that if one asks
the driver model to unbind the PCS driver from the PCS device, then
the driver model will do that whether the PCS driver wants to allow it
at that moment or not. It isn't something the PCS driver can prevent.
One can tell the driver model not to expose the bind/unbind attributes
for the driver, but that doesn't stop the unbind happening should the
struct device actually go away.
So, IMHO, it's better to design assuming that components will go away
at an inconvenient time and deal with it gracefully.
See above, but I think it's better here to assume that components will
stick around and if they disappear at an inconvenient time then we
should just let the netdev be removed as well.
--Sean
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:23
This adds a function to set the PCS only if there is not one currently
set. The intention here is to allow MAC drivers to have a "default" PCS
(such as an internal one) which may be used when one has not been set
via the device tree. This allows for backwards compatibility for cases
where a PCS was automatically attached if necessary.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/phylink.c | 26 ++++++++++++++++++++++++++
include/linux/phylink.h | 1 +
2 files changed, 27 insertions(+)
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 09:51:43
On Mon, Oct 04, 2021 at 03:15:17PM -0400, Sean Anderson wrote:
This adds a function to set the PCS only if there is not one currently
set. The intention here is to allow MAC drivers to have a "default" PCS
(such as an internal one) which may be used when one has not been set
via the device tree. This allows for backwards compatibility for cases
where a PCS was automatically attached if necessary.
I'm not sure I entirely like this approach. Why can't the network
driver check for the pcs-handle property and avoid using its
"default" if present?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Andrew Lunn <andrew@lunn.ch> Date: 2021-10-05 13:43:17
On Tue, Oct 05, 2021 at 10:51:38AM +0100, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:17PM -0400, Sean Anderson wrote:
quoted
This adds a function to set the PCS only if there is not one currently
set. The intention here is to allow MAC drivers to have a "default" PCS
(such as an internal one) which may be used when one has not been set
via the device tree. This allows for backwards compatibility for cases
where a PCS was automatically attached if necessary.
I'm not sure I entirely like this approach. Why can't the network
driver check for the pcs-handle property and avoid using its
"default" if present?
And that would also be in line with
ethernet/freescale/dpaa2/dpaa2-mac.c: node = fwnode_find_reference(dpmac_node, "pcs-handle", 0);
We need a uniform meaning of pcs-handle. And dpaa2-mac.c has set the
precedent that the MAC uses it, not phylink. That can however be
changed, if it make sense, but both users should do the same.
Andrew
From: Sean Anderson <hidden> Date: 2021-10-05 16:17:50
On 10/5/21 9:43 AM, Andrew Lunn wrote:
On Tue, Oct 05, 2021 at 10:51:38AM +0100, Russell King (Oracle) wrote:
quoted
On Mon, Oct 04, 2021 at 03:15:17PM -0400, Sean Anderson wrote:
quoted
This adds a function to set the PCS only if there is not one currently
set. The intention here is to allow MAC drivers to have a "default" PCS
(such as an internal one) which may be used when one has not been set
via the device tree. This allows for backwards compatibility for cases
where a PCS was automatically attached if necessary.
I'm not sure I entirely like this approach. Why can't the network
driver check for the pcs-handle property and avoid using its
"default" if present?
And that would also be in line with
ethernet/freescale/dpaa2/dpaa2-mac.c: node = fwnode_find_reference(dpmac_node, "pcs-handle", 0);
We need a uniform meaning of pcs-handle. And dpaa2-mac.c has set the
precedent that the MAC uses it, not phylink. That can however be
changed, if it make sense, but both users should do the same.
The tricky bit here happens when drivers set the PCS in mac_prepare()
depending on the interface. So you have to remember during probe()
whether you are supposed to set the PCS for later. I would like to leave
more of this to phylink to ensure that the process is done in a uniform
way.
--Sean
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:31
Some devices expose memory-mapped c22-compliant PHYs. Because these
devices do not have an MDIO bus, we cannot use the existing helpers.
Refactor the existing helpers to allow supplying the values for c22
registers directly, instead of using MDIO to access them. Only get_state
and set_adversisement are converted, since they contain the most complex
logic.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/phylink.c | 154 ++++++++++++++++++++++----------------
include/linux/phylink.h | 5 ++
2 files changed, 96 insertions(+), 63 deletions(-)
@@ -2667,32 +2710,48 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,return;}-state->link=!!(bmsr&BMSR_LSTATUS);-state->an_complete=!!(bmsr&BMSR_ANEGCOMPLETE);-if(!state->link)-return;--switch(state->interface){-casePHY_INTERFACE_MODE_1000BASEX:-phylink_decode_c37_word(state,lpa,SPEED_1000);-break;--casePHY_INTERFACE_MODE_2500BASEX:-phylink_decode_c37_word(state,lpa,SPEED_2500);-break;--casePHY_INTERFACE_MODE_SGMII:-casePHY_INTERFACE_MODE_QSGMII:-phylink_decode_sgmii_word(state,lpa);-break;--default:-state->link=false;-break;-}+phylink_mii_c22_pcs_decode_state(state,bmsr,lpa);}EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state);+/**+*phylink_mii_c22_pcs_encode_advertisement()-configuretheclause37PCS+*advertisement+*@interface:thePHYinterfacemodebeingconfigured+*@advertising:theethtooladvertisementmask+*@adv:thevalueofthe%MII_ADVERTISEregister+*+*HelperforMACPCSsupportingthe802.3clause22registersetfor+*clause37negotiationand/orSGMIIcontrol.+*+*Encodetheclause37PCSadvertisementasspecifiedby@interfaceand+*@advertising.Callersshouldwrite@advifithasbeenmodified.+*+*Return:Thenewvaluefor@adv.+*/+u16phylink_mii_c22_pcs_encode_advertisement(phy_interface_tinterface,+constunsignedlong*advertising,+u16adv)+{+switch(interface){+casePHY_INTERFACE_MODE_1000BASEX:+casePHY_INTERFACE_MODE_2500BASEX:+adv=ADVERTISE_1000XFULL;+if(linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,+advertising))+adv|=ADVERTISE_1000XPAUSE;+if(linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,+advertising))+adv|=ADVERTISE_1000XPSE_ASYM;+returnadv;+casePHY_INTERFACE_MODE_SGMII:+return0x0001;+default:+/* Nothing to do for other modes */+returnadv;+}+}+/***phylink_mii_c22_pcs_set_advertisement()-configuretheclause37PCS*advertisement
@@ -2719,48 +2778,17 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,intval,ret;u16adv;-switch(interface){-casePHY_INTERFACE_MODE_1000BASEX:-casePHY_INTERFACE_MODE_2500BASEX:-adv=ADVERTISE_1000XFULL;-if(linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,-advertising))-adv|=ADVERTISE_1000XPAUSE;-if(linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,-advertising))-adv|=ADVERTISE_1000XPSE_ASYM;+val=mdiobus_read(bus,addr,MII_ADVERTISE);+if(val<0)+returnval;-val=mdiobus_read(bus,addr,MII_ADVERTISE);-if(val<0)-returnval;--if(val==adv)-return0;--ret=mdiobus_write(bus,addr,MII_ADVERTISE,adv);-if(ret<0)-returnret;--return1;--casePHY_INTERFACE_MODE_SGMII:-val=mdiobus_read(bus,addr,MII_ADVERTISE);-if(val<0)-returnval;--if(val==0x0001)-return0;--ret=mdiobus_write(bus,addr,MII_ADVERTISE,0x0001);-if(ret<0)-returnret;--return1;--default:-/* Nothing to do for other modes */+adv=phylink_mii_c22_pcs_encode_advertisement(interface,advertising,+adv);+if(adv==val)return0;-}++ret=mdiobus_write(bus,addr,MII_ADVERTISE,adv);+returnret<0?ret:1;}EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement);
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-22 12:33:41
On Mon, Oct 04, 2021 at 03:15:18PM -0400, Sean Anderson wrote:
Some devices expose memory-mapped c22-compliant PHYs. Because these
devices do not have an MDIO bus, we cannot use the existing helpers.
Refactor the existing helpers to allow supplying the values for c22
registers directly, instead of using MDIO to access them. Only get_state
and set_adversisement are converted, since they contain the most complex
logic.
I think this patch is useful on its own, there are certainly cases
where being able to hold the MII bus lock while reading the BMSR/LPA
registers would be advantageous. Please can you update the patch
against net-next and submit it?
Thanks.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:34
As the number of interfaces grows, the number of if statements grows
ever more unweildy. Clean everything up a bit by using a switch
statement. No functional change intended.
While we're on the subject, could someone clarify the relationship
between the various speed capabilities? What's the difference between
MACB_CAPS_GIGABIT_MODE_AVAILABLE, MACB_CAPS_HIGH_SPEED, MACB_CAPS_PCS,
and macb_is_gem()? Would there ever be a GEM without GIGABIT_MODE?
HIGH_SPEED without PCS? Why doesn't SGMII care if we're a gem (I think
this one is a bug, because it cares later on)?
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/ethernet/cadence/macb_main.c | 99 +++++++++++-------------
1 file changed, 45 insertions(+), 54 deletions(-)
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-04 23:04:30
On Mon, Oct 04, 2021 at 03:15:19PM -0400, Sean Anderson wrote:
As the number of interfaces grows, the number of if statements grows
ever more unweildy. Clean everything up a bit by using a switch
statement. No functional change intended.
Shouldn't this be != ?
Since PHY_INTERFACE_MODE_NA is supposed to return all capabilities.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-04 23:09:30
On 10/4/21 7:04 PM, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:19PM -0400, Sean Anderson wrote:
quoted
As the number of interfaces grows, the number of if statements grows
ever more unweildy. Clean everything up a bit by using a switch
statement. No functional change intended.
From: Nicolas Ferre <nicolas.ferre@microchip.com> Date: 2021-10-07 13:22:12
On 04/10/2021 at 21:15, Sean Anderson wrote:
While we're on the subject, could someone clarify the relationship
between the various speed capabilities? What's the difference between
MACB_CAPS_GIGABIT_MODE_AVAILABLE, MACB_CAPS_HIGH_SPEED, MACB_CAPS_PCS,
and macb_is_gem()? Would there ever be a GEM without GIGABIT_MODE?
Yes. GEM is a new revision of the IP that is capable of doing Gigabit
mode or not. sama7g5_emac_config is typically one of those doing only
10/100.
HIGH_SPEED without PCS? Why doesn't SGMII care if we're a gem (I think
this one is a bug, because it cares later on)?
MACB_CAPS_HIGH_SPEED and MACB_CAPS_PCS were added by
e4e143e26ce8f5f57c60a994bdc63d0ddce3a823 ("net: macb: add support for
high speed interface"). In this commit it is said that "This controller
has separate MAC's and PCS'es for low and high speed paths." Maybe it's
a hint.
Best regards,
Nicolas
--
Nicolas Ferre
From: Sean Anderson <hidden> Date: 2021-10-08 00:20:22
Hi Nicolas,
On 10/7/21 9:22 AM, Nicolas Ferre wrote:
On 04/10/2021 at 21:15, Sean Anderson wrote:
quoted
While we're on the subject, could someone clarify the relationship
between the various speed capabilities? What's the difference between
MACB_CAPS_GIGABIT_MODE_AVAILABLE, MACB_CAPS_HIGH_SPEED, MACB_CAPS_PCS,
and macb_is_gem()? Would there ever be a GEM without GIGABIT_MODE?
Yes. GEM is a new revision of the IP that is capable of doing Gigabit
mode or not. sama7g5_emac_config is typically one of those doing only
10/100.
Thanks for pointing that out. But even that config still has
MACB_CAPS_GIGABIT_MODE_AVAILABLE. So presumably you can use it for
gigabit speed if you don't use MII-on-RGMII. I suppose that
sama7g5_emac_config is not a GEM?
quoted
HIGH_SPEED without PCS? Why doesn't SGMII care if we're a gem (I think
this one is a bug, because it cares later on)?
MACB_CAPS_HIGH_SPEED and MACB_CAPS_PCS were added by
e4e143e26ce8f5f57c60a994bdc63d0ddce3a823 ("net: macb: add support for
high speed interface"). In this commit it is said that "This
controller has separate MAC's and PCS'es for low and high speed
paths." Maybe it's a hint.
Ah, so perhaps HIGH_SPEED only represents the capability for a
high-speed PCS. Which of course is a bit strange considering that we
check for both it, PCS, and GIGABIT_MODE when determining whether we can
do 10G.
--Sean
From: Nicolas Ferre <nicolas.ferre@microchip.com> Date: 2021-10-08 08:12:23
Sean,
On 08/10/2021 at 02:20, Sean Anderson wrote:
On 10/7/21 9:22 AM, Nicolas Ferre wrote:
quoted
On 04/10/2021 at 21:15, Sean Anderson wrote:
quoted
While we're on the subject, could someone clarify the relationship
between the various speed capabilities? What's the difference between
MACB_CAPS_GIGABIT_MODE_AVAILABLE, MACB_CAPS_HIGH_SPEED, MACB_CAPS_PCS,
and macb_is_gem()? Would there ever be a GEM without GIGABIT_MODE?
>>
quoted
Yes. GEM is a new revision of the IP that is capable of doing Gigabit
mode or not. sama7g5_emac_config is typically one of those doing only
10/100.
>
Thanks for pointing that out. But even that config still has
MACB_CAPS_GIGABIT_MODE_AVAILABLE. So presumably you can use it for
gigabit speed if you don't use MII-on-RGMII. I suppose that
sama7g5_emac_config is not a GEM?
There must be a confusion between sama7g5_gem_config and
sama7g5_emac_config here. The later one doesn't have this
MACB_CAPS_GIGABIT_MODE_AVAILABLE capability.
Both are flavors of GEM and identified as such in the driver.
Best regards,
Nicolas
--
Nicolas Ferre
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:35
The new pcs-related functions in the next few commits fit better before
phylink_create, so move phylink_set_pcs in preparation. No functional
change intended.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/phylink.c | 42 +++++++++++++++++++--------------------
1 file changed, 21 insertions(+), 21 deletions(-)
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 09:43:41
On Mon, Oct 04, 2021 at 03:15:15PM -0400, Sean Anderson wrote:
The new pcs-related functions in the next few commits fit better before
phylink_create, so move phylink_set_pcs in preparation. No functional
change intended.
Signed-off-by: Sean Anderson <redacted>
Reviewed-by: Russell King (Oracle) <redacted>
Thanks.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:38
This adds support for using an external PCS. If someone else has set the
PCS beforehand, then we will use it instead of the internal PCS.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/ethernet/cadence/macb_main.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
@@ -862,7 +862,7 @@ static int macb_mac_prepare(struct phylink_config *config, unsigned int mode,}if(set_pcs)-phylink_set_pcs(bp->phylink,&bp->phylink_pcs);+set_pcs=phylink_set_pcs_weak(bp->phylink,&bp->phylink_pcs);spin_lock_irqsave(&bp->lock,flags);
@@ -877,8 +877,11 @@ static int macb_mac_prepare(struct phylink_config *config, unsigned int mode,ncr|=MACB_BIT(MIIONRGMII);}-if(macb_is_gem(bp)&&set_pcs)-ctrl|=GEM_BIT(PCSSEL);+if(macb_is_gem(bp)){+ctrl&=~GEM_BIT(PCSSEL);+if(set_pcs)+ctrl|=GEM_BIT(PCSSEL);+}/* Apply the new configuration, if any */if(old_ctrl^ctrl)
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:44
This function is useful when probing MDIO devices which present a
phy-like interface despite not using the Linux ethernet phy subsystem.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/phy/phy_device.c | 3 ++-
include/linux/phy.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
@@ -805,7 +805,7 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr,*valid,%-EIOonbusaccesserror,or%-ENODEVifnodeviceresponds*orinvalidID.*/-staticintget_phy_c22_id(structmii_bus*bus,intaddr,u32*phy_id)+intget_phy_c22_id(structmii_bus*bus,intaddr,u32*phy_id){intphy_reg;
@@ -833,6 +833,7 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id)return0;}+EXPORT_SYMBOL_GPL(get_phy_c22_id);/* Extract the phy ID from the compatible string of the form*ethernet-phy-idAAAA.BBBB.
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 10:12:29
On Mon, Oct 04, 2021 at 03:15:24PM -0400, Sean Anderson wrote:
This function is useful when probing MDIO devices which present a
phy-like interface despite not using the Linux ethernet phy subsystem.
Maybe we should consider moving this into mdio_device.c and renaming
it if it's going to become more generic? Maybe mdio_read_c22_id()?
Andrew, Heiner, any opinions?
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:47
mac_prepare is called every time the interface is changed, so we can do
all of our configuration there, instead of in mac_config. This will be
useful for the next patch where we will set the PCS bit based on whether
we are using our internal PCS. No functional change intended.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/ethernet/cadence/macb_main.c | 67 +++++++++++++-----------
1 file changed, 35 insertions(+), 32 deletions(-)
@@ -652,42 +652,10 @@ static const struct phylink_pcs_ops macb_phylink_pcs_ops = {staticvoidmacb_mac_config(structphylink_config*config,unsignedintmode,conststructphylink_link_state*state){-structnet_device*ndev=to_net_dev(config->dev);-structmacb*bp=netdev_priv(ndev);unsignedlongflags;-u32old_ctrl,ctrl;-u32old_ncr,ncr;spin_lock_irqsave(&bp->lock,flags);-old_ctrl=ctrl=macb_or_gem_readl(bp,NCFGR);-old_ncr=ncr=macb_or_gem_readl(bp,NCR);--if(bp->caps&MACB_CAPS_MACB_IS_EMAC){-if(state->interface==PHY_INTERFACE_MODE_RMII)-ctrl|=MACB_BIT(RM9200_RMII);-}elseif(macb_is_gem(bp)){-ctrl&=~(GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL));-ncr&=~GEM_BIT(ENABLE_HS_MAC);--if(state->interface==PHY_INTERFACE_MODE_SGMII){-ctrl|=GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL);-}elseif(state->interface==PHY_INTERFACE_MODE_10GBASER){-ctrl|=GEM_BIT(PCSSEL);-ncr|=GEM_BIT(ENABLE_HS_MAC);-}elseif(bp->caps&MACB_CAPS_MIIONRGMII&&-bp->phy_interface==PHY_INTERFACE_MODE_MII){-ncr|=MACB_BIT(MIIONRGMII);-}-}--/* Apply the new configuration, if any */-if(old_ctrl^ctrl)-macb_or_gem_writel(bp,NCFGR,ctrl);--if(old_ncr^ncr)-macb_or_gem_writel(bp,NCR,ncr);-/* Disable AN for SGMII fixed link configuration, enable otherwise.*MustbewrittenafterPCSSELissetinNCFGR,*otherwisewriteswillnottakeeffect.
@@ -797,6 +765,9 @@ static int macb_mac_prepare(struct phylink_config *config, unsigned int mode,{structnet_device*ndev=to_net_dev(config->dev);structmacb*bp=netdev_priv(ndev);+unsignedlongflags;+u32old_ctrl,ctrl;+u32old_ncr,ncr;if(interface==PHY_INTERFACE_MODE_10GBASER)bp->phylink_pcs.ops=&macb_phylink_usx_pcs_ops;
@@ -808,6 +779,38 @@ static int macb_mac_prepare(struct phylink_config *config, unsigned int mode,if(bp->phylink_pcs.ops)phylink_set_pcs(bp->phylink,&bp->phylink_pcs);+spin_lock_irqsave(&bp->lock,flags);++old_ctrl=ctrl=macb_or_gem_readl(bp,NCFGR);+old_ncr=ncr=macb_or_gem_readl(bp,NCR);++if(bp->caps&MACB_CAPS_MACB_IS_EMAC){+if(interface==PHY_INTERFACE_MODE_RMII)+ctrl|=MACB_BIT(RM9200_RMII);+}elseif(macb_is_gem(bp)){+ctrl&=~(GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL));+ncr&=~GEM_BIT(ENABLE_HS_MAC);++if(state->interface==PHY_INTERFACE_MODE_SGMII){+ctrl|=GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL);+}elseif(state->interface==PHY_INTERFACE_MODE_10GBASER){+ctrl|=GEM_BIT(PCSSEL);+ncr|=GEM_BIT(ENABLE_HS_MAC);+}elseif(bp->caps&MACB_CAPS_MIIONRGMII&&+bp->phy_interface==PHY_INTERFACE_MODE_MII){+ncr|=MACB_BIT(MIIONRGMII);+}+}++/* Apply the new configuration, if any */+if(old_ctrl^ctrl)+macb_or_gem_writel(bp,NCFGR,ctrl);++if(old_ncr^ncr)+macb_or_gem_writel(bp,NCR,ncr);++spin_unlock_irqrestore(&bp->lock,flags);+return0;}
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-04 23:05:38
On Mon, Oct 04, 2021 at 03:15:20PM -0400, Sean Anderson wrote:
mac_prepare is called every time the interface is changed, so we can do
all of our configuration there, instead of in mac_config. This will be
useful for the next patch where we will set the PCS bit based on whether
we are using our internal PCS. No functional change intended.
The subject line appears to be the reverse of what you're actually
doing.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-04 23:10:02
On 10/4/21 7:05 PM, Russell King (Oracle) wrote:
On Mon, Oct 04, 2021 at 03:15:20PM -0400, Sean Anderson wrote:
quoted
mac_prepare is called every time the interface is changed, so we can do
all of our configuration there, instead of in mac_config. This will be
useful for the next patch where we will set the PCS bit based on whether
we are using our internal PCS. No functional change intended.
The subject line appears to be the reverse of what you're actually
doing.
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:51
This adds some helpers for accessing non-phy MDIO devices. They are
analogous to phy_(read|write|modify), except that they take an mdio_device
and not a phy_device.
Signed-off-by: Sean Anderson <redacted>
---
include/linux/mdio.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
From: Sean Anderson <hidden> Date: 2021-10-04 19:16:56
This moves all PCS-related settings to the pcs callbacks. This makes it
easy to support external PCSs. In addition, support for 1000BASE-X is
added (since we need it to set the SGMII mux).
pcs_config should set all registers necessary to bring the link up. In
addition, it needs to keep track of whether it modified anything so that
phylink can restart autonegotiation. config is also the right time to
veto configuration parameters, such as using the wrong interface. This
catches someone trying to use a slower speed (which could be supported
otherwise) after using a faster speed. We can't support this because
phylink doesn't support detaching PCSs.
pcs_link_up is necessary IFF the mode is not in-band and the speed and
duplex are different from what was set in config. However, because the
PCS supports only fixed speed (SPEED_1000 or SPEED_10000) and full
duplex, there is nothing to configure. Therefore, link_up has been
removed.
Now that the autonegotiation is done in pcs_config, we no longer need to
do it in macb_mac_config.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/ethernet/cadence/macb_main.c | 214 +++++++++++++++--------
1 file changed, 138 insertions(+), 76 deletions(-)
@@ -609,70 +685,60 @@ static int macb_usx_pcs_config(struct phylink_pcs *pcs,constunsignedlong*advertising,boolpermit_pause_to_mac){-structmacb*bp=container_of(pcs,structmacb,phylink_pcs);+boolchanged;+structmacb*bp=pcs_to_macb(pcs);+u16old,new;+unsignedlongflags;-gem_writel(bp,USX_CONTROL,gem_readl(bp,USX_CONTROL)|-GEM_BIT(SIGNAL_OK));+if(interface!=PHY_INTERFACE_MODE_10GBASER)+return-EOPNOTSUPP;-return0;-}+spin_lock_irqsave(&bp->lock,flags);+old=new=gem_readl(bp,NCR);+new|=GEM_BIT(ENABLE_HS_MAC);+if(old!=new){+changed=true;+gem_writel(bp,NCFGR,new);+}-staticvoidmacb_pcs_get_state(structphylink_pcs*pcs,-structphylink_link_state*state)-{-state->link=0;-}+if(macb_pcs_config_an(bp,mode,interface,advertising))+changed=true;-staticvoidmacb_pcs_an_restart(structphylink_pcs*pcs)-{-/* Not supported */-}+old=new=gem_readl(bp,USX_CONTROL);+new|=GEM_BIT(SIGNAL_OK);+if(old!=new){+changed=true;+gem_writel(bp,USX_CONTROL,new);+}-staticintmacb_pcs_config(structphylink_pcs*pcs,-unsignedintmode,-phy_interface_tinterface,-constunsignedlong*advertising,-boolpermit_pause_to_mac)-{-return0;+old=new=gem_readl(bp,USX_CONTROL);+new=GEM_BFINS(SERDES_RATE,MACB_SERDES_RATE_10G,new);+new=GEM_BFINS(USX_CTRL_SPEED,HS_SPEED_10000M,new);+new&=~(GEM_BIT(TX_SCR_BYPASS)|GEM_BIT(RX_SCR_BYPASS));+new|=GEM_BIT(TX_EN);+if(old!=new){+changed=true;+gem_writel(bp,USX_CONTROL,new);+}++spin_unlock_irqrestore(&bp->lock,flags);+returnchanged;}staticconststructphylink_pcs_opsmacb_phylink_usx_pcs_ops={.pcs_get_state=macb_usx_pcs_get_state,.pcs_config=macb_usx_pcs_config,-.pcs_link_up=macb_usx_pcs_link_up,};staticconststructphylink_pcs_opsmacb_phylink_pcs_ops={.pcs_get_state=macb_pcs_get_state,-.pcs_an_restart=macb_pcs_an_restart,.pcs_config=macb_pcs_config,};staticvoidmacb_mac_config(structphylink_config*config,unsignedintmode,conststructphylink_link_state*state){-unsignedlongflags;--spin_lock_irqsave(&bp->lock,flags);--/* Disable AN for SGMII fixed link configuration, enable otherwise.-*MustbewrittenafterPCSSELissetinNCFGR,-*otherwisewriteswillnottakeeffect.-*/-if(macb_is_gem(bp)&&state->interface==PHY_INTERFACE_MODE_SGMII){-u32pcsctrl,old_pcsctrl;--old_pcsctrl=gem_readl(bp,PCSCNTRL);-if(mode==MLO_AN_FIXED)-pcsctrl=old_pcsctrl&~GEM_BIT(PCSAUTONEG);-else-pcsctrl=old_pcsctrl|GEM_BIT(PCSAUTONEG);-if(old_pcsctrl!=pcsctrl)-gem_writel(bp,PCSCNTRL,pcsctrl);-}--spin_unlock_irqrestore(&bp->lock,flags);+/* Nothing to do */}staticvoidmacb_mac_link_down(structphylink_config*config,unsignedintmode,
@@ -787,21 +856,14 @@ static int macb_mac_prepare(struct phylink_config *config, unsigned int mode,if(bp->caps&MACB_CAPS_MACB_IS_EMAC){if(interface==PHY_INTERFACE_MODE_RMII)ctrl|=MACB_BIT(RM9200_RMII);-}elseif(macb_is_gem(bp)){-ctrl&=~(GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL));-ncr&=~GEM_BIT(ENABLE_HS_MAC);--if(state->interface==PHY_INTERFACE_MODE_SGMII){-ctrl|=GEM_BIT(SGMIIEN)|GEM_BIT(PCSSEL);-}elseif(state->interface==PHY_INTERFACE_MODE_10GBASER){-ctrl|=GEM_BIT(PCSSEL);-ncr|=GEM_BIT(ENABLE_HS_MAC);-}elseif(bp->caps&MACB_CAPS_MIIONRGMII&&-bp->phy_interface==PHY_INTERFACE_MODE_MII){-ncr|=MACB_BIT(MIIONRGMII);-}+}elseif(bp->caps&MACB_CAPS_MIIONRGMII&&+bp->phy_interface==PHY_INTERFACE_MODE_MII){+ncr|=MACB_BIT(MIIONRGMII);}+if(macb_is_gem(bp)&&set_pcs)+ctrl|=GEM_BIT(PCSSEL);+/* Apply the new configuration, if any */if(old_ctrl^ctrl)macb_or_gem_writel(bp,NCFGR,ctrl);
There is no requirement to set state->interface here. Phylink doesn't
cater for interface changes when reading the state. As documented,
phylink will set state->interface already before calling this function
to indicate what interface mode it is currently expecting from the
hardware.
+static int macb_pcs_config_an(struct macb *bp, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising)
+{
+ bool changed = false;
+ u16 old, new;
+
+ old = gem_readl(bp, PCSANADV);
+ new = phylink_mii_c22_pcs_encode_advertisement(interface, advertising,
+ old);
+ if (old != new) {
+ changed = true;
+ gem_writel(bp, PCSANADV, new);
+ }
+
+ old = new = gem_readl(bp, PCSCNTRL);
+ if (mode == MLO_AN_INBAND)
Please use phylink_autoneg_inband(mode) here.
+ new |= BMCR_ANENABLE;
+ else
+ new &= ~BMCR_ANENABLE;
+ if (old != new) {
+ changed = true;
+ gem_writel(bp, PCSCNTRL, new);
+ }
There has been the suggestion that we should allow in-band AN to be
disabled in 1000base-X if we're in in-band mode according to the
ethtool state. I have a patch that adds that.
+ return changed;
+}
+
+static int macb_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ bool changed = false;
+ struct macb *bp = pcs_to_macb(pcs);
+ u16 old, new;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ old = new = gem_readl(bp, NCFGR);
+ if (interface == PHY_INTERFACE_MODE_SGMII) {
+ new |= GEM_BIT(SGMIIEN);
+ } else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
+ new &= ~GEM_BIT(SGMIIEN);
+ } else {
+ spin_lock_irqsave(&bp->lock, flags);
+ return -EOPNOTSUPP;
You can't actually abort at this point - phylink will print the error
and carry on regardless. The checking is all done via the validate()
callback and if that indicates the interface mode is acceptable, then
it should be accepted.
You don't want to remove this. When operating in 1000BASE-X mode, it
will be called if a restart is required (e.g. macb_pcs_config()
returning positive, or an ethtool request.) You need to keep the empty
function. That may also help the diff algorithm to produce a cleaner
patch too.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
There is no requirement to set state->interface here. Phylink doesn't
cater for interface changes when reading the state. As documented,
phylink will set state->interface already before calling this function
to indicate what interface mode it is currently expecting from the
hardware.
Ok, so instead I should be doing something like
if (gem_readl(bp, NCFGR) & GEM_BIT(SGMIIEN))
interface = PHY_INTERFACE_MODE_SGMII;
else
interface = PHY_INTERFACE_MODE_1000BASEX;
if (interface != state->interface) {
state->link = 0;
return;
}
?
quoted
+static int macb_pcs_config_an(struct macb *bp, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising)
+{
+ bool changed = false;
+ u16 old, new;
+
+ old = gem_readl(bp, PCSANADV);
+ new = phylink_mii_c22_pcs_encode_advertisement(interface, advertising,
+ old);
+ if (old != new) {
+ changed = true;
+ gem_writel(bp, PCSANADV, new);
+ }
+
+ old = new = gem_readl(bp, PCSCNTRL);
+ if (mode == MLO_AN_INBAND)
Please use phylink_autoneg_inband(mode) here.
Ok.
quoted
+ new |= BMCR_ANENABLE;
+ else
+ new &= ~BMCR_ANENABLE;
+ if (old != new) {
+ changed = true;
+ gem_writel(bp, PCSCNTRL, new);
+ }
There has been the suggestion that we should allow in-band AN to be
disabled in 1000base-X if we're in in-band mode according to the
ethtool state.
This logic is taken from phylink_mii_c22_pcs_config. Maybe I should add
another _encode variant? I hadn't done this here because the logic was
only one if statement.
I have a patch that adds that.
Have you posted it?
quoted
+ return changed;
+}
+
+static int macb_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ bool changed = false;
+ struct macb *bp = pcs_to_macb(pcs);
+ u16 old, new;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bp->lock, flags);
+ old = new = gem_readl(bp, NCFGR);
+ if (interface == PHY_INTERFACE_MODE_SGMII) {
+ new |= GEM_BIT(SGMIIEN);
+ } else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
+ new &= ~GEM_BIT(SGMIIEN);
+ } else {
+ spin_lock_irqsave(&bp->lock, flags);
+ return -EOPNOTSUPP;
You can't actually abort at this point - phylink will print the error
and carry on regardless. The checking is all done via the validate()
callback and if that indicates the interface mode is acceptable, then
it should be accepted.
Ok, so where can the PCS NAK an interface? This is the only callback
which has a return code, so I assumed this was the correct place to say
"no, we don't support this." This is what lynx_pcs_config does as well.
Hm, I didn't realized I had removed this, so I add it back in the next
patch. I will merge that one into this one.
When operating in 1000BASE-X mode, it
will be called if a restart is required (e.g. macb_pcs_config()
returning positive, or an ethtool request.) You need to keep the empty
function.
Ok, perhaps I can add some sanity checks for this in pcs_register.
--Sean
That may also help the diff algorithm to produce a cleaner
patch too.
There is no requirement to set state->interface here. Phylink doesn't
cater for interface changes when reading the state. As documented,
phylink will set state->interface already before calling this function
to indicate what interface mode it is currently expecting from the
hardware.
Ok, so instead I should be doing something like
if (gem_readl(bp, NCFGR) & GEM_BIT(SGMIIEN))
interface = PHY_INTERFACE_MODE_SGMII;
else
interface = PHY_INTERFACE_MODE_1000BASEX;
if (interface != state->interface) {
state->link = 0;
return;
}
Why would it be different? If we've called the pcs_config method to
set the interface to one mode, why would it change?
quoted
There has been the suggestion that we should allow in-band AN to be
disabled in 1000base-X if we're in in-band mode according to the
ethtool state.
This logic is taken from phylink_mii_c22_pcs_config. Maybe I should add
another _encode variant? I hadn't done this here because the logic was
only one if statement.
quoted
I have a patch that adds that.
Have you posted it?
I haven't - it is a patch from Robert Hancock, "net: phylink: Support
disabling autonegotiation for PCS". I've had it in my tree for a while,
but I do want to make some changes to it before re-posting.
quoted
You can't actually abort at this point - phylink will print the error
and carry on regardless. The checking is all done via the validate()
callback and if that indicates the interface mode is acceptable, then
it should be accepted.
Ok, so where can the PCS NAK an interface? This is the only callback
which has a return code, so I assumed this was the correct place to say
"no, we don't support this." This is what lynx_pcs_config does as well.
At the moment, the PCS doesn't get to NAK an inappropriate interface.
That's currently the job of the MAC's validate callback with the
assumtion that the MAC knows what interfaces are supportable.
Trying to do it later, once the configuration has been worked out can
_only_ lead to a failure of some kind - in many paths, there is no way
to report the problem except by printing a message into the kernel log.
For example, by the time we reach pcs_config(), we've already prepared
the MAC for a change to the interface, we've told the MAC to configure
for that interface. Now the PCS rejects it - we have no record of the
old configuration to restore. Even if we had a way to restore it, then
we could return an error to the user - but the user doesn't get to
control the interface themselves. If it was the result of a PHY changing
its interface, then what - we can only log an error to the kernel log.
If it's the result of a SFP being plugged in, we have no way to
renegotiate.
pcs_config() is too late to be making decisions about whether the
requested configuration is acceptable or not. It needs to be done as
part of the validation step.
However, the validation step is not purely just validation, but it's
negotiation too for SFPs to be able to work out what interface mode
they should use in combination with the support that the MAC/PCS
offers.
I do feel that the implementation around the validation/selection of
interface for SFP etc is starting to creak, and I've some patches that
introduce a bitmap of interface types that are supported by the various
components. I haven't had the motivation to finish that off as my last
attempt at making a phylink API change was not pleasant in terms of
either help updating network drivers or getting patches tested. So I
now try to avoid phylink API changes at all cost.
People have whinged that phylink's API changes too quickly... I'm
guessing we're now going to get other people arguing that it needs
change to fix issues like this...
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
There is no requirement to set state->interface here. Phylink doesn't
cater for interface changes when reading the state. As documented,
phylink will set state->interface already before calling this function
to indicate what interface mode it is currently expecting from the
hardware.
Ok, so instead I should be doing something like
if (gem_readl(bp, NCFGR) & GEM_BIT(SGMIIEN))
interface = PHY_INTERFACE_MODE_SGMII;
else
interface = PHY_INTERFACE_MODE_1000BASEX;
if (interface != state->interface) {
state->link = 0;
return;
}
Why would it be different? If we've called the pcs_config method to
set the interface to one mode, why would it change?
config() does not always come before get_state due to (e.g.)
phylink_ethtool_ksettings_get. Though in that instance, state->interface
is not read. And of course this ordering isn't documented.
That being said, I will just do
if (interface != PHY_INTERFACE_MODE_SGMII ||
interface != PHY_INTERFACE_MODE_1000BASEX) {
state->link = 0;
return;
}
for next time.
quoted
quoted
There has been the suggestion that we should allow in-band AN to be
disabled in 1000base-X if we're in in-band mode according to the
ethtool state.
This logic is taken from phylink_mii_c22_pcs_config. Maybe I should add
another _encode variant? I hadn't done this here because the logic was
only one if statement.
quoted
I have a patch that adds that.
Have you posted it?
I haven't - it is a patch from Robert Hancock, "net: phylink: Support
disabling autonegotiation for PCS". I've had it in my tree for a while,
but I do want to make some changes to it before re-posting.
You can't actually abort at this point - phylink will print the error
and carry on regardless. The checking is all done via the validate()
callback and if that indicates the interface mode is acceptable, then
it should be accepted.
Ok, so where can the PCS NAK an interface? This is the only callback
which has a return code, so I assumed this was the correct place to say
"no, we don't support this." This is what lynx_pcs_config does as well.
At the moment, the PCS doesn't get to NAK an inappropriate interface.
That's currently the job of the MAC's validate callback with the
assumtion that the MAC knows what interfaces are supportable.
Which is a rather silly assumption because then you have to update the
MAC's validate function every time you add a new PCS. And this gets
messy rather fast. For example, you might want to connect your SFP
module to a MAC which only has an RGMII interface. So you put a DP83869
on your board connected like
MAC <--RGMII--> DP83869 <--SGMII--> SFP
For the moment, I think you have to just pretend that the DP83869 is the
only PHY in the system and hope that you don't need to talk to the SFP's
PHY. But if you want to use the DP83869 as a PCS, then you need to
update the MAC's validate() to allow SGMII, even though the MAC doesn't
support that without an external converter.
In an ideal world, the MAC would select its interface based on the PCS
(or lack of one), and the PCS would validate the interface mode. But of
course, there may be multiple PCSs available, so it is not so easy.
(Selecting between multiple PCSs (or no PCS at all) seems to be similar
in spirit to the PORT_XXX settings)
Trying to do it later, once the configuration has been worked out can
_only_ lead to a failure of some kind - in many paths, there is no way
to report the problem except by printing a message into the kernel log.
For example, by the time we reach pcs_config(), we've already prepared
the MAC for a change to the interface, we've told the MAC to configure
for that interface. Now the PCS rejects it - we have no record of the
old configuration to restore. Even if we had a way to restore it, then
we could return an error to the user - but the user doesn't get to
control the interface themselves. If it was the result of a PHY changing
its interface, then what - we can only log an error to the kernel log.
If it's the result of a SFP being plugged in, we have no way to
renegotiate.
pcs_config() is too late to be making decisions about whether the
requested configuration is acceptable or not. It needs to be done as
part of the validation step.
Well, if these are the constraints, then IMO the PCS must have its own
validate() callback. Otherwise there is no way to tell a MAC that (for
example) supports both SGMII and 1000BASE-X that the PCS only supports
1000BASE-X. As another example, the MAC could support half duplex, but
the PCS might only suppport full duplex.
However, the validation step is not purely just validation, but it's
negotiation too for SFPs to be able to work out what interface mode
they should use in combination with the support that the MAC/PCS
offers.
I do feel that the implementation around the validation/selection of
interface for SFP etc is starting to creak, and I've some patches that
introduce a bitmap of interface types that are supported by the various
components. I haven't had the motivation to finish that off as my last
attempt at making a phylink API change was not pleasant in terms of
either help updating network drivers or getting patches tested. So I
now try to avoid phylink API changes at all cost.
People have whinged that phylink's API changes too quickly... I'm
guessing we're now going to get other people arguing that it needs
change to fix issues like this...
I think it should change, and I can help test things out on my own
setup, for whatever that's worth.
At the very least, it should be clearer what things are allowed to fail
for what reasons. Several callbacks are void when things can fail under
the hood (e.g. link_up or an_restart). And the API seems to have been
primarily designed around PCSs which are tightly-coupled to their MACs.
--Sean
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-05 22:19:56
On Tue, Oct 05, 2021 at 05:44:11PM -0400, Sean Anderson wrote:
At the very least, it should be clearer what things are allowed to fail
for what reasons. Several callbacks are void when things can fail under
the hood (e.g. link_up or an_restart). And the API seems to have been
primarily designed around PCSs which are tightly-coupled to their MACs.
It has indeed been designed around that, because that's where the
technology that has been available to me has been. It is only in
the recent few years that we are starting to see designs where
the PCS is separate.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-07 10:34:16
On Tue, Oct 05, 2021 at 11:19:45PM +0100, Russell King (Oracle) wrote:
On Tue, Oct 05, 2021 at 05:44:11PM -0400, Sean Anderson wrote:
quoted
At the very least, it should be clearer what things are allowed to fail
for what reasons. Several callbacks are void when things can fail under
the hood (e.g. link_up or an_restart). And the API seems to have been
primarily designed around PCSs which are tightly-coupled to their MACs.
I think what I'd like to see is rather than a validate() callback for
the PCS, a bitmap of phy_interface_t modes that the PCS supports,
which is the direction I was wanting to take phylink and SFP support.
We can then use that information to inform the interface selection in
phylink and avoid interface modes that the PCS doesn't support.
However, things get tricky when we have several PCS that we can switch
between, and the switching is done in mac_prepare(). The current PCS
(if there is even a PCS attached) may not represent the abilities
that are actually available.
It sounds easy - just throw in an extra validation step when calling
phylink_validate(), but it isn't that simple. To avoid breaking
existing setups, phylink would need to know of every PCS that _could_
be attached, and the decisions that the MAC makes to select which PCS
is going to be used for any configuration.
We could possibly introduce a .mac_select_pcs(interface) method
which the MAC could return the PCS it wishes to use for the interface
mode with the guarantee that the PCS it returns is suitable - and if
it returns NULL that means the interface mode is unsupported. That,
along with the bitmask would probably work.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-07 11:29:14
On Thu, Oct 07, 2021 at 11:34:06AM +0100, Russell King (Oracle) wrote:
On Tue, Oct 05, 2021 at 11:19:45PM +0100, Russell King (Oracle) wrote:
quoted
On Tue, Oct 05, 2021 at 05:44:11PM -0400, Sean Anderson wrote:
quoted
At the very least, it should be clearer what things are allowed to fail
for what reasons. Several callbacks are void when things can fail under
the hood (e.g. link_up or an_restart). And the API seems to have been
primarily designed around PCSs which are tightly-coupled to their MACs.
I think what I'd like to see is rather than a validate() callback for
the PCS, a bitmap of phy_interface_t modes that the PCS supports,
which is the direction I was wanting to take phylink and SFP support.
We can then use that information to inform the interface selection in
phylink and avoid interface modes that the PCS doesn't support.
However, things get tricky when we have several PCS that we can switch
between, and the switching is done in mac_prepare(). The current PCS
(if there is even a PCS attached) may not represent the abilities
that are actually available.
It sounds easy - just throw in an extra validation step when calling
phylink_validate(), but it isn't that simple. To avoid breaking
existing setups, phylink would need to know of every PCS that _could_
be attached, and the decisions that the MAC makes to select which PCS
is going to be used for any configuration.
We could possibly introduce a .mac_select_pcs(interface) method
which the MAC could return the PCS it wishes to use for the interface
mode with the guarantee that the PCS it returns is suitable - and if
it returns NULL that means the interface mode is unsupported. That,
along with the bitmask would probably work.
Here's a patch which illustrates roughly what I'm thinking at the
moment - only build tested.
mac_select_pcs() should not ever fail in phylink_major_config() - that
would be a bug. I've hooked mac_select_pcs() also into the validate
function so we can catch problems there, but we will need to involve
the PCS in the interface selection for SFPs etc.
Note that mac_select_pcs() must be inconsequential - it's asking the
MAC which PCS it wishes to use for the interface mode.
I am still very much undecided whether we wish phylink to parse the
pcs-handle property and if present, override the MAC - I feel that
logic depends in the MAC driver, since a single PCS can be very
restrictive in terms of what interface modes are supportable. If the
MAC wishes pcs-handle to override its internal ones, then it can
always do:
if (port->external_pcs)
return port->external_pcs;
in its mac_select_pcs() implementation. This gives us a bit of future
flexibility.
If we parse pcs-handle in phylink, then if we end up with multiple PCS
to choose from, we then need to work out how to either allow the MAC
driver to tell phylink not to parse pcs-handle, or we need some way for
phylink to ask the MAC "these are the PCS I have, which one should I
use" which is yet another interface.
What I don't like about the patch is the need to query the PCS based on
interface - when we have a SFP plugged in, it may support multiple
interfaces. I think we still need the MAC to restrict what it returns
in its validate() method according to the group of PCS that it has
available for the SFP interface selection to work properly. Things in
this regard should become easier _if_ I can switch phylink over to
selecting interface based on phy_interface_t bitmaps rather than the
current bodge using ethtool link modes, but that needs changes to phylib
and all MAC drivers, otherwise we have to support two entirely separate
ways to select the interface mode.
My argument against that is... I'll end up converting the network
interfaces that I use to the new implementation, and the old version
will start to rot. I've already stopped testing phylink without a PCS
attached for this very reason. The more legacy code we keep, the worse
this problem becomes.
@@ -6185,7 +6190,7 @@ static int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode,constunsignedlong*advertising,boolpermit_pause_to_mac){-structmvpp2_port*port=mvpp2_pcs_to_port(pcs);+structmvpp2_port*port=mvpp2_pcs_gmac_to_port(pcs);u32mask,val,an,old_an,changed;mask=MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS|
@@ -6239,7 +6244,7 @@ static int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode,staticvoidmvpp2_gmac_pcs_an_restart(structphylink_pcs*pcs){-structmvpp2_port*port=mvpp2_pcs_to_port(pcs);+structmvpp2_port*port=mvpp2_pcs_gmac_to_port(pcs);u32val=readl(port->base+MVPP2_GMAC_AUTONEG_CONFIG);writel(val|MVPP2_GMAC_IN_BAND_RESTART_AN,
@@ -6428,8 +6433,23 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,writel(ctrl4,port->base+MVPP22_GMAC_CTRL_4_REG);}-staticintmvpp2__mac_prepare(structphylink_config*config,unsignedintmode,-phy_interface_tinterface)+staticstructphylink_pcs*mvpp2_select_pcs(structphylink_config*config,+phy_interface_tinterface)+{+structmvpp2_port*port=mvpp2_phylink_to_port(config);++/* Select the appropriate PCS operations depending on the+*configuredinterfacemode.Wewillonlyswitchtoamode+*thatthevalidate()checkshavealreadypassed.+*/+if(mvpp2_is_xlg(interface))+return&port->pcs_xlg;+else+return&port->pcs_gmac;+}++staticintmvpp2_mac_prepare(structphylink_config*config,unsignedintmode,+phy_interface_tinterface){structmvpp2_port*port=mvpp2_phylink_to_port(config);
@@ -6475,31 +6495,9 @@ static int mvpp2__mac_prepare(struct phylink_config *config, unsigned int mode,}}-/* Select the appropriate PCS operations depending on the-*configuredinterfacemode.Wewillonlyswitchtoamode-*thatthevalidate()checkshavealreadypassed.-*/-if(mvpp2_is_xlg(interface))-port->phylink_pcs.ops=&mvpp2_phylink_xlg_pcs_ops;-else-port->phylink_pcs.ops=&mvpp2_phylink_gmac_pcs_ops;-return0;}-staticintmvpp2_mac_prepare(structphylink_config*config,unsignedintmode,-phy_interface_tinterface)-{-structmvpp2_port*port=mvpp2_phylink_to_port(config);-intret;--ret=mvpp2__mac_prepare(config,mode,interface);-if(ret==0)-phylink_set_pcs(port->phylink,&port->phylink_pcs);--returnret;-}-staticvoidmvpp2_mac_config(structphylink_config*config,unsignedintmode,conststructphylink_link_state*state){
From: "Russell King (Oracle)" <linux@armlinux.org.uk> Date: 2021-10-07 16:23:45
On Thu, Oct 07, 2021 at 12:29:00PM +0100, Russell King (Oracle) wrote:
Here's a patch which illustrates roughly what I'm thinking at the
moment - only build tested.
mac_select_pcs() should not ever fail in phylink_major_config() - that
would be a bug. I've hooked mac_select_pcs() also into the validate
function so we can catch problems there, but we will need to involve
the PCS in the interface selection for SFPs etc.
Note that mac_select_pcs() must be inconsequential - it's asking the
MAC which PCS it wishes to use for the interface mode.
I am still very much undecided whether we wish phylink to parse the
pcs-handle property and if present, override the MAC - I feel that
logic depends in the MAC driver, since a single PCS can be very
restrictive in terms of what interface modes are supportable. If the
MAC wishes pcs-handle to override its internal ones, then it can
always do:
if (port->external_pcs)
return port->external_pcs;
in its mac_select_pcs() implementation. This gives us a bit of future
flexibility.
If we parse pcs-handle in phylink, then if we end up with multiple PCS
to choose from, we then need to work out how to either allow the MAC
driver to tell phylink not to parse pcs-handle, or we need some way for
phylink to ask the MAC "these are the PCS I have, which one should I
use" which is yet another interface.
What I don't like about the patch is the need to query the PCS based on
interface - when we have a SFP plugged in, it may support multiple
interfaces. I think we still need the MAC to restrict what it returns
in its validate() method according to the group of PCS that it has
available for the SFP interface selection to work properly. Things in
this regard should become easier _if_ I can switch phylink over to
selecting interface based on phy_interface_t bitmaps rather than the
current bodge using ethtool link modes, but that needs changes to phylib
and all MAC drivers, otherwise we have to support two entirely separate
ways to select the interface mode.
My argument against that is... I'll end up converting the network
interfaces that I use to the new implementation, and the old version
will start to rot. I've already stopped testing phylink without a PCS
attached for this very reason. The more legacy code we keep, the worse
this problem becomes.
Having finished off the SFP side of the phy_interface_t bitmap
(http://git.armlinux.org.uk/cgit/linux-arm.git/log/?h=net-queue)
and I think the mac_select_pcs() approach will work.
See commit
http://git.armlinux.org.uk/cgit/linux-arm.git/commit/?h=net-queue&id=3e0d51c361f5191111af206e3ed024d4367fce78
where we have a set of phy_interface_t to choose one from, and if
we add PCS selection into that logic, the loop becomes:
static phy_interface_t phylink_select_interface(struct phylink *pl,
const unsigned long *intf
const char *intf_name)
{
phy_interface_t interface, intf;
...
interface = PHY_INTERFACE_MODE_NA;
for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) {
intf = phylink_sfp_interface_preference[i];
if (!test_bit(intf, u))
continue;
pcs = pl->pcs;
if (pl->mac_ops->mac_select_pcs) {
pcs = pl->mac_ops->mac_select_pcs(pl->config, intf);
if (!pcs)
continue;
}
if (pcs && !test_bit(intf, pcs->supported_interfaces))
continue;
interface = intf;
break;
}
...
}
The alternative would be to move some of that logic into
phylink_sfp_config_nophy(), and will mean knocking out bits from
the mask supplied to phylink_select_interface() each time we select
an interface mode that the PCS doesn't support... which sounds rather
more yucky to me.
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
From: Sean Anderson <hidden> Date: 2021-10-07 17:04:37
On 10/7/21 12:23 PM, Russell King (Oracle) wrote:
On Thu, Oct 07, 2021 at 12:29:00PM +0100, Russell King (Oracle) wrote:
quoted
Here's a patch which illustrates roughly what I'm thinking at the
moment - only build tested.
mac_select_pcs() should not ever fail in phylink_major_config() - that
would be a bug. I've hooked mac_select_pcs() also into the validate
function so we can catch problems there, but we will need to involve
the PCS in the interface selection for SFPs etc.
Note that mac_select_pcs() must be inconsequential - it's asking the
MAC which PCS it wishes to use for the interface mode.
I am still very much undecided whether we wish phylink to parse the
pcs-handle property and if present, override the MAC - I feel that
logic depends in the MAC driver, since a single PCS can be very
restrictive in terms of what interface modes are supportable. If the
MAC wishes pcs-handle to override its internal ones, then it can
always do:
if (port->external_pcs)
return port->external_pcs;
in its mac_select_pcs() implementation. This gives us a bit of future
flexibility.
If we parse pcs-handle in phylink, then if we end up with multiple PCS
to choose from, we then need to work out how to either allow the MAC
driver to tell phylink not to parse pcs-handle, or we need some way for
phylink to ask the MAC "these are the PCS I have, which one should I
use" which is yet another interface.
What I don't like about the patch is the need to query the PCS based on
interface - when we have a SFP plugged in, it may support multiple
interfaces. I think we still need the MAC to restrict what it returns
in its validate() method according to the group of PCS that it has
available for the SFP interface selection to work properly. Things in
this regard should become easier _if_ I can switch phylink over to
selecting interface based on phy_interface_t bitmaps rather than the
current bodge using ethtool link modes, but that needs changes to phylib
and all MAC drivers, otherwise we have to support two entirely separate
ways to select the interface mode.
My argument against that is... I'll end up converting the network
interfaces that I use to the new implementation, and the old version
will start to rot. I've already stopped testing phylink without a PCS
attached for this very reason. The more legacy code we keep, the worse
this problem becomes.
Having finished off the SFP side of the phy_interface_t bitmap
(http://git.armlinux.org.uk/cgit/linux-arm.git/log/?h=net-queue)
and I think the mac_select_pcs() approach will work.
See commit
http://git.armlinux.org.uk/cgit/linux-arm.git/commit/?h=net-queue&id=3e0d51c361f5191111af206e3ed024d4367fce78
where we have a set of phy_interface_t to choose one from, and if
we add PCS selection into that logic, the loop becomes:
static phy_interface_t phylink_select_interface(struct phylink *pl,
const unsigned long *intf
const char *intf_name)
{
phy_interface_t interface, intf;
...
interface = PHY_INTERFACE_MODE_NA;
for (i = 0; i < ARRAY_SIZE(phylink_sfp_interface_preference); i++) {
intf = phylink_sfp_interface_preference[i];
if (!test_bit(intf, u))
continue;
pcs = pl->pcs;
if (pl->mac_ops->mac_select_pcs) {
pcs = pl->mac_ops->mac_select_pcs(pl->config, intf);
if (!pcs)
continue;
}
if (pcs && !test_bit(intf, pcs->supported_interfaces))
continue;
interface = intf;
break;
}
...
}
The alternative would be to move some of that logic into
phylink_sfp_config_nophy(), and will mean knocking out bits from
the mask supplied to phylink_select_interface() each time we select
an interface mode that the PCS doesn't support... which sounds rather
more yucky to me.
With appropriate helper functions, I don't think we would need to have a
separate mac_select_pcs callback:
probe()
{
priv->pl = phylink_create();
priv->pcs1 = my_internal_pcs;
priv->pcs2 = phylink_find_pcs();
}
validate()
{
switch (state->interface) {
case PHY_INTERFACE_MODE_NA:
case PHY_INTERFACE_GMII:
phylink_set(mask, 1000baseT_Full);
phylink_set(mask, 1000baseX_Full);
if (one)
break;
fallthrough;
default:
matched = phylink_set_pcs_modes(mask, priv->pcs1, state);
matched ||= phylink_set_pcs_modes(mask, priv->pcs2, state);
if (matched)
break;
bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
return;
}
bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
}
prepare()
{
switch (state->interface) {
case PHY_INTERFACE_GMII:
enable_gmii();
break;
default:
if (phylink_attach_matching_pcs(priv->pl, priv->pcs1, state->interface)) {
enable_internal_pcs();
break;
}
if (phylink_attach_matching_pcs(priv->pl, priv->pcs2, state->interface)) {
enable_external_pcs();
break;
}
BUG();
}
}
int phylink_set_interface_mode(mask, iface)
{
/* switch statement from phylink_parse_mode here */
}
bool phylink_set_pcs_modes(mask, pcs, state)
{
if (state->interface != PHY_INTERFACE_MODE_NA) {
if (!test_bit(state->interface, pcs->supported_interfaces))
return false;
phylink_set_interface_mode(mask, state->interface);
return true;
}
for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
if (test_bit(i, pcs->supported_interfaces))
phylink_set_interface_mode(mask, state->interface);
}
return true;
}
bool phylink_attach_matching_pcs(pl, pcs, iface)
{
if (!test_bit(iface, pcs->supported_interfaces))
return false;
phylink_set_pcs(pl, pcs);
return true;
}
I think this has some advantages over a separate mac_select_pcs():
- In validate() you get all the available interfaces.
- The MAC can set the priority of its PCSs however it likes, which is
probably good enough for almost every case.
- The MAC doesn't care about what interfaces the PCSs actually support.
- phylink can do whatever logic it wants for selection under the hood.
- From phylink's POV, drivers behave the same way no matter whether they
use these helpers or whether they just say "If we use SGMII, then use
our internal PCS)".
--Sean
From: Sean Anderson <hidden> Date: 2021-10-04 19:17:00
This adds support for restarting autonegotiation using the internal PCS.
Signed-off-by: Sean Anderson <redacted>
---
drivers/net/ethernet/cadence/macb_main.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
From: Sean Anderson <hidden> Date: 2021-10-04 19:17:04
This adds support for the Xilinx 1G/2.5G Ethernet PCS/PMA or SGMII
device. This is a soft device which converts between GMII and either
SGMII, 2.5G SGMII, 1000BASE-X, or 2500BASE-X. If configured correctly,
it can also switch between SGMII and 1000BASE-X at runtime. Internally,
these are referred to as the "standard" to match the terminology in the
datasheet. I am not sure how to handle the 2.5G SGMII case yet (since
AIUI Linux doesn't think it exists), and I do not have the hardware to
test it, so I have left out support.
This device has a c22-compliant PHY interface, so for the most part we
can just use the phylink helpers. Where we have to do things manually is
usually just to set the interface. We also set the speed and duplex when
the link comes up. I don't know what the permit_pause_to_mac parameter
is for in pcs_config, so I ignore it...
This device supports an interrupt which is triggered on link status
change. While according to Documentation/networking/sfp-phylink.rst the
mac should call phylink_mac_change on link state change, it is unclear
to me what the PCS should call. For now I have just set the PCS to
poll.
This device supports sharing some logic between different
implementations of the device. In this case, one device has the shared
logic, and several output (clocks, resets, etc.) are connected between
it and the consuming devices. I am not sure how to model this (create a
clock? add a devlink?) so I have left it out, but I would like to
include support for this use-case.
Signed-off-by: Sean Anderson <redacted>
---
MAINTAINERS | 6 +
drivers/net/pcs/Kconfig | 19 ++
drivers/net/pcs/Makefile | 1 +
drivers/net/pcs/pcs-xilinx.c | 326 +++++++++++++++++++++++++++++++++++
4 files changed, 352 insertions(+)
create mode 100644 drivers/net/pcs/pcs-xilinx.c
@@ -0,0 +1,326 @@+// SPDX-License-Identifier: GPL-2.0++/*+*Copyright2021SeanAnderson<sean.anderson@seco.com>+*+*ThisisthedriverfortheXilinx1G/2.5GEthernetPCS/PMAorSGMIILogiCORE+*IP.Atypicalsetupwilllooksomethinglike+*+*MAC<--GMII-->PCS+PMA<--internal/TBI-->PMD(SERDES)<--SGMII/1000BASE-X+*+*ThelinktothePMDisnotmodeledbythisdriver,exceptforrefclk.Itis+*assumedthattheSERDESneedsnoconfiguration.Itisalsopossibletogo+*fromSGMIItoGMII(PHYmode),butthisisnotsupported.+*+*ThisdriverwaswrittenwithreferencetoPG047:+*https://www.xilinx.com/support/documentation/ip_documentation/gig_ethernet_pcs_pma/v16_2/pg047-gig-eth-pcs-pma.pdf+*/++#include<linux/clk.h>+#include<linux/mdio.h>+#include<linux/of.h>+#include<linux/phylink.h>+#include<linux/reset.h>++/* Vendor-specific MDIO registers */+#define XILINX_PCS_ANICR 16 /* Auto-Negotiation Interrupt Control Register */+#define XILINX_PCS_SSR 17 /* Standard Selection Register */++#define XILINX_PCS_ANICR_IE BIT(0) /* Interrupt Enable */+#define XILINX_PCS_ANICR_IS BIT(1) /* Interrupt Status */++#define XILINX_PCS_SSR_SGMII BIT(0) /* Select SGMII standard */++/**+*enumxilinx_pcs_standard-Supportforinterfacestandards+*@XILINX_PCS_STD_SGMII:SGMIIfor10/100/1000BASE-T+*@XILINX_PCS_STD_1000BASEX:1000BASE-XPMDSupportInterface+*@XILINX_PCS_STD_BOTH:SupportforbothSGMIIand1000BASE-X+*@XILINX_PCS_STD_2500BASEX:2500BASE-XPMDSupportInterface+*@XILINX_PCS_STD_2500SGMII:2.5GSGMIIfor2.5GBASE-T+*/+enumxilinx_pcs_standard{+XILINX_PCS_STD_SGMII,+XILINX_PCS_STD_1000BASEX,+XILINX_PCS_STD_BOTH,+XILINX_PCS_STD_2500BASEX,+XILINX_PCS_STD_2500SGMII,+};++/**+*structxilinx_pcs-PrivatedataforXilinxPCSdevices+*@pcs:ThephylinkPCS+*@mdiodev:ThemdiodeviceusedtoaccessthePCS+*@refclk:ThereferenceclockforthePMD+*@reset:TheresetcontrollerforthePCS+*@standard:Thesupportedinterfacestandard+*/+structxilinx_pcs{+structphylink_pcspcs;+structmdio_device*mdiodev;+structclk*refclk;+structreset_control*reset;+enumxilinx_pcs_standardstandard;+};++staticinlinestructxilinx_pcs*pcs_to_xilinx(structphylink_pcs*pcs)+{+returncontainer_of(pcs,structxilinx_pcs,pcs);+}++staticvoidxilinx_pcs_get_state(structphylink_pcs*pcs,+structphylink_link_state*state)+{+structxilinx_pcs*xp=pcs_to_xilinx(pcs);++switch(xp->standard){+caseXILINX_PCS_STD_SGMII:+state->interface=PHY_INTERFACE_MODE_SGMII;+break;+caseXILINX_PCS_STD_1000BASEX:+state->interface=PHY_INTERFACE_MODE_1000BASEX;+break;+caseXILINX_PCS_STD_BOTH:{+intssr=mdiodev_read(xp->mdiodev,XILINX_PCS_SSR);++if(ssr<0){+dev_err(pcs->dev,"could not read SSR (err=%d)\n",ssr);+return;+}++if(ssr&XILINX_PCS_SSR_SGMII)+state->interface=PHY_INTERFACE_MODE_SGMII;+else+state->interface=PHY_INTERFACE_MODE_1000BASEX;+break;+}+caseXILINX_PCS_STD_2500BASEX:+state->interface=PHY_INTERFACE_MODE_2500BASEX;+break;+default:+return;+}++phylink_mii_c22_pcs_get_state(xp->mdiodev,state);+}++staticintxilinx_pcs_config(structphylink_pcs*pcs,unsignedintmode,+phy_interface_tinterface,+constunsignedlong*advertising,+boolpermit_pause_to_mac)+{+intret;+boolchanged=false;+structxilinx_pcs*xp=pcs_to_xilinx(pcs);++switch(xp->standard){+caseXILINX_PCS_STD_SGMII:+if(interface!=PHY_INTERFACE_MODE_SGMII)+return-EOPNOTSUPP;+break;+caseXILINX_PCS_STD_1000BASEX:+if(interface!=PHY_INTERFACE_MODE_1000BASEX)+return-EOPNOTSUPP;+break;+caseXILINX_PCS_STD_BOTH:{+u16ssr;++if(interface==PHY_INTERFACE_MODE_SGMII)+ssr=XILINX_PCS_SSR_SGMII;+elseif(interface==PHY_INTERFACE_MODE_1000BASEX)+ssr=0;+else+return-EOPNOTSUPP;++ret=mdiodev_read(xp->mdiodev,XILINX_PCS_SSR);+if(ret<0)+returnret;++if(ret==ssr)+break;++changed=true;+ret=mdiodev_write(xp->mdiodev,XILINX_PCS_SSR,ssr);+if(ret)+returnret;+break;+}+caseXILINX_PCS_STD_2500BASEX:+if(interface!=PHY_INTERFACE_MODE_2500BASEX)+return-EOPNOTSUPP;+break;+default:+return-EOPNOTSUPP;+}++ret=phylink_mii_c22_pcs_config(xp->mdiodev,mode,interface,+advertising);+if(ret)+returnret;+returnchanged;+}++staticvoidxilinx_pcs_an_restart(structphylink_pcs*pcs)+{+structxilinx_pcs*xp=pcs_to_xilinx(pcs);++phylink_mii_c22_pcs_an_restart(xp->mdiodev);+}++staticvoidxilinx_pcs_link_up(structphylink_pcs*pcs,unsignedintmode,+phy_interface_tinterface,intspeed,intduplex)+{+intbmcr;+structxilinx_pcs*xp=pcs_to_xilinx(pcs);++if(phylink_autoneg_inband(mode))+return;++bmcr=mdiodev_read(xp->mdiodev,MII_BMCR);+if(bmcr<0){+dev_err(pcs->dev,"could not read BMCR (err=%d)\n",bmcr);+return;+}++bmcr&=~BMCR_FULLDPLX;+if(duplex==DUPLEX_FULL)+bmcr|=BMCR_FULLDPLX;+elseif(duplex!=DUPLEX_HALF)+dev_err(pcs->dev,"unknown duplex %d\n",duplex);++bmcr&=~(BMCR_SPEED1000|BMCR_SPEED100);+switch(speed){+caseSPEED_2500:+caseSPEED_1000:+bmcr|=BMCR_SPEED1000;+break;+caseSPEED_100:+bmcr|=BMCR_SPEED100;+break;+caseSPEED_10:+bmcr|=BMCR_SPEED10;+break;+default:+dev_err(pcs->dev,"invalid speed %d\n",speed);+}++bmcr=mdiodev_write(xp->mdiodev,MII_BMCR,bmcr);+if(bmcr<0)+dev_err(pcs->dev,"could not write BMCR (err=%d)\n",bmcr);+}++staticconststructphylink_pcs_opsxilinx_pcs_ops={+.pcs_get_state=xilinx_pcs_get_state,+.pcs_config=xilinx_pcs_config,+.pcs_an_restart=xilinx_pcs_an_restart,+.pcs_link_up=xilinx_pcs_link_up,+};++staticintxilinx_pcs_probe(structmdio_device*mdiodev)+{+constchar*standard;+intret;+structxilinx_pcs*xp;+structdevice*dev=&mdiodev->dev;+structdevice_node*np=dev->of_node;+u32phy_id;++xp=devm_kzalloc(dev,sizeof(*xp),GFP_KERNEL);+if(!xp)+return-ENOMEM;+xp->mdiodev=mdiodev;+dev_set_drvdata(dev,xp);++ret=of_property_read_string(np,"standard",&standard);+if(ret)+returndev_err_probe(dev,ret,"could not read standard\n");++if(!strncmp(standard,"1000base-x",10))+xp->standard=XILINX_PCS_STD_1000BASEX;+elseif(!strncmp(standard,"sgmii/1000base-x",16))+xp->standard=XILINX_PCS_STD_BOTH;+elseif(!strncmp(standard,"sgmii",5))+xp->standard=XILINX_PCS_STD_SGMII;+elseif(!strncmp(standard,"2500base-x",10))+xp->standard=XILINX_PCS_STD_2500BASEX;+/* TODO: 2.5G SGMII support */+else+returndev_err_probe(dev,-EINVAL,+"unknown/unsupported standard %s\n",+standard);++xp->refclk=devm_clk_get(dev,"refclk");+if(IS_ERR(xp->refclk))+returndev_err_probe(dev,PTR_ERR(xp->refclk),+"could not get reference clock\n");++xp->reset=devm_reset_control_get_exclusive(dev,"pcs");+if(IS_ERR(xp->reset))+returndev_err_probe(dev,PTR_ERR(xp->reset),+"could not get reset\n");++ret=reset_control_assert(xp->reset);+if(ret)+returndev_err_probe(dev,ret,"could not enter reset\n");++ret=clk_prepare_enable(xp->refclk);+if(ret)+returndev_err_probe(dev,ret,+"could not enable reference clock\n");++ret=reset_control_deassert(xp->reset);+if(ret){+dev_err_probe(dev,ret,"could not exit reset\n");+gotoerr_unprepare;+}++/* Sanity check */+ret=get_phy_c22_id(mdiodev->bus,mdiodev->addr,&phy_id);+if(ret){+dev_err_probe(dev,ret,"could not read id\n");+gotoerr_unprepare;+}+if((phy_id&0xfffffff0)!=0x01740c00)+dev_warn(dev,"unknown phy id %x\n",phy_id);++xp->pcs.dev=dev;+xp->pcs.ops=&xilinx_pcs_ops;+xp->pcs.poll=true;+ret=phylink_register_pcs(&xp->pcs);+if(ret)+returndev_err_probe(dev,ret,"could not register PCS\n");+dev_info(dev,"probed (standard=%s)\n",standard);+return0;++err_unprepare:+clk_disable_unprepare(xp->refclk);+returnret;+}++staticvoidxilinx_pcs_remove(structmdio_device*mdiodev)+{+structxilinx_pcs*xp=dev_get_drvdata(&mdiodev->dev);++phylink_unregister_pcs(&xp->pcs);+reset_control_assert(xp->reset);+clk_disable_unprepare(xp->refclk);+}++staticconststructof_device_idxilinx_pcs_of_match[]={+{.compatible="xlnx,pcs-16.2",},+{},+};+MODULE_DEVICE_TABLE(of,xilinx_timer_of_match);++staticstructmdio_driverxilinx_pcs_driver={+.probe=xilinx_pcs_probe,+.remove=xilinx_pcs_remove,+.mdiodrv.driver={+.name="xilinx-pcs",+.of_match_table=of_match_ptr(xilinx_pcs_of_match),+},+};+mdio_module_driver(xilinx_pcs_driver);++MODULE_ALIAS("platform:xilinx-pcs");+MODULE_DESCRIPTION("Xilinx PCS driver");+MODULE_LICENSE("GPL v2");