Commit 6ed33c13 authored by David S. Miller's avatar David S. Miller

Merge branch 'enetc-flow-control'

Vladimir Oltean says:

====================
Flow control for NXP ENETC

This patch series contains logic for enabling the lossless mode on the
RX rings of the ENETC, and the PAUSE thresholds on the internal FIFO
memory.

During testing it was found that, with the default FIFO configuration,
a sender which isn't persuaded by our PAUSE frames and keeps sending
will cause some MAC RX frame errors. To mitigate this, we need to ensure
that the FIFO never runs completely full, so we need to fix up a setting
that was supposed to be configured well out of reset. Unfortunately this
requires the addition of a new mini-driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c1d9e34e a8648887
......@@ -102,3 +102,18 @@ Example:
full-duplex;
};
};
* Integrated Endpoint Register Block bindings
Optionally, the fsl_enetc driver can probe on the Integrated Endpoint Register
Block, which preconfigures the FIFO limits for the ENETC ports. This is a node
with the following properties:
- reg : Specifies the address in the SoC memory space.
- compatible : Must be "fsl,ls1028a-enetc-ierb".
Example:
ierb@1f0800000 {
compatible = "fsl,ls1028a-enetc-ierb";
reg = <0x01 0xf0800000 0x0 0x10000>;
};
......@@ -1116,6 +1116,12 @@ fixed-link {
};
};
/* Integrated Endpoint Register Block */
ierb@1f0800000 {
compatible = "fsl,ls1028a-enetc-ierb";
reg = <0x01 0xf0800000 0x0 0x10000>;
};
rcpm: power-controller@1e34040 {
compatible = "fsl,ls1028a-rcpm", "fsl,qoriq-rcpm-2.1+";
reg = <0x0 0x1e34040 0x0 0x1c>;
......
......@@ -2,6 +2,7 @@
config FSL_ENETC
tristate "ENETC PF driver"
depends on PCI && PCI_MSI
depends on FSL_ENETC_IERB || FSL_ENETC_IERB=n
select FSL_ENETC_MDIO
select PHYLINK
select PCS_LYNX
......@@ -25,6 +26,14 @@ config FSL_ENETC_VF
If compiled as module (M), the module name is fsl-enetc-vf.
config FSL_ENETC_IERB
tristate "ENETC IERB driver"
help
This driver configures the Integrated Endpoint Register Block on NXP
LS1028A.
If compiled as module (M), the module name is fsl-enetc-ierb.
config FSL_ENETC_MDIO
tristate "ENETC MDIO driver"
depends on PCI && MDIO_DEVRES && MDIO_BUS
......
......@@ -11,6 +11,9 @@ obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o
fsl-enetc-vf-y := enetc_vf.o $(common-objs)
fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o
obj-$(CONFIG_FSL_ENETC_IERB) += fsl-enetc-ierb.o
fsl-enetc-ierb-y := enetc_ierb.o
obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o
fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o
......
......@@ -237,6 +237,22 @@ static inline bool enetc_si_is_pf(struct enetc_si *si)
return !!(si->hw.port);
}
static inline int enetc_pf_to_port(struct pci_dev *pf_pdev)
{
switch (pf_pdev->devfn) {
case 0:
return 0;
case 1:
return 1;
case 2:
return 2;
case 6:
return 3;
default:
return -1;
}
}
#define ENETC_MAX_NUM_TXQS 8
#define ENETC_INT_NAME_MAX (IFNAMSIZ + 8)
......
......@@ -708,6 +708,22 @@ static int enetc_set_wol(struct net_device *dev,
return ret;
}
static void enetc_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct enetc_ndev_priv *priv = netdev_priv(dev);
phylink_ethtool_get_pauseparam(priv->phylink, pause);
}
static int enetc_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
struct enetc_ndev_priv *priv = netdev_priv(dev);
return phylink_ethtool_set_pauseparam(priv->phylink, pause);
}
static int enetc_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
......@@ -754,6 +770,8 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
.get_ts_info = enetc_get_ts_info,
.get_wol = enetc_get_wol,
.set_wol = enetc_set_wol,
.get_pauseparam = enetc_get_pauseparam,
.set_pauseparam = enetc_set_pauseparam,
};
static const struct ethtool_ops enetc_vf_ethtool_ops = {
......
......@@ -109,6 +109,7 @@ enum enetc_bdr_type {TX, RX};
/* RX BDR reg offsets */
#define ENETC_RBMR 0
#define ENETC_RBMR_BDS BIT(2)
#define ENETC_RBMR_CM BIT(4)
#define ENETC_RBMR_VTE BIT(5)
#define ENETC_RBMR_EN BIT(31)
#define ENETC_RBSR 0x4
......@@ -180,6 +181,8 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PSIVLANR(n) (0x0240 + (n) * 4) /* n = SI index */
#define ENETC_PSIVLAN_EN BIT(31)
#define ENETC_PSIVLAN_SET_QOS(val) ((u32)(val) << 12)
#define ENETC_PPAUONTR 0x0410
#define ENETC_PPAUOFFTR 0x0414
#define ENETC_PTXMBAR 0x0608
#define ENETC_PCAPR0 0x0900
#define ENETC_PCAPR0_RXBDR(val) ((val) >> 24)
......@@ -227,6 +230,7 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM0_TX_EN BIT(0)
#define ENETC_PM0_RX_EN BIT(1)
#define ENETC_PM0_PROMISC BIT(4)
#define ENETC_PM0_PAUSE_IGN BIT(8)
#define ENETC_PM0_CMD_XGLP BIT(10)
#define ENETC_PM0_CMD_TXP BIT(11)
#define ENETC_PM0_CMD_PHY_TX_EN BIT(15)
......@@ -239,6 +243,11 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PM_IMDIO_BASE 0x8030
#define ENETC_PM0_PAUSE_QUANTA 0x8054
#define ENETC_PM0_PAUSE_THRESH 0x8064
#define ENETC_PM1_PAUSE_QUANTA 0x9054
#define ENETC_PM1_PAUSE_THRESH 0x9064
#define ENETC_PM0_SINGLE_STEP 0x80c0
#define ENETC_PM1_SINGLE_STEP 0x90c0
#define ENETC_PM0_SINGLE_STEP_CH BIT(7)
......
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2021 NXP Semiconductors
*
* The Integrated Endpoint Register Block (IERB) is configured by pre-boot
* software and is supposed to be to ENETC what a NVRAM is to a 'real' PCIe
* card. Upon FLR, values from the IERB are transferred to the ENETC PFs, and
* are read-only in the PF memory space.
*
* This driver fixes up the power-on reset values for the ENETC shared FIFO,
* such that the TX and RX allocations are sufficient for jumbo frames, and
* that intelligent FIFO dropping is enabled before the internal data
* structures are corrupted.
*
* Even though not all ports might be used on a given board, we are not
* concerned with partitioning the FIFO, because the default values configure
* no strict reservations, so the entire FIFO can be used by the RX of a single
* port, or the TX of a single port.
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include "enetc.h"
#include "enetc_ierb.h"
/* IERB registers */
#define ENETC_IERB_TXMBAR(port) (((port) * 0x100) + 0x8080)
#define ENETC_IERB_RXMBER(port) (((port) * 0x100) + 0x8090)
#define ENETC_IERB_RXMBLR(port) (((port) * 0x100) + 0x8094)
#define ENETC_IERB_RXBCR(port) (((port) * 0x100) + 0x80a0)
#define ENETC_IERB_TXBCR(port) (((port) * 0x100) + 0x80a8)
#define ENETC_IERB_FMBDTR 0xa000
#define ENETC_RESERVED_FOR_ICM 1024
struct enetc_ierb {
void __iomem *regs;
};
static void enetc_ierb_write(struct enetc_ierb *ierb, u32 offset, u32 val)
{
iowrite32(val, ierb->regs + offset);
}
int enetc_ierb_register_pf(struct platform_device *pdev,
struct pci_dev *pf_pdev)
{
struct enetc_ierb *ierb = platform_get_drvdata(pdev);
int port = enetc_pf_to_port(pf_pdev);
u16 tx_credit, rx_credit, tx_alloc;
if (port < 0)
return -ENODEV;
if (!ierb)
return -EPROBE_DEFER;
/* By default, it is recommended to set the Host Transfer Agent
* per port transmit byte credit to "1000 + max_frame_size/2".
* The power-on reset value (1800 bytes) is rounded up to the nearest
* 100 assuming a maximum frame size of 1536 bytes.
*/
tx_credit = roundup(1000 + ENETC_MAC_MAXFRM_SIZE / 2, 100);
/* Internal memory allocated for transmit buffering is guaranteed but
* not reserved; i.e. if the total transmit allocation is not used,
* then the unused portion is not left idle, it can be used for receive
* buffering but it will be reclaimed, if required, from receive by
* intelligently dropping already stored receive frames in the internal
* memory to ensure that the transmit allocation is respected.
*
* PaTXMBAR must be set to a value larger than
* PaTXBCR + 2 * max_frame_size + 32
* if frame preemption is not enabled, or to
* 2 * PaTXBCR + 2 * p_max_frame_size (pMAC maximum frame size) +
* 2 * np_max_frame_size (eMAC maximum frame size) + 64
* if frame preemption is enabled.
*/
tx_alloc = roundup(2 * tx_credit + 4 * ENETC_MAC_MAXFRM_SIZE + 64, 16);
/* Initial credits, in units of 8 bytes, to the Ingress Congestion
* Manager for the maximum amount of bytes the port is allocated for
* pending traffic.
* It is recommended to set the initial credits to 2 times the maximum
* frame size (2 frames of maximum size).
*/
rx_credit = DIV_ROUND_UP(ENETC_MAC_MAXFRM_SIZE * 2, 8);
enetc_ierb_write(ierb, ENETC_IERB_TXBCR(port), tx_credit);
enetc_ierb_write(ierb, ENETC_IERB_TXMBAR(port), tx_alloc);
enetc_ierb_write(ierb, ENETC_IERB_RXBCR(port), rx_credit);
return 0;
}
EXPORT_SYMBOL(enetc_ierb_register_pf);
static int enetc_ierb_probe(struct platform_device *pdev)
{
struct enetc_ierb *ierb;
struct resource *res;
void __iomem *regs;
ierb = devm_kzalloc(&pdev->dev, sizeof(*ierb), GFP_KERNEL);
if (!ierb)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
ierb->regs = regs;
/* Free buffer depletion threshold in bytes.
* This sets the minimum amount of free buffer memory that should be
* maintained in the datapath sub system, and when the amount of free
* buffer memory falls below this threshold, a depletion indication is
* asserted, which may trigger "intelligent drop" frame releases from
* the ingress queues in the ICM.
* It is recommended to set the free buffer depletion threshold to 1024
* bytes, since the ICM needs some FIFO memory for its own use.
*/
enetc_ierb_write(ierb, ENETC_IERB_FMBDTR, ENETC_RESERVED_FOR_ICM);
platform_set_drvdata(pdev, ierb);
return 0;
}
static int enetc_ierb_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id enetc_ierb_match[] = {
{ .compatible = "fsl,ls1028a-enetc-ierb", },
{},
};
MODULE_DEVICE_TABLE(of, enetc_ierb_match);
static struct platform_driver enetc_ierb_driver = {
.driver = {
.name = "fsl-enetc-ierb",
.of_match_table = enetc_ierb_match,
},
.probe = enetc_ierb_probe,
.remove = enetc_ierb_remove,
};
module_platform_driver(enetc_ierb_driver);
MODULE_DESCRIPTION("NXP ENETC IERB");
MODULE_LICENSE("Dual BSD/GPL");
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
/* Copyright 2021 NXP Semiconductors */
#include <linux/pci.h>
#include <linux/platform_device.h>
#if IS_ENABLED(CONFIG_FSL_ENETC_IERB)
int enetc_ierb_register_pf(struct platform_device *pdev,
struct pci_dev *pf_pdev);
#else
static inline int enetc_ierb_register_pf(struct platform_device *pdev,
struct pci_dev *pf_pdev)
{
return -EOPNOTSUPP;
}
#endif
......@@ -4,8 +4,10 @@
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/fsl/enetc_mdio.h>
#include <linux/of_platform.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include "enetc_ierb.h"
#include "enetc_pf.h"
#define ENETC_DRV_NAME_STR "ENETC PF driver"
......@@ -518,7 +520,6 @@ static void enetc_configure_port_mac(struct enetc_hw *hw)
ENETC_SET_MAXFRM(ENETC_RX_MAXFRM_SIZE));
enetc_port_wr(hw, ENETC_PTCMSDUR(0), ENETC_MAC_MAXFRM_SIZE);
enetc_port_wr(hw, ENETC_PTXMBAR, 2 * ENETC_MAC_MAXFRM_SIZE);
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, ENETC_PM0_CMD_PHY_TX_EN |
ENETC_PM0_CMD_TXP | ENETC_PM0_PROMISC);
......@@ -1013,7 +1014,12 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
int duplex, bool tx_pause, bool rx_pause)
{
struct enetc_pf *pf = phylink_to_enetc_pf(config);
u32 pause_off_thresh = 0, pause_on_thresh = 0;
u32 init_quanta = 0, refresh_quanta = 0;
struct enetc_hw *hw = &pf->si->hw;
struct enetc_ndev_priv *priv;
u32 rbmr, cmd_cfg;
int idx;
priv = netdev_priv(pf->si->ndev);
if (priv->active_offloads & ENETC_F_QBV)
......@@ -1021,9 +1027,60 @@ static void enetc_pl_mac_link_up(struct phylink_config *config,
if (!phylink_autoneg_inband(mode) &&
phy_interface_mode_is_rgmii(interface))
enetc_force_rgmii_mac(&pf->si->hw, speed, duplex);
enetc_force_rgmii_mac(hw, speed, duplex);
/* Flow control */
for (idx = 0; idx < priv->num_rx_rings; idx++) {
rbmr = enetc_rxbdr_rd(hw, idx, ENETC_RBMR);
if (tx_pause)
rbmr |= ENETC_RBMR_CM;
else
rbmr &= ~ENETC_RBMR_CM;
enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
}
if (tx_pause) {
/* When the port first enters congestion, send a PAUSE request
* with the maximum number of quanta. When the port exits
* congestion, it will automatically send a PAUSE frame with
* zero quanta.
*/
init_quanta = 0xffff;
/* Also, set up the refresh timer to send follow-up PAUSE
* frames at half the quanta value, in case the congestion
* condition persists.
*/
refresh_quanta = 0xffff / 2;
/* Start emitting PAUSE frames when 3 large frames (or more
* smaller frames) have accumulated in the FIFO waiting to be
* DMAed to the RX ring.
*/
pause_on_thresh = 3 * ENETC_MAC_MAXFRM_SIZE;
pause_off_thresh = 1 * ENETC_MAC_MAXFRM_SIZE;
}
enetc_port_wr(hw, ENETC_PM0_PAUSE_QUANTA, init_quanta);
enetc_port_wr(hw, ENETC_PM1_PAUSE_QUANTA, init_quanta);
enetc_port_wr(hw, ENETC_PM0_PAUSE_THRESH, refresh_quanta);
enetc_port_wr(hw, ENETC_PM1_PAUSE_THRESH, refresh_quanta);
enetc_port_wr(hw, ENETC_PPAUONTR, pause_on_thresh);
enetc_port_wr(hw, ENETC_PPAUOFFTR, pause_off_thresh);
cmd_cfg = enetc_port_rd(hw, ENETC_PM0_CMD_CFG);
if (rx_pause)
cmd_cfg &= ~ENETC_PM0_PAUSE_IGN;
else
cmd_cfg |= ENETC_PM0_PAUSE_IGN;
enetc_port_wr(hw, ENETC_PM0_CMD_CFG, cmd_cfg);
enetc_port_wr(hw, ENETC_PM1_CMD_CFG, cmd_cfg);
enetc_mac_enable(&pf->si->hw, true);
enetc_mac_enable(hw, true);
}
static void enetc_pl_mac_link_down(struct phylink_config *config,
......@@ -1115,6 +1172,30 @@ static int enetc_init_port_rss_memory(struct enetc_si *si)
return err;
}
static int enetc_pf_register_with_ierb(struct pci_dev *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct platform_device *ierb_pdev;
struct device_node *ierb_node;
/* Don't register with the IERB if the PF itself is disabled */
if (!node || !of_device_is_available(node))
return 0;
ierb_node = of_find_compatible_node(NULL, NULL,
"fsl,ls1028a-enetc-ierb");
if (!ierb_node || !of_device_is_available(ierb_node))
return -ENODEV;
ierb_pdev = of_find_device_by_node(ierb_node);
of_node_put(ierb_node);
if (!ierb_pdev)
return -EPROBE_DEFER;
return enetc_ierb_register_pf(ierb_pdev, pdev);
}
static int enetc_pf_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
......@@ -1125,6 +1206,14 @@ static int enetc_pf_probe(struct pci_dev *pdev,
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));
err = enetc_pci_probe(pdev, KBUILD_MODNAME, sizeof(*pf));
if (err) {
dev_err(&pdev->dev, "PCI probing failed\n");
......
......@@ -455,11 +455,6 @@ static struct enetc_psfp epsfp = {
static LIST_HEAD(enetc_block_cb_list);
static inline int enetc_get_port(struct enetc_ndev_priv *priv)
{
return priv->si->pdev->devfn & 0x7;
}
/* Stream Identity Entry Set Descriptor */
static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
struct enetc_streamid *sid,
......@@ -504,7 +499,7 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
si_conf = &cbd.sid_set;
/* Only one port supported for one entry, set itself */
si_conf->iports = cpu_to_le32(1 << enetc_get_port(priv));
si_conf->iports = cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
si_conf->id_type = 1;
si_conf->oui[2] = 0x0;
si_conf->oui[1] = 0x80;
......@@ -529,7 +524,7 @@ static int enetc_streamid_hw_set(struct enetc_ndev_priv *priv,
si_conf->en = 0x80;
si_conf->stream_handle = cpu_to_le32(sid->handle);
si_conf->iports = cpu_to_le32(1 << enetc_get_port(priv));
si_conf->iports = cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
si_conf->id_type = sid->filtertype;
si_conf->oui[2] = 0x0;
si_conf->oui[1] = 0x80;
......@@ -591,7 +586,8 @@ static int enetc_streamfilter_hw_set(struct enetc_ndev_priv *priv,
}
sfi_config->sg_inst_table_index = cpu_to_le16(sfi->gate_id);
sfi_config->input_ports = cpu_to_le32(1 << enetc_get_port(priv));
sfi_config->input_ports =
cpu_to_le32(1 << enetc_pf_to_port(priv->si->pdev));
/* The priority value which may be matched against the
* frame’s priority value to determine a match for this entry.
......@@ -1562,10 +1558,10 @@ int enetc_setup_tc_psfp(struct net_device *ndev, void *type_data)
switch (f->command) {
case FLOW_BLOCK_BIND:
set_bit(enetc_get_port(priv), &epsfp.dev_bitmap);
set_bit(enetc_pf_to_port(priv->si->pdev), &epsfp.dev_bitmap);
break;
case FLOW_BLOCK_UNBIND:
clear_bit(enetc_get_port(priv), &epsfp.dev_bitmap);
clear_bit(enetc_pf_to_port(priv->si->pdev), &epsfp.dev_bitmap);
if (!epsfp.dev_bitmap)
clean_psfp_all();
break;
......
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