Commit d0fe7104 authored by Alexander Duyck's avatar Alexander Duyck Committed by Paolo Abeni
Browse files

fbnic: Replace use of internal PCS w/ Designware XPCS



As we have exposed the PCS registers via the SWMII we can now start looking
at connecting the XPCS driver to those registers and let it mange the PCS
instead of us doing it directly from the fbnic driver.

For now this just gets us the ability to detect link. The hope is in the
future to add some of the vendor specific registers to begin enabling XPCS
configuration of the interface.

Signed-off-by: default avatarAlexander Duyck <alexanderduyck@fb.com>
Link: https://patch.msgid.link/176374325295.959489.14521115864034905277.stgit@ahduyck-xeon-server.home.arpa


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent d0ce9fd7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ config FBNIC
	depends on PTP_1588_CLOCK_OPTIONAL
	select NET_DEVLINK
	select PAGE_POOL
	select PCS_XPCS
	select PHYLINK
	select PLDMFW
	help
+1 −1
Original line number Diff line number Diff line
@@ -133,7 +133,7 @@ static irqreturn_t fbnic_mac_msix_intr(int __always_unused irq, void *data)

	/* Record link down events */
	if (!fbd->mac->get_link(fbd, fbn->aui, fbn->fec))
		phylink_pcs_change(&fbn->phylink_pcs, false);
		phylink_pcs_change(fbn->pcs, false);

	return IRQ_HANDLED;
}
+2 −5
Original line number Diff line number Diff line
@@ -697,10 +697,7 @@ void fbnic_reset_queues(struct fbnic_net *fbn,
 **/
void fbnic_netdev_free(struct fbnic_dev *fbd)
{
	struct fbnic_net *fbn = netdev_priv(fbd->netdev);

	if (fbn->phylink)
		phylink_destroy(fbn->phylink);
	fbnic_phylink_destroy(fbd->netdev);

	free_netdev(fbd->netdev);
	fbd->netdev = NULL;
@@ -802,7 +799,7 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)

	netif_tx_stop_all_queues(netdev);

	if (fbnic_phylink_init(netdev)) {
	if (fbnic_phylink_create(netdev)) {
		fbnic_netdev_free(fbd);
		return NULL;
	}
+3 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ struct fbnic_net {

	struct phylink *phylink;
	struct phylink_config phylink_config;
	struct phylink_pcs phylink_pcs;
	struct phylink_pcs *pcs;

	u8 aui;
	u8 fec;
@@ -108,6 +108,8 @@ int fbnic_phylink_ethtool_ksettings_get(struct net_device *netdev,
					struct ethtool_link_ksettings *cmd);
int fbnic_phylink_get_fecparam(struct net_device *netdev,
			       struct ethtool_fecparam *fecparam);
int fbnic_phylink_create(struct net_device *netdev);
void fbnic_phylink_destroy(struct net_device *netdev);
int fbnic_phylink_init(struct net_device *netdev);
void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev);
bool fbnic_check_split_frames(struct bpf_prog *prog,
+48 −56
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */

#include <linux/pcs/pcs-xpcs.h>
#include <linux/phy.h>
#include <linux/phylink.h>

@@ -101,56 +102,6 @@ int fbnic_phylink_get_fecparam(struct net_device *netdev,
	return 0;
}

static struct fbnic_net *
fbnic_pcs_to_net(struct phylink_pcs *pcs)
{
	return container_of(pcs, struct fbnic_net, phylink_pcs);
}

static void
fbnic_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
			    struct phylink_link_state *state)
{
	struct fbnic_net *fbn = fbnic_pcs_to_net(pcs);
	struct fbnic_dev *fbd = fbn->fbd;

	switch (fbn->aui) {
	case FBNIC_AUI_25GAUI:
		state->speed = SPEED_25000;
		break;
	case FBNIC_AUI_LAUI2:
	case FBNIC_AUI_50GAUI1:
		state->speed = SPEED_50000;
		break;
	case FBNIC_AUI_100GAUI2:
		state->speed = SPEED_100000;
		break;
	default:
		state->link = 0;
		return;
	}

	state->duplex = DUPLEX_FULL;

	state->link = (fbd->pmd_state == FBNIC_PMD_SEND_DATA) &&
		      (rd32(fbd, FBNIC_PCS(MDIO_STAT1, 0)) &
		       MDIO_STAT1_LSTATUS);
}

static int
fbnic_phylink_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
			 phy_interface_t interface,
			 const unsigned long *advertising,
			 bool permit_pause_to_mac)
{
	return 0;
}

static const struct phylink_pcs_ops fbnic_phylink_pcs_ops = {
	.pcs_config = fbnic_phylink_pcs_config,
	.pcs_get_state = fbnic_phylink_pcs_get_state,
};

static struct phylink_pcs *
fbnic_phylink_mac_select_pcs(struct phylink_config *config,
			     phy_interface_t interface)
@@ -158,7 +109,7 @@ fbnic_phylink_mac_select_pcs(struct phylink_config *config,
	struct net_device *netdev = to_net_dev(config->dev);
	struct fbnic_net *fbn = netdev_priv(netdev);

	return &fbn->phylink_pcs;
	return fbn->pcs;
}

static int
@@ -232,13 +183,33 @@ static const struct phylink_mac_ops fbnic_phylink_mac_ops = {
	.mac_link_up = fbnic_phylink_mac_link_up,
};

int fbnic_phylink_init(struct net_device *netdev)
/**
 * fbnic_phylink_create - Phylink device creation
 * @netdev: Network Device struct to attach phylink device
 *
 * Initialize and attach a phylink instance to the device. The phylink
 * device will make use of the netdev struct to track carrier and will
 * eventually be used to expose the current state of the MAC and PCS
 * setup.
 *
 * Return: 0 on success, negative on failure
 **/
int fbnic_phylink_create(struct net_device *netdev)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	struct fbnic_dev *fbd = fbn->fbd;
	struct phylink_pcs *pcs;
	struct phylink *phylink;
	int err;

	pcs = xpcs_create_pcs_mdiodev(fbd->mdio_bus, 0);
	if (IS_ERR(pcs)) {
		err = PTR_ERR(pcs);
		dev_err(fbd->dev, "Failed to create PCS device: %d\n", err);
		return err;
	}

	fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops;
	fbn->pcs = pcs;

	fbn->phylink_config.dev = &netdev->dev;
	fbn->phylink_config.type = PHYLINK_NETDEV;
@@ -261,14 +232,35 @@ int fbnic_phylink_init(struct net_device *netdev)
	phylink = phylink_create(&fbn->phylink_config, NULL,
				 fbnic_phylink_select_interface(fbn->aui),
				 &fbnic_phylink_mac_ops);
	if (IS_ERR(phylink))
		return PTR_ERR(phylink);
	if (IS_ERR(phylink)) {
		err = PTR_ERR(phylink);
		dev_err(netdev->dev.parent,
			"Failed to create Phylink interface, err: %d\n", err);
		xpcs_destroy_pcs(pcs);
		return err;
	}

	fbn->phylink = phylink;

	return 0;
}

/**
 * fbnic_phylink_destroy - Teardown phylink related interfaces
 * @netdev: Network Device struct containing phylink device
 *
 * Detach and free resources related to phylink interface.
 **/
void fbnic_phylink_destroy(struct net_device *netdev)
{
	struct fbnic_net *fbn = netdev_priv(netdev);

	if (fbn->phylink)
		phylink_destroy(fbn->phylink);
	if (fbn->pcs)
		xpcs_destroy_pcs(fbn->pcs);
}

/**
 * fbnic_phylink_pmd_training_complete_notify - PMD training complete notifier
 * @netdev: Netdev struct phylink device attached to
@@ -315,5 +307,5 @@ void fbnic_phylink_pmd_training_complete_notify(struct net_device *netdev)
		    FBNIC_PMD_SEND_DATA) != FBNIC_PMD_LINK_READY)
		return;

	phylink_pcs_change(&fbn->phylink_pcs, false);
	phylink_pcs_change(fbn->pcs, false);
}