mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
net: mvpp2: add RXQ flow control configurations
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> Acked-by: Marcin Wojtas <mw@semihalf.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a59d354208
commit
3bd17fdc08
2 changed files with 150 additions and 1 deletions
|
@ -765,9 +765,36 @@
|
|||
/* MSS Flow control */
|
||||
#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 \
|
||||
|
@ -1022,6 +1049,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 {
|
||||
|
@ -1184,6 +1214,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
|
||||
|
|
|
@ -741,6 +741,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 was 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 was 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,
|
||||
|
@ -3013,6 +3117,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 */
|
||||
|
@ -3025,6 +3132,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:
|
||||
|
@ -4324,6 +4435,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);
|
||||
|
||||
|
@ -7156,6 +7269,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) {
|
||||
|
|
Loading…
Reference in a new issue