Message ID | 1612253821-1148-11-git-send-email-stefanc@marvell.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | net: mvpp2: Add TX Flow Control support | expand |
Context | Check | Description |
---|---|---|
netdev/cover_letter | success | Link |
netdev/fixes_present | success | Link |
netdev/patch_count | success | Link |
netdev/tree_selection | success | Clearly marked for net-next |
netdev/subject_prefix | success | Link |
netdev/cc_maintainers | success | CCed 5 of 5 maintainers |
netdev/source_inline | success | Was 0 now: 0 |
netdev/verify_signedoff | success | Link |
netdev/module_param | success | Was 0 now: 0 |
netdev/build_32bit | success | Errors and warnings before: 5 this patch: 5 |
netdev/kdoc | success | Errors and warnings before: 0 this patch: 0 |
netdev/verify_fixes | success | Link |
netdev/checkpatch | success | total: 0 errors, 0 warnings, 0 checks, 201 lines checked |
netdev/build_allmodconfig_warn | success | Errors and warnings before: 5 this patch: 5 |
netdev/header_inline | success | Link |
netdev/stable | success | Stable not CCed |
Hi, wt., 2 lut 2021 o 09:18 <stefanc@marvell.com> napisał(a): > > From: Stefan Chulski <stefanc@marvell.com> > > This patch adds RXQ flow control configurations. > Flow control disabled by default. > Minimum ring size limited to 1024 descriptors. > > Signed-off-by: Stefan Chulski <stefanc@marvell.com> > --- > drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 35 +++++- > drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 116 ++++++++++++++++++++ > 2 files changed, 150 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h > index e010410..0f27be0 100644 > --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h > +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h > @@ -766,9 +766,36 @@ > #define MSS_SRAM_SIZE 0x800 > #define MSS_FC_COM_REG 0 > #define FLOW_CONTROL_ENABLE_BIT BIT(0) > +#define FLOW_CONTROL_UPDATE_COMMAND_BIT BIT(31) > #define FC_QUANTA 0xFFFF > #define FC_CLK_DIVIDER 100 > -#define MSS_THRESHOLD_STOP 768 > + > +#define MSS_RXQ_TRESH_BASE 0x200 > +#define MSS_RXQ_TRESH_OFFS 4 > +#define MSS_RXQ_TRESH_REG(q, fq) (MSS_RXQ_TRESH_BASE + (((q) + (fq)) \ > + * MSS_RXQ_TRESH_OFFS)) > + > +#define MSS_RXQ_TRESH_START_MASK 0xFFFF > +#define MSS_RXQ_TRESH_STOP_MASK (0xFFFF << MSS_RXQ_TRESH_STOP_OFFS) > +#define MSS_RXQ_TRESH_STOP_OFFS 16 > + > +#define MSS_RXQ_ASS_BASE 0x80 > +#define MSS_RXQ_ASS_OFFS 4 > +#define MSS_RXQ_ASS_PER_REG 4 > +#define MSS_RXQ_ASS_PER_OFFS 8 > +#define MSS_RXQ_ASS_PORTID_OFFS 0 > +#define MSS_RXQ_ASS_PORTID_MASK 0x3 > +#define MSS_RXQ_ASS_HOSTID_OFFS 2 > +#define MSS_RXQ_ASS_HOSTID_MASK 0x3F > + > +#define MSS_RXQ_ASS_Q_BASE(q, fq) ((((q) + (fq)) % MSS_RXQ_ASS_PER_REG) \ > + * MSS_RXQ_ASS_PER_OFFS) > +#define MSS_RXQ_ASS_PQ_BASE(q, fq) ((((q) + (fq)) / MSS_RXQ_ASS_PER_REG) \ > + * MSS_RXQ_ASS_OFFS) > +#define MSS_RXQ_ASS_REG(q, fq) (MSS_RXQ_ASS_BASE + MSS_RXQ_ASS_PQ_BASE(q, fq)) > + > +#define MSS_THRESHOLD_STOP 768 > +#define MSS_THRESHOLD_START 1024 > > /* RX buffer constants */ > #define MVPP2_SKB_SHINFO_SIZE \ > @@ -1026,6 +1053,9 @@ struct mvpp2 { > > /* Global TX Flow Control config */ > bool global_tx_fc; > + > + /* Spinlocks for CM3 shared memory configuration */ > + spinlock_t mss_spinlock; > }; > > struct mvpp2_pcpu_stats { > @@ -1188,6 +1218,9 @@ struct mvpp2_port { > bool rx_hwtstamp; > enum hwtstamp_tx_types tx_hwtstamp_type; > struct mvpp2_hwtstamp_queue tx_hwtstamp_queue[2]; > + > + /* Firmware TX flow control */ > + bool tx_fc; > }; > > /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the > diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c > index 770f45a..d778ae1 100644 > --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c > +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c > @@ -742,6 +742,110 @@ static void *mvpp2_buf_alloc(struct mvpp2_port *port, > return data; > } > > +/* Routine enable flow control for RXQs condition */ > +static void mvpp2_rxq_enable_fc(struct mvpp2_port *port) > +{ > + int val, cm3_state, host_id, q; > + int fq = port->first_rxq; > + unsigned long flags; > + > + spin_lock_irqsave(&port->priv->mss_spinlock, flags); > + > + /* Remove Flow control enable bit to prevent race between FW and Kernel > + * If Flow control were enabled, it would be re-enabled. Nit: s/were/was/ Thanks, Marcin > + */ > + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); > + cm3_state = (val & FLOW_CONTROL_ENABLE_BIT); > + val &= ~FLOW_CONTROL_ENABLE_BIT; > + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); > + > + /* Set same Flow control for all RXQs */ > + for (q = 0; q < port->nrxqs; q++) { > + /* Set stop and start Flow control RXQ thresholds */ > + val = MSS_THRESHOLD_START; > + val |= (MSS_THRESHOLD_STOP << MSS_RXQ_TRESH_STOP_OFFS); > + mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val); > + > + val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq)); > + /* Set RXQ port ID */ > + val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq)); > + val |= (port->id << MSS_RXQ_ASS_Q_BASE(q, fq)); > + val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq) > + + MSS_RXQ_ASS_HOSTID_OFFS)); > + > + /* Calculate RXQ host ID: > + * In Single queue mode: Host ID equal to Host ID used for > + * shared RX interrupt > + * In Multi queue mode: Host ID equal to number of > + * RXQ ID / number of CoS queues > + * In Single resource mode: Host ID always equal to 0 > + */ > + if (queue_mode == MVPP2_QDIST_SINGLE_MODE) > + host_id = port->nqvecs; > + else if (queue_mode == MVPP2_QDIST_MULTI_MODE) > + host_id = q; > + else > + host_id = 0; > + > + /* Set RXQ host ID */ > + val |= (host_id << (MSS_RXQ_ASS_Q_BASE(q, fq) > + + MSS_RXQ_ASS_HOSTID_OFFS)); > + > + mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val); > + } > + > + /* Notify Firmware that Flow control config space ready for update */ > + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); > + val |= FLOW_CONTROL_UPDATE_COMMAND_BIT; > + val |= cm3_state; > + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); > + > + spin_unlock_irqrestore(&port->priv->mss_spinlock, flags); > +} > + > +/* Routine disable flow control for RXQs condition */ > +static void mvpp2_rxq_disable_fc(struct mvpp2_port *port) > +{ > + int val, cm3_state, q; > + unsigned long flags; > + int fq = port->first_rxq; > + > + spin_lock_irqsave(&port->priv->mss_spinlock, flags); > + > + /* Remove Flow control enable bit to prevent race between FW and Kernel > + * If Flow control were enabled, it would be re-enabled. > + */ > + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); > + cm3_state = (val & FLOW_CONTROL_ENABLE_BIT); > + val &= ~FLOW_CONTROL_ENABLE_BIT; > + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); > + > + /* Disable Flow control for all RXQs */ > + for (q = 0; q < port->nrxqs; q++) { > + /* Set threshold 0 to disable Flow control */ > + val = 0; > + val |= (0 << MSS_RXQ_TRESH_STOP_OFFS); > + mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val); > + > + val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq)); > + > + val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq)); > + > + val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq) > + + MSS_RXQ_ASS_HOSTID_OFFS)); > + > + mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val); > + } > + > + /* Notify Firmware that Flow control config space ready for update */ > + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); > + val |= FLOW_CONTROL_UPDATE_COMMAND_BIT; > + val |= cm3_state; > + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); > + > + spin_unlock_irqrestore(&port->priv->mss_spinlock, flags); > +} > + > /* Release buffer to BM */ > static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, > dma_addr_t buf_dma_addr, > @@ -3006,6 +3110,9 @@ static void mvpp2_cleanup_rxqs(struct mvpp2_port *port) > > for (queue = 0; queue < port->nrxqs; queue++) > mvpp2_rxq_deinit(port, port->rxqs[queue]); > + > + if (port->tx_fc) > + mvpp2_rxq_disable_fc(port); > } > > /* Init all Rx queues for port */ > @@ -3018,6 +3125,10 @@ static int mvpp2_setup_rxqs(struct mvpp2_port *port) > if (err) > goto err_cleanup; > } > + > + if (port->tx_fc) > + mvpp2_rxq_enable_fc(port); > + > return 0; > > err_cleanup: > @@ -4317,6 +4428,8 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev, > > if (ring->rx_pending > MVPP2_MAX_RXD_MAX) > new_rx_pending = MVPP2_MAX_RXD_MAX; > + else if (ring->rx_pending < MSS_THRESHOLD_START) > + new_rx_pending = MSS_THRESHOLD_START; > else if (!IS_ALIGNED(ring->rx_pending, 16)) > new_rx_pending = ALIGN(ring->rx_pending, 16); > > @@ -7170,6 +7283,9 @@ static int mvpp2_probe(struct platform_device *pdev) > priv->hw_version = MVPP23; > } > > + /* Init mss lock */ > + spin_lock_init(&priv->mss_spinlock); > + > /* Initialize network controller */ > err = mvpp2_init(pdev, priv); > if (err < 0) { > -- > 1.9.1 >
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h index e010410..0f27be0 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h @@ -766,9 +766,36 @@ #define MSS_SRAM_SIZE 0x800 #define MSS_FC_COM_REG 0 #define FLOW_CONTROL_ENABLE_BIT BIT(0) +#define FLOW_CONTROL_UPDATE_COMMAND_BIT BIT(31) #define FC_QUANTA 0xFFFF #define FC_CLK_DIVIDER 100 -#define MSS_THRESHOLD_STOP 768 + +#define MSS_RXQ_TRESH_BASE 0x200 +#define MSS_RXQ_TRESH_OFFS 4 +#define MSS_RXQ_TRESH_REG(q, fq) (MSS_RXQ_TRESH_BASE + (((q) + (fq)) \ + * MSS_RXQ_TRESH_OFFS)) + +#define MSS_RXQ_TRESH_START_MASK 0xFFFF +#define MSS_RXQ_TRESH_STOP_MASK (0xFFFF << MSS_RXQ_TRESH_STOP_OFFS) +#define MSS_RXQ_TRESH_STOP_OFFS 16 + +#define MSS_RXQ_ASS_BASE 0x80 +#define MSS_RXQ_ASS_OFFS 4 +#define MSS_RXQ_ASS_PER_REG 4 +#define MSS_RXQ_ASS_PER_OFFS 8 +#define MSS_RXQ_ASS_PORTID_OFFS 0 +#define MSS_RXQ_ASS_PORTID_MASK 0x3 +#define MSS_RXQ_ASS_HOSTID_OFFS 2 +#define MSS_RXQ_ASS_HOSTID_MASK 0x3F + +#define MSS_RXQ_ASS_Q_BASE(q, fq) ((((q) + (fq)) % MSS_RXQ_ASS_PER_REG) \ + * MSS_RXQ_ASS_PER_OFFS) +#define MSS_RXQ_ASS_PQ_BASE(q, fq) ((((q) + (fq)) / MSS_RXQ_ASS_PER_REG) \ + * MSS_RXQ_ASS_OFFS) +#define MSS_RXQ_ASS_REG(q, fq) (MSS_RXQ_ASS_BASE + MSS_RXQ_ASS_PQ_BASE(q, fq)) + +#define MSS_THRESHOLD_STOP 768 +#define MSS_THRESHOLD_START 1024 /* RX buffer constants */ #define MVPP2_SKB_SHINFO_SIZE \ @@ -1026,6 +1053,9 @@ struct mvpp2 { /* Global TX Flow Control config */ bool global_tx_fc; + + /* Spinlocks for CM3 shared memory configuration */ + spinlock_t mss_spinlock; }; struct mvpp2_pcpu_stats { @@ -1188,6 +1218,9 @@ struct mvpp2_port { bool rx_hwtstamp; enum hwtstamp_tx_types tx_hwtstamp_type; struct mvpp2_hwtstamp_queue tx_hwtstamp_queue[2]; + + /* Firmware TX flow control */ + bool tx_fc; }; /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 770f45a..d778ae1 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -742,6 +742,110 @@ static void *mvpp2_buf_alloc(struct mvpp2_port *port, return data; } +/* Routine enable flow control for RXQs condition */ +static void mvpp2_rxq_enable_fc(struct mvpp2_port *port) +{ + int val, cm3_state, host_id, q; + int fq = port->first_rxq; + unsigned long flags; + + spin_lock_irqsave(&port->priv->mss_spinlock, flags); + + /* Remove Flow control enable bit to prevent race between FW and Kernel + * If Flow control were enabled, it would be re-enabled. + */ + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); + cm3_state = (val & FLOW_CONTROL_ENABLE_BIT); + val &= ~FLOW_CONTROL_ENABLE_BIT; + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); + + /* Set same Flow control for all RXQs */ + for (q = 0; q < port->nrxqs; q++) { + /* Set stop and start Flow control RXQ thresholds */ + val = MSS_THRESHOLD_START; + val |= (MSS_THRESHOLD_STOP << MSS_RXQ_TRESH_STOP_OFFS); + mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val); + + val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq)); + /* Set RXQ port ID */ + val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq)); + val |= (port->id << MSS_RXQ_ASS_Q_BASE(q, fq)); + val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq) + + MSS_RXQ_ASS_HOSTID_OFFS)); + + /* Calculate RXQ host ID: + * In Single queue mode: Host ID equal to Host ID used for + * shared RX interrupt + * In Multi queue mode: Host ID equal to number of + * RXQ ID / number of CoS queues + * In Single resource mode: Host ID always equal to 0 + */ + if (queue_mode == MVPP2_QDIST_SINGLE_MODE) + host_id = port->nqvecs; + else if (queue_mode == MVPP2_QDIST_MULTI_MODE) + host_id = q; + else + host_id = 0; + + /* Set RXQ host ID */ + val |= (host_id << (MSS_RXQ_ASS_Q_BASE(q, fq) + + MSS_RXQ_ASS_HOSTID_OFFS)); + + mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val); + } + + /* Notify Firmware that Flow control config space ready for update */ + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); + val |= FLOW_CONTROL_UPDATE_COMMAND_BIT; + val |= cm3_state; + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); + + spin_unlock_irqrestore(&port->priv->mss_spinlock, flags); +} + +/* Routine disable flow control for RXQs condition */ +static void mvpp2_rxq_disable_fc(struct mvpp2_port *port) +{ + int val, cm3_state, q; + unsigned long flags; + int fq = port->first_rxq; + + spin_lock_irqsave(&port->priv->mss_spinlock, flags); + + /* Remove Flow control enable bit to prevent race between FW and Kernel + * If Flow control were enabled, it would be re-enabled. + */ + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); + cm3_state = (val & FLOW_CONTROL_ENABLE_BIT); + val &= ~FLOW_CONTROL_ENABLE_BIT; + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); + + /* Disable Flow control for all RXQs */ + for (q = 0; q < port->nrxqs; q++) { + /* Set threshold 0 to disable Flow control */ + val = 0; + val |= (0 << MSS_RXQ_TRESH_STOP_OFFS); + mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val); + + val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq)); + + val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq)); + + val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq) + + MSS_RXQ_ASS_HOSTID_OFFS)); + + mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val); + } + + /* Notify Firmware that Flow control config space ready for update */ + val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG); + val |= FLOW_CONTROL_UPDATE_COMMAND_BIT; + val |= cm3_state; + mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val); + + spin_unlock_irqrestore(&port->priv->mss_spinlock, flags); +} + /* Release buffer to BM */ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, @@ -3006,6 +3110,9 @@ static void mvpp2_cleanup_rxqs(struct mvpp2_port *port) for (queue = 0; queue < port->nrxqs; queue++) mvpp2_rxq_deinit(port, port->rxqs[queue]); + + if (port->tx_fc) + mvpp2_rxq_disable_fc(port); } /* Init all Rx queues for port */ @@ -3018,6 +3125,10 @@ static int mvpp2_setup_rxqs(struct mvpp2_port *port) if (err) goto err_cleanup; } + + if (port->tx_fc) + mvpp2_rxq_enable_fc(port); + return 0; err_cleanup: @@ -4317,6 +4428,8 @@ static int mvpp2_check_ringparam_valid(struct net_device *dev, if (ring->rx_pending > MVPP2_MAX_RXD_MAX) new_rx_pending = MVPP2_MAX_RXD_MAX; + else if (ring->rx_pending < MSS_THRESHOLD_START) + new_rx_pending = MSS_THRESHOLD_START; else if (!IS_ALIGNED(ring->rx_pending, 16)) new_rx_pending = ALIGN(ring->rx_pending, 16); @@ -7170,6 +7283,9 @@ static int mvpp2_probe(struct platform_device *pdev) priv->hw_version = MVPP23; } + /* Init mss lock */ + spin_lock_init(&priv->mss_spinlock); + /* Initialize network controller */ err = mvpp2_init(pdev, priv); if (err < 0) {