mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
net: dsa: netc: initialize buffer pool table and implement flow-control
The buffer pool is a quantity of memory available for buffering a group of flows (e.g. frames having the same priority, frames received from the same port), while waiting to be transmitted on a port. The buffer pool tracks internal memory consumption with upper bound limits and optionally a non-shared portion when associated with a shared buffer pool. Currently the shared buffer pool is not supported, it will be added in the future. For i.MX94, the switch has 4 ports and 8 buffer pools, so each port is allocated two buffer pools. For frames with priorities of 0 to 3, they will be mapped to the first buffer pool; For frames with priorities of 4 to 7, they will be mapped to the second buffer pool. Each buffer pool has a flow control on threshold and a flow control off threshold. By setting these threshold, add the flow control support to each port. Signed-off-by: Wei Fang <wei.fang@nxp.com> Link: https://patch.msgid.link/20260518082506.1318236-14-wei.fang@nxp.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
46d6407692
commit
a5ccb7f5e0
|
|
@ -212,6 +212,9 @@ static void netc_get_switch_capabilities(struct netc_switch *priv)
|
|||
|
||||
val = netc_base_rd(regs, NETC_HTMCAPR);
|
||||
priv->htmcapr_num_words = FIELD_GET(HTMCAPR_NUM_WORDS, val);
|
||||
|
||||
val = netc_base_rd(regs, NETC_BPCAPR);
|
||||
priv->num_bp = FIELD_GET(BPCAPR_NUM_BP, val);
|
||||
}
|
||||
|
||||
static int netc_init_all_ports(struct netc_switch *priv)
|
||||
|
|
@ -403,6 +406,15 @@ static void netc_port_fixed_config(struct netc_port *np)
|
|||
/* Enable L2 and L3 DOS */
|
||||
netc_port_rmw(np, NETC_PCR, PCR_L2DOSE | PCR_L3DOSE,
|
||||
PCR_L2DOSE | PCR_L3DOSE);
|
||||
|
||||
/* Set the quanta value of TX PAUSE frame */
|
||||
netc_mac_port_wr(np, NETC_PM_PAUSE_QUANTA(0), NETC_PAUSE_QUANTA);
|
||||
|
||||
/* When a quanta timer counts down and reaches this value,
|
||||
* the MAC sends a refresh PAUSE frame with the programmed
|
||||
* full quanta value if a pause condition still exists.
|
||||
*/
|
||||
netc_mac_port_wr(np, NETC_PM_PAUSE_THRESH(0), NETC_PAUSE_THRESH);
|
||||
}
|
||||
|
||||
static void netc_port_default_config(struct netc_port *np)
|
||||
|
|
@ -636,6 +648,79 @@ static int netc_add_standalone_fdb_bcast_entry(struct netc_switch *priv)
|
|||
bcast, NETC_STANDALONE_PVID);
|
||||
}
|
||||
|
||||
static void netc_port_set_pbpmcr(struct netc_port *np, u64 mapping)
|
||||
{
|
||||
u32 pbpmcr0 = lower_32_bits(mapping);
|
||||
u32 pbpmcr1 = upper_32_bits(mapping);
|
||||
|
||||
netc_port_wr(np, NETC_PBPMCR0, pbpmcr0);
|
||||
netc_port_wr(np, NETC_PBPMCR1, pbpmcr1);
|
||||
}
|
||||
|
||||
static void netc_ipv_to_buffer_pool_mapping(struct netc_switch *priv)
|
||||
{
|
||||
int bp_per_port = priv->num_bp / priv->info->num_ports;
|
||||
int q = NETC_IPV_NUM / bp_per_port;
|
||||
int r = NETC_IPV_NUM % bp_per_port;
|
||||
int num = q + r;
|
||||
|
||||
/* IPV-to-buffer-pool mapping per port:
|
||||
* Each port is allocated 'bp_per_port' buffer pools and supports 8
|
||||
* IPVs, where a higher IPV indicates a higher frame priority. Each
|
||||
* IPV can be mapped to only one buffer pool, from hardware design
|
||||
* perspective, bp_per_port will not be greater than 8. So 'q' will
|
||||
* not be 0.
|
||||
*
|
||||
* The mapping rule is as follows:
|
||||
* - The first 'num' IPVs share the port's first buffer pool (index
|
||||
* 'base_id').
|
||||
* - After that, every 'q' IPVs share one buffer pool, with pool
|
||||
* indices increasing sequentially.
|
||||
*/
|
||||
for (int i = 0; i < priv->info->num_ports; i++) {
|
||||
u32 base_id = i * bp_per_port;
|
||||
u32 bp_id = base_id;
|
||||
u64 mapping = 0;
|
||||
|
||||
for (int ipv = 0; ipv < NETC_IPV_NUM; ipv++) {
|
||||
/* Update the buffer pool index */
|
||||
if (ipv >= num)
|
||||
bp_id = base_id + ((ipv - num) / q) + 1;
|
||||
|
||||
mapping |= (u64)bp_id << (ipv * 8);
|
||||
}
|
||||
|
||||
netc_port_set_pbpmcr(priv->ports[i], mapping);
|
||||
}
|
||||
}
|
||||
|
||||
static int netc_switch_bpt_default_config(struct netc_switch *priv)
|
||||
{
|
||||
if (priv->num_bp < priv->info->num_ports)
|
||||
return -EINVAL;
|
||||
|
||||
priv->bpt_list = devm_kcalloc(priv->dev, priv->num_bp,
|
||||
sizeof(struct bpt_cfge_data),
|
||||
GFP_KERNEL);
|
||||
if (!priv->bpt_list)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize the maximum threshold of each buffer pool entry */
|
||||
for (int i = 0; i < priv->num_bp; i++) {
|
||||
struct bpt_cfge_data *cfge = &priv->bpt_list[i];
|
||||
int err;
|
||||
|
||||
cfge->max_thresh = cpu_to_le16(NETC_BP_THRESH);
|
||||
err = ntmp_bpt_update_entry(&priv->ntmp, i, cfge);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
netc_ipv_to_buffer_pool_mapping(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netc_setup(struct dsa_switch *ds)
|
||||
{
|
||||
struct netc_switch *priv = ds->priv;
|
||||
|
|
@ -665,6 +750,10 @@ static int netc_setup(struct dsa_switch *ds)
|
|||
dsa_switch_for_each_available_port(dp, ds)
|
||||
netc_port_default_config(priv->ports[dp->index]);
|
||||
|
||||
err = netc_switch_bpt_default_config(priv);
|
||||
if (err)
|
||||
goto free_lock_and_ntmp_user;
|
||||
|
||||
err = netc_add_standalone_vlan_entry(priv);
|
||||
if (err)
|
||||
goto free_lock_and_ntmp_user;
|
||||
|
|
@ -1218,6 +1307,45 @@ static void netc_port_set_rmii_mii_mac(struct netc_port *np,
|
|||
netc_mac_port_rmw(np, NETC_PM_IF_MODE(0), mask, val);
|
||||
}
|
||||
|
||||
static void netc_port_set_tx_pause(struct netc_port *np, bool tx_pause)
|
||||
{
|
||||
struct netc_switch *priv = np->switch_priv;
|
||||
int port = np->dp->index;
|
||||
int i, j, num_bp;
|
||||
|
||||
num_bp = priv->num_bp / priv->info->num_ports;
|
||||
for (i = 0, j = port * num_bp; i < num_bp; i++, j++) {
|
||||
struct bpt_cfge_data *cfge = &priv->bpt_list[j];
|
||||
struct bpt_cfge_data old_cfge = *cfge;
|
||||
|
||||
if (tx_pause) {
|
||||
cfge->fc_on_thresh = cpu_to_le16(NETC_FC_THRESH_ON);
|
||||
cfge->fc_off_thresh = cpu_to_le16(NETC_FC_THRESH_OFF);
|
||||
cfge->fccfg_sbpen = FIELD_PREP(BPT_FC_CFG,
|
||||
BPT_FC_CFG_EN_BPFC);
|
||||
cfge->fc_ports = cpu_to_le32(BIT(port));
|
||||
} else {
|
||||
cfge->fc_on_thresh = cpu_to_le16(0);
|
||||
cfge->fc_off_thresh = cpu_to_le16(0);
|
||||
cfge->fccfg_sbpen = 0;
|
||||
cfge->fc_ports = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
if (ntmp_bpt_update_entry(&priv->ntmp, j, cfge)) {
|
||||
*cfge = old_cfge;
|
||||
dev_warn(priv->dev,
|
||||
"Failed to %s TX pause of buffer pool %d (swp%d)\n",
|
||||
tx_pause ? "enable" : "disable", j, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void netc_port_set_rx_pause(struct netc_port *np, bool rx_pause)
|
||||
{
|
||||
netc_mac_port_rmw(np, NETC_PM_CMD_CFG(0), PM_CMD_CFG_PAUSE_IGN,
|
||||
rx_pause ? 0 : PM_CMD_CFG_PAUSE_IGN);
|
||||
}
|
||||
|
||||
static void netc_port_mac_rx_enable(struct netc_port *np)
|
||||
{
|
||||
netc_port_rmw(np, NETC_POR, POR_RXDIS, 0);
|
||||
|
|
@ -1319,6 +1447,8 @@ static void netc_mac_link_up(struct phylink_config *config,
|
|||
interface == PHY_INTERFACE_MODE_MII)
|
||||
netc_port_set_rmii_mii_mac(np, speed, duplex);
|
||||
|
||||
netc_port_set_tx_pause(np, tx_pause);
|
||||
netc_port_set_rx_pause(np, rx_pause);
|
||||
netc_port_mac_tx_enable(np);
|
||||
netc_port_mac_rx_enable(np);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ struct netc_switch_platform {
|
|||
static void imx94_switch_phylink_get_caps(int port,
|
||||
struct phylink_config *config)
|
||||
{
|
||||
config->mac_capabilities = MAC_1000FD;
|
||||
config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_1000FD;
|
||||
|
||||
switch (port) {
|
||||
case 0 ... 1:
|
||||
|
|
|
|||
|
|
@ -28,11 +28,27 @@
|
|||
|
||||
#define NETC_TC_NUM 8
|
||||
#define NETC_CBDR_NUM 2
|
||||
#define NETC_IPV_NUM 8
|
||||
|
||||
#define NETC_MAX_FRAME_LEN 9600
|
||||
|
||||
#define NETC_STANDALONE_PVID 0
|
||||
|
||||
/* Threshold format: MANT (bits 11:4) * 2^EXP (bits 3:0)
|
||||
* Unit: Memory words (average of 20 bytes each)
|
||||
* NETC_BP_THRESH = 0x8c3, MANT = 0x8c, EXP = 3. Threshold: 1120 words
|
||||
* NETC_FC_THRESH_ON = 0x733, MANT = 0x73, EXP = 3. Threshold: 920 words
|
||||
* NETC_FC_THRESH_OFF = 0x263, MANT = 0x26, EXP = 3. Threshold: 304 words
|
||||
*/
|
||||
#define NETC_BP_THRESH 0x8c3
|
||||
#define NETC_FC_THRESH_ON 0x733
|
||||
#define NETC_FC_THRESH_OFF 0x263
|
||||
|
||||
/* PAUSE quanta: 0xFFFF = 65535 quanta (each quanta = 512 bit times) */
|
||||
#define NETC_PAUSE_QUANTA 0xFFFF
|
||||
/* PAUSE refresh threshold: send refresh when timer reaches this value */
|
||||
#define NETC_PAUSE_THRESH 0x7FFF
|
||||
|
||||
struct netc_switch;
|
||||
|
||||
struct netc_switch_info {
|
||||
|
|
@ -94,6 +110,9 @@ struct netc_switch {
|
|||
|
||||
/* Switch hardware capabilities */
|
||||
u32 htmcapr_num_words;
|
||||
u32 num_bp;
|
||||
|
||||
struct bpt_cfge_data *bpt_list;
|
||||
};
|
||||
|
||||
#define NETC_PRIV(ds) ((struct netc_switch *)((ds)->priv))
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
#define NETC_SWITCH_DEVICE_ID 0xeef2
|
||||
|
||||
/* Definition of Switch base registers */
|
||||
#define NETC_BPCAPR 0x0008
|
||||
#define BPCAPR_NUM_BP GENMASK(7, 0)
|
||||
|
||||
#define NETC_PBPMCR0 0x0400
|
||||
#define NETC_PBPMCR1 0x0404
|
||||
|
||||
#define NETC_CBDRMR(a) (0x0800 + (a) * 0x30)
|
||||
#define NETC_CBDRBAR0(a) (0x0810 + (a) * 0x30)
|
||||
#define NETC_CBDRBAR1(a) (0x0814 + (a) * 0x30)
|
||||
|
|
@ -152,6 +158,7 @@ enum netc_stg_stage {
|
|||
#define NETC_PM_CMD_CFG(a) (0x1008 + (a) * 0x400)
|
||||
#define PM_CMD_CFG_TX_EN BIT(0)
|
||||
#define PM_CMD_CFG_RX_EN BIT(1)
|
||||
#define PM_CMD_CFG_PAUSE_IGN BIT(8)
|
||||
|
||||
#define NETC_PM_MAXFRM(a) (0x1014 + (a) * 0x400)
|
||||
#define PM_MAXFRAM GENMASK(15, 0)
|
||||
|
|
@ -160,6 +167,9 @@ enum netc_stg_stage {
|
|||
#define PM_IEVENT_TX_EMPTY BIT(5)
|
||||
#define PM_IEVENT_RX_EMPTY BIT(6)
|
||||
|
||||
#define NETC_PM_PAUSE_QUANTA(a) (0x1054 + (a) * 0x400)
|
||||
#define NETC_PM_PAUSE_THRESH(a) (0x1064 + (a) * 0x400)
|
||||
|
||||
#define NETC_PM_IF_MODE(a) (0x1300 + (a) * 0x400)
|
||||
#define PM_IF_MODE_IFMODE GENMASK(2, 0)
|
||||
#define IFMODE_MII 1
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user