mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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: Alexander Duyck <alexanderduyck@fb.com> Link: https://patch.msgid.link/176374325295.959489.14521115864034905277.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
committed by
Paolo Abeni
parent
d0ce9fd7ea
commit
d0fe7104c7
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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;
|
||||
|
||||
fbn->phylink_pcs.ops = &fbnic_phylink_pcs_ops;
|
||||
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->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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user