Commit f0168042 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: enetc: reimplement RFS/RSS memory clearing as PCI quirk

The workaround implemented in commit 3222b5b6 ("net: enetc:
initialize RFS/RSS memories for unused ports too") is no longer
effective after commit 6fffbc7a ("PCI: Honor firmware's device
disabled status"). Thus, it has introduced a regression and we see AER
errors being reported again:

$ ip link set sw2p0 up && dhclient -i sw2p0 && ip addr show sw2p0
fsl_enetc 0000:00:00.2 eno2: configuring for fixed/internal link mode
fsl_enetc 0000:00:00.2 eno2: Link is Up - 2.5Gbps/Full - flow control rx/tx
mscc_felix 0000:00:00.5 swp2: configuring for fixed/sgmii link mode
mscc_felix 0000:00:00.5 swp2: Link is Up - 1Gbps/Full - flow control off
sja1105 spi2.2 sw2p0: configuring for phy/rgmii-id link mode
sja1105 spi2.2 sw2p0: Link is Up - 1Gbps/Full - flow control off
pcieport 0000:00:1f.0: AER: Multiple Corrected error received: 0000:00:00.0
pcieport 0000:00:1f.0: AER: can't find device of ID0000

Rob's suggestion is to reimplement the enetc driver workaround as a
PCI fixup, and to modify the PCI core to run the fixups for all PCI
functions. This change handles the first part.

We refactor the common code in enetc_psi_create() and enetc_psi_destroy(),
and use the PCI fixup only for those functions for which enetc_pf_probe()
won't get called. This avoids some work being done twice for the PFs
which are enabled.

Fixes: 6fffbc7a ("PCI: Honor firmware's device disabled status")
Link: https://lore.kernel.org/netdev/CAL_JsqLsVYiPLx2kcHkDQ4t=hQVCR7NHziDwi9cCFUFhx48Qow@mail.gmail.com/Suggested-by: default avatarRob Herring <robh@kernel.org>
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1a8c251c
...@@ -1208,50 +1208,81 @@ static int enetc_pf_register_with_ierb(struct pci_dev *pdev) ...@@ -1208,50 +1208,81 @@ static int enetc_pf_register_with_ierb(struct pci_dev *pdev)
return enetc_ierb_register_pf(ierb_pdev, pdev); return enetc_ierb_register_pf(ierb_pdev, pdev);
} }
static int enetc_pf_probe(struct pci_dev *pdev, static struct enetc_si *enetc_psi_create(struct pci_dev *pdev)
const struct pci_device_id *ent)
{ {
struct device_node *node = pdev->dev.of_node;
struct enetc_ndev_priv *priv;
struct net_device *ndev;
struct enetc_si *si; struct enetc_si *si;
struct enetc_pf *pf;
int err; int err;
err = enetc_pf_register_with_ierb(pdev); err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(struct enetc_pf));
if (err == -EPROBE_DEFER) if (err) {
return err; dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
if (err) goto out;
dev_warn(&pdev->dev, }
"Could not register with IERB driver: %pe, please update the device tree\n",
ERR_PTR(err));
err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
if (err)
return dev_err_probe(&pdev->dev, err, "PCI probing failed\n");
si = pci_get_drvdata(pdev); si = pci_get_drvdata(pdev);
if (!si->hw.port || !si->hw.global) { if (!si->hw.port || !si->hw.global) {
err = -ENODEV; err = -ENODEV;
dev_err(&pdev->dev, "could not map PF space, probing a VF?\n"); dev_err(&pdev->dev, "could not map PF space, probing a VF?\n");
goto err_map_pf_space; goto out_pci_remove;
} }
err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE, err = enetc_setup_cbdr(&pdev->dev, &si->hw, ENETC_CBDR_DEFAULT_SIZE,
&si->cbd_ring); &si->cbd_ring);
if (err) if (err)
goto err_setup_cbdr; goto out_pci_remove;
err = enetc_init_port_rfs_memory(si); err = enetc_init_port_rfs_memory(si);
if (err) { if (err) {
dev_err(&pdev->dev, "Failed to initialize RFS memory\n"); dev_err(&pdev->dev, "Failed to initialize RFS memory\n");
goto err_init_port_rfs; goto out_teardown_cbdr;
} }
err = enetc_init_port_rss_memory(si); err = enetc_init_port_rss_memory(si);
if (err) { if (err) {
dev_err(&pdev->dev, "Failed to initialize RSS memory\n"); dev_err(&pdev->dev, "Failed to initialize RSS memory\n");
goto err_init_port_rss; goto out_teardown_cbdr;
}
return si;
out_teardown_cbdr:
enetc_teardown_cbdr(&si->cbd_ring);
out_pci_remove:
enetc_pci_remove(pdev);
out:
return ERR_PTR(err);
}
static void enetc_psi_destroy(struct pci_dev *pdev)
{
struct enetc_si *si = pci_get_drvdata(pdev);
enetc_teardown_cbdr(&si->cbd_ring);
enetc_pci_remove(pdev);
}
static int enetc_pf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device_node *node = pdev->dev.of_node;
struct enetc_ndev_priv *priv;
struct net_device *ndev;
struct enetc_si *si;
struct enetc_pf *pf;
int err;
err = enetc_pf_register_with_ierb(pdev);
if (err == -EPROBE_DEFER)
return err;
if (err)
dev_warn(&pdev->dev,
"Could not register with IERB driver: %pe, please update the device tree\n",
ERR_PTR(err));
si = enetc_psi_create(pdev);
if (IS_ERR(si)) {
err = PTR_ERR(si);
goto err_psi_create;
} }
if (node && !of_device_is_available(node)) { if (node && !of_device_is_available(node)) {
...@@ -1339,15 +1370,10 @@ static int enetc_pf_probe(struct pci_dev *pdev, ...@@ -1339,15 +1370,10 @@ static int enetc_pf_probe(struct pci_dev *pdev,
si->ndev = NULL; si->ndev = NULL;
free_netdev(ndev); free_netdev(ndev);
err_alloc_netdev: err_alloc_netdev:
err_init_port_rss:
err_init_port_rfs:
err_device_disabled: err_device_disabled:
err_setup_mac_addresses: err_setup_mac_addresses:
enetc_teardown_cbdr(&si->cbd_ring); enetc_psi_destroy(pdev);
err_setup_cbdr: err_psi_create:
err_map_pf_space:
enetc_pci_remove(pdev);
return err; return err;
} }
...@@ -1370,12 +1396,29 @@ static void enetc_pf_remove(struct pci_dev *pdev) ...@@ -1370,12 +1396,29 @@ static void enetc_pf_remove(struct pci_dev *pdev)
enetc_free_msix(priv); enetc_free_msix(priv);
enetc_free_si_resources(priv); enetc_free_si_resources(priv);
enetc_teardown_cbdr(&si->cbd_ring);
free_netdev(si->ndev); free_netdev(si->ndev);
enetc_pci_remove(pdev); enetc_psi_destroy(pdev);
}
static void enetc_fixup_clear_rss_rfs(struct pci_dev *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct enetc_si *si;
/* Only apply quirk for disabled functions. For the ones
* that are enabled, enetc_pf_probe() will apply it.
*/
if (node && of_device_is_available(node))
return;
si = enetc_psi_create(pdev);
if (si)
enetc_psi_destroy(pdev);
} }
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF,
enetc_fixup_clear_rss_rfs);
static const struct pci_device_id enetc_pf_id_table[] = { static const struct pci_device_id enetc_pf_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) }, { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF) },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment