Commit 5c26c1d6 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dpaa2-eth-add-MAC-PHY-support-through-phylink'

Ioana Ciornei says:

====================
dpaa2-eth: add MAC/PHY support through phylink

The dpaa2-eth driver now has support for connecting to its associated PHY
device found through standard OF bindings. The PHY interraction is handled
by PHYLINK and even though, at the moment, only RGMII_* phy modes are
supported by the driver, this is just the first step into adding the
necessary changes to support the entire spectrum of capabilities.

This comes after feedback on the initial DPAA2 MAC RFC submitted here:
https://lwn.net/Articles/791182/



The notable change is that now, the DPMAC is not a separate driver, and
communication between the DPMAC and DPNI no longer happens through
firmware. Rather, the DPMAC is now a set of API functions that other
net_device drivers (DPNI, DPSW, etc) can use for PHY management.

The change is incremental, because the DPAA2 architecture has many modes of
connecting net devices in hardware loopback (for example DPNI to DPNI).
Those operating modes do not have a DPMAC and phylink instance.

The documentation patch provides a more complete view of the software
architecture and the current implementation.

Changes in v2:
 - added patch 1/5 in order to fix module build
 - use -ENOTCONN as a proper return error of dprc_get_connection()
 - move the locks to rtnl outside of dpaa2_eth_[dis]connect_mac functions
 - remove setting supported/advertised from .validate()

Changes in v3:
 - remove an unused variable

Changes in v4:
 - use ERR_PTR instead of plain NULL
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e3b205b1 ecc5fe7d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -8,3 +8,4 @@ DPAA2 Documentation
   overview
   dpio-driver
   ethernet-driver
   mac-phy-support
+191 −0
Original line number Diff line number Diff line
.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>

=======================
DPAA2 MAC / PHY support
=======================

:Copyright: |copy| 2019 NXP

Overview
--------

The DPAA2 MAC / PHY support consists of a set of APIs that help DPAA2 network
drivers (dpaa2-eth, dpaa2-ethsw) interract with the PHY library.

DPAA2 Software Architecture
---------------------------

Among other DPAA2 objects, the fsl-mc bus exports DPNI objects (abstracting a
network interface) and DPMAC objects (abstracting a MAC). The dpaa2-eth driver
probes on the DPNI object and connects to and configures a DPMAC object with
the help of phylink.

Data connections may be established between a DPNI and a DPMAC, or between two
DPNIs. Depending on the connection type, the netif_carrier_[on/off] is handled
directly by the dpaa2-eth driver or by phylink.

.. code-block:: none

  Sources of abstracted link state information presented by the MC firmware

                                               +--------------------------------------+
  +------------+                  +---------+  |                           xgmac_mdio |
  | net_device |                  | phylink |--|  +-----+  +-----+  +-----+  +-----+  |
  +------------+                  +---------+  |  | PHY |  | PHY |  | PHY |  | PHY |  |
        |                             |        |  +-----+  +-----+  +-----+  +-----+  |
      +------------------------------------+   |                    External MDIO bus |
      |            dpaa2-eth               |   +--------------------------------------+
      +------------------------------------+
        |                             |                                           Linux
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        |                             |                                     MC firmware
        |              /|             V
  +----------+        / |       +----------+
  |          |       /  |       |          |
  |          |       |  |       |          |
  |   DPNI   |<------|  |<------|   DPMAC  |
  |          |       |  |       |          |
  |          |       \  |<---+  |          |
  +----------+        \ |    |  +----------+
                       \|    |
                             |
           +--------------------------------------+
           | MC firmware polling MAC PCS for link |
           |  +-----+  +-----+  +-----+  +-----+  |
           |  | PCS |  | PCS |  | PCS |  | PCS |  |
           |  +-----+  +-----+  +-----+  +-----+  |
           |                    Internal MDIO bus |
           +--------------------------------------+


Depending on an MC firmware configuration setting, each MAC may be in one of two modes:

- DPMAC_LINK_TYPE_FIXED: the link state management is handled exclusively by
  the MC firmware by polling the MAC PCS. Without the need to register a
  phylink instance, the dpaa2-eth driver will not bind to the connected dpmac
  object at all.

- DPMAC_LINK_TYPE_PHY: The MC firmware is left waiting for link state update
  events, but those are in fact passed strictly between the dpaa2-mac (based on
  phylink) and its attached net_device driver (dpaa2-eth, dpaa2-ethsw),
  effectively bypassing the firmware.

Implementation
--------------

At probe time or when a DPNI's endpoint is dynamically changed, the dpaa2-eth
is responsible to find out if the peer object is a DPMAC and if this is the
case, to integrate it with PHYLINK using the dpaa2_mac_connect() API, which
will do the following:

 - look up the device tree for PHYLINK-compatible of binding (phy-handle)
 - will create a PHYLINK instance associated with the received net_device
 - connect to the PHY using phylink_of_phy_connect()

The following phylink_mac_ops callback are implemented:

 - .validate() will populate the supported linkmodes with the MAC capabilities
   only when the phy_interface_t is RGMII_* (at the moment, this is the only
   link type supported by the driver).

 - .mac_config() will configure the MAC in the new configuration using the
   dpmac_set_link_state() MC firmware API.

 - .mac_link_up() / .mac_link_down() will update the MAC link using the same
   API described above.

At driver unbind() or when the DPNI object is disconnected from the DPMAC, the
dpaa2-eth driver calls dpaa2_mac_disconnect() which will, in turn, disconnect
from the PHY and destroy the PHYLINK instance.

In case of a DPNI-DPMAC connection, an 'ip link set dev eth0 up' would start
the following sequence of operations:

(1) phylink_start() called from .dev_open().
(2) The .mac_config() and .mac_link_up() callbacks are called by PHYLINK.
(3) In order to configure the HW MAC, the MC Firmware API
    dpmac_set_link_state() is called.
(4) The firmware will eventually setup the HW MAC in the new configuration.
(5) A netif_carrier_on() call is made directly from PHYLINK on the associated
    net_device.
(6) The dpaa2-eth driver handles the LINK_STATE_CHANGE irq in order to
    enable/disable Rx taildrop based on the pause frame settings.

.. code-block:: none

  +---------+               +---------+
  | PHYLINK |-------------->|  eth0   |
  +---------+           (5) +---------+
  (1) ^  |
      |  |
      |  v (2)
  +-----------------------------------+
  |             dpaa2-eth             |
  +-----------------------------------+
         |                    ^ (6)
         |                    |
         v (3)                |
  +---------+---------------+---------+
  |  DPMAC  |               |  DPNI   |
  +---------+               +---------+
  |            MC Firmware            |
  +-----------------------------------+
         |
         |
         v (4)
  +-----------------------------------+
  |             HW MAC                |
  +-----------------------------------+

In case of a DPNI-DPNI connection, a usual sequence of operations looks like
the following:

(1) ip link set dev eth0 up
(2) The dpni_enable() MC API called on the associated fsl_mc_device.
(3) ip link set dev eth1 up
(4) The dpni_enable() MC API called on the associated fsl_mc_device.
(5) The LINK_STATE_CHANGED irq is received by both instances of the dpaa2-eth
    driver because now the operational link state is up.
(6) The netif_carrier_on() is called on the exported net_device from
    link_state_update().

.. code-block:: none

  +---------+               +---------+
  |  eth0   |               |  eth1   |
  +---------+               +---------+
      |  ^                     ^  |
      |  |                     |  |
  (1) v  | (6)             (6) |  v (3)
  +---------+               +---------+
  |dpaa2-eth|               |dpaa2-eth|
  +---------+               +---------+
      |  ^                     ^  |
      |  |                     |  |
  (2) v  | (5)             (5) |  v (4)
  +---------+---------------+---------+
  |  DPNI   |               |  DPNI   |
  +---------+               +---------+
  |            MC Firmware            |
  +-----------------------------------+


Exported API
------------

Any DPAA2 driver that drivers endpoints of DPMAC objects should service its
_EVENT_ENDPOINT_CHANGED irq and connect/disconnect from the associated DPMAC
when necessary using the below listed API::

 - int dpaa2_mac_connect(struct dpaa2_mac *mac);
 - void dpaa2_mac_disconnect(struct dpaa2_mac *mac);

A phylink integration is necessary only when the partner DPMAC is not of TYPE_FIXED.
One can check for this condition using the below API::

 - bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev,struct fsl_mc_io *mc_io);

Before connection to a MAC, the caller must allocate and populate the
dpaa2_mac structure with the associated net_device, a pointer to the MC portal
to be used and the actual fsl_mc_device structure of the DPMAC.
+4 −0
Original line number Diff line number Diff line
@@ -5053,10 +5053,14 @@ M: Ioana Radulescu <ruxandra.radulescu@nxp.com>
L:	netdev@vger.kernel.org
S:	Maintained
F:	drivers/net/ethernet/freescale/dpaa2/dpaa2-eth*
F:	drivers/net/ethernet/freescale/dpaa2/dpaa2-mac*
F:	drivers/net/ethernet/freescale/dpaa2/dpni*
F:	drivers/net/ethernet/freescale/dpaa2/dpmac*
F:	drivers/net/ethernet/freescale/dpaa2/dpkg.h
F:	drivers/net/ethernet/freescale/dpaa2/Makefile
F:	drivers/net/ethernet/freescale/dpaa2/Kconfig
F:	Documentation/networking/device_drivers/freescale/dpaa2/ethernet-driver.rst
F:	Documentation/networking/device_drivers/freescale/dpaa2/mac-phy-support.rst
DPAA2 ETHERNET SWITCH DRIVER
M:	Ioana Radulescu <ruxandra.radulescu@nxp.com>
+2 −4
Original line number Diff line number Diff line
@@ -104,10 +104,8 @@ static int __fsl_mc_device_match(struct device *dev, void *data)
	return fsl_mc_device_match(mc_dev, obj_desc);
}

static struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc
								*obj_desc,
						  struct fsl_mc_device
								*mc_bus_dev)
struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
					   struct fsl_mc_device *mc_bus_dev)
{
	struct device *dev;

+53 −0
Original line number Diff line number Diff line
@@ -554,3 +554,56 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io,

	return 0;
}

/**
 * dprc_get_connection() - Get connected endpoint and link status if connection
 *			exists.
 * @mc_io:	Pointer to MC portal's I/O object
 * @cmd_flags:	Command flags; one or more of 'MC_CMD_FLAG_'
 * @token:	Token of DPRC object
 * @endpoint1:	Endpoint 1 configuration parameters
 * @endpoint2:	Returned endpoint 2 configuration parameters
 * @state:	Returned link state:
 *		1 - link is up;
 *		0 - link is down;
 *		-1 - no connection (endpoint2 information is irrelevant)
 *
 * Return:     '0' on Success; -ENOTCONN if connection does not exist.
 */
int dprc_get_connection(struct fsl_mc_io *mc_io,
			u32 cmd_flags,
			u16 token,
			const struct dprc_endpoint *endpoint1,
			struct dprc_endpoint *endpoint2,
			int *state)
{
	struct dprc_cmd_get_connection *cmd_params;
	struct dprc_rsp_get_connection *rsp_params;
	struct fsl_mc_command cmd = { 0 };
	int err, i;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION,
					  cmd_flags,
					  token);
	cmd_params = (struct dprc_cmd_get_connection *)cmd.params;
	cmd_params->ep1_id = cpu_to_le32(endpoint1->id);
	cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id);
	for (i = 0; i < 16; i++)
		cmd_params->ep1_type[i] = endpoint1->type[i];

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return -ENOTCONN;

	/* retrieve response parameters */
	rsp_params = (struct dprc_rsp_get_connection *)cmd.params;
	endpoint2->id = le32_to_cpu(rsp_params->ep2_id);
	endpoint2->if_id = le16_to_cpu(rsp_params->ep2_interface_id);
	*state = le32_to_cpu(rsp_params->state);
	for (i = 0; i < 16; i++)
		endpoint2->type[i] = rsp_params->ep2_type[i];

	return 0;
}
Loading