/* * Driver for Marvell NETA network card for Armada XP and Armada 370 SoCs. * * Copyright (C) 2012 Marvell * * Rami Rosen <rosenr@marvell.com> * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied.
*/
/* Exception Interrupt Port/Queue Cause register * * Their behavior depend of the mapping done using the PCPX2Q * registers. For a given CPU if the bit associated to a queue is not * set, then for the register a read from this CPU will always return * 0 and a write won't do anything
*/
/* bits 0..7 = TXQ SENT, one bit per queue. * bits 8..15 = RXQ OCCUP, one bit per queue. * bits 16..23 = RXQ FREE, one bit per queue. * bit 29 = OLD_REG_SUM, see old reg ? * bit 30 = TX_ERR_SUM, one bit for 4 ports * bit 31 = MISC_SUM, one bit for 4 ports
*/ #define MVNETA_TX_INTR_MASK(nr_txqs) (((1 << nr_txqs) - 1) << 0) #define MVNETA_TX_INTR_MASK_ALL (0xff << 0) #define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8) #define MVNETA_RX_INTR_MASK_ALL (0xff << 8) #define MVNETA_MISCINTR_INTR_MASK BIT(31)
/* The values of the bucket refill base period and refill period are taken from * the reference manual, and adds up to a base resolution of 10Kbps. This allows * to cover all rate-limit values from 10Kbps up to 5Gbps
*/
/* Base period for the rate limit algorithm */ #define MVNETA_TXQ_BUCKET_REFILL_BASE_PERIOD_NS 100
/* Number of Base Period to wait between each bucket refill */ #define MVNETA_TXQ_BUCKET_REFILL_PERIOD 1000
/* The base resolution for rate limiting, in bps. Any max_rate value should be * a multiple of that value.
*/ #define MVNETA_TXQ_RATE_LIMIT_RESOLUTION (NSEC_PER_SEC / \
(MVNETA_TXQ_BUCKET_REFILL_BASE_PERIOD_NS * \
MVNETA_TXQ_BUCKET_REFILL_PERIOD))
/* The two bytes Marvell header. Either contains a special value used * by Marvell switches when a specific hardware mode is enabled (not * supported by this driver) or is filled automatically by zeroes on * the RX side. Those two bytes being at the front of the Ethernet * header, they allow to have the IP header aligned on a 4 bytes * boundary automatically: the hardware skips those two bytes on its * own.
*/ #define MVNETA_MH_SIZE 2
/* Number of bytes to be taken into account by HW when putting incoming data * to the buffers. It is needed in case NET_SKB_PAD exceeds maximum packet * offset supported in MVNETA_RXQ_CONFIG_REG(q) registers.
*/ #define MVNETA_RX_PKT_OFFSET_CORRECTION 64
/* Flags for special SoC configurations */ bool neta_armada3700; bool neta_ac5;
u16 rx_offset_correction; conststruct mbus_dram_target_info *dram_target_info;
};
/* The mvneta_tx_desc and mvneta_rx_desc structures describe the * layout of the transmit and reception DMA descriptors, and their * layout is therefore defined by the hardware design
*/
/* Virtual address of the RX buffer */ void **buf_virt_addr;
/* Virtual address of the RX DMA descriptors array */ struct mvneta_rx_desc *descs;
/* DMA address of the RX DMA descriptors array */
dma_addr_t descs_phys;
/* Index of the last RX DMA descriptor */ int last_desc;
/* Index of the next RX DMA descriptor to process */ int next_desc_to_proc;
/* Index of first RX DMA descriptor to refill */ int first_to_refill;
u32 refill_num;
};
staticenum cpuhp_state online_hpstate; /* The hardware supports eight (8) rx queues, but we are only allowing * the first one to be used. Therefore, let's just allocate one queue.
*/ staticint rxq_number = 8; staticint txq_number = 8;
staticint rxq_def;
staticint rx_copybreak __read_mostly = 256;
/* HW BM need that each port be identify by a unique ID */ staticint global_port_id;
/* Checks whether the RX descriptor having this status is both the first * and the last descriptor for the RX packet. Each RX packet is currently * received through a single RX descriptor, so not having each RX * descriptor with its first and last bits set is an error
*/ staticint mvneta_rxq_desc_is_first_last(u32 status)
{ return (status & MVNETA_RXD_FIRST_LAST_DESC) ==
MVNETA_RXD_FIRST_LAST_DESC;
}
/* Add number of descriptors ready to receive new packets */ staticvoid mvneta_rxq_non_occup_desc_add(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int ndescs)
{ /* Only MVNETA_RXQ_ADD_NON_OCCUPIED_MAX (255) descriptors can * be added at once
*/ while (ndescs > MVNETA_RXQ_ADD_NON_OCCUPIED_MAX) {
mvreg_write(pp, MVNETA_RXQ_STATUS_UPDATE_REG(rxq->id),
(MVNETA_RXQ_ADD_NON_OCCUPIED_MAX <<
MVNETA_RXQ_ADD_NON_OCCUPIED_SHIFT));
ndescs -= MVNETA_RXQ_ADD_NON_OCCUPIED_MAX;
}
/* Get number of RX descriptors occupied by received packets */ staticint mvneta_rxq_busy_desc_num_get(struct mvneta_port *pp, struct mvneta_rx_queue *rxq)
{
u32 val;
val = mvreg_read(pp, MVNETA_RXQ_STATUS_REG(rxq->id)); return val & MVNETA_RXQ_OCCUPIED_ALL_MASK;
}
/* Update num of rx desc called upon return from rx path or * from mvneta_rxq_drop_pkts().
*/ staticvoid mvneta_rxq_desc_num_update(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int rx_done, int rx_filled)
{
u32 val;
/* Only 255 descriptors can be added at once */ while ((rx_done > 0) || (rx_filled > 0)) { if (rx_done <= 0xff) {
val = rx_done;
rx_done = 0;
} else {
val = 0xff;
rx_done -= 0xff;
} if (rx_filled <= 0xff) {
val |= rx_filled << MVNETA_RXQ_ADD_NON_OCCUPIED_SHIFT;
rx_filled = 0;
} else {
val |= 0xff << MVNETA_RXQ_ADD_NON_OCCUPIED_SHIFT;
rx_filled -= 0xff;
}
mvreg_write(pp, MVNETA_RXQ_STATUS_UPDATE_REG(rxq->id), val);
}
}
/* Get pointer to next RX descriptor to be processed by SW */ staticstruct mvneta_rx_desc *
mvneta_rxq_next_desc_get(struct mvneta_rx_queue *rxq)
{ int rx_desc = rxq->next_desc_to_proc;
/* Change maximum receive size of the port. */ staticvoid mvneta_max_rx_size_set(struct mvneta_port *pp, int max_rx_size)
{
u32 val;
val = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
val &= ~MVNETA_GMAC_MAX_RX_SIZE_MASK;
val |= ((max_rx_size - MVNETA_MH_SIZE) / 2) <<
MVNETA_GMAC_MAX_RX_SIZE_SHIFT;
mvreg_write(pp, MVNETA_GMAC_CTRL_0, val);
}
/* Set rx queue offset */ staticvoid mvneta_rxq_offset_set(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int offset)
{
u32 val;
val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
val &= ~MVNETA_RXQ_PKT_OFFSET_ALL_MASK;
/* Offset is in */
val |= MVNETA_RXQ_PKT_OFFSET_MASK(offset >> 3);
mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
}
/* Tx descriptors helper methods */
/* Update HW with number of TX descriptors to be sent */ staticvoid mvneta_txq_pend_desc_add(struct mvneta_port *pp, struct mvneta_tx_queue *txq, int pend_desc)
{
u32 val;
pend_desc += txq->pending;
/* Only 255 Tx descriptors can be added at once */ do {
val = min(pend_desc, 255);
mvreg_write(pp, MVNETA_TXQ_UPDATE_REG(txq->id), val);
pend_desc -= val;
} while (pend_desc > 0);
txq->pending = 0;
}
/* Get pointer to next TX descriptor to be processed (send) by HW */ staticstruct mvneta_tx_desc *
mvneta_txq_next_desc_get(struct mvneta_tx_queue *txq)
{ int tx_desc = txq->next_desc_to_proc;
val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
val |= MVNETA_RXQ_HW_BUF_ALLOC;
mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
}
/* Notify HW about port's assignment of pool for bigger packets */ staticvoid mvneta_rxq_long_pool_set(struct mvneta_port *pp, struct mvneta_rx_queue *rxq)
{
u32 val;
val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
val &= ~MVNETA_RXQ_LONG_POOL_ID_MASK;
val |= (pp->pool_long->id << MVNETA_RXQ_LONG_POOL_ID_SHIFT);
/* Notify HW about port's assignment of pool for smaller packets */ staticvoid mvneta_rxq_short_pool_set(struct mvneta_port *pp, struct mvneta_rx_queue *rxq)
{
u32 val;
val = mvreg_read(pp, MVNETA_RXQ_CONFIG_REG(rxq->id));
val &= ~MVNETA_RXQ_SHORT_POOL_ID_MASK;
val |= (pp->pool_short->id << MVNETA_RXQ_SHORT_POOL_ID_SHIFT);
if (pp->bm_win_id < 0) { /* Find first not occupied window */ for (i = 0; i < MVNETA_MAX_DECODE_WIN; i++) { if (win_enable & (1 << i)) {
pp->bm_win_id = i; break;
}
} if (i == MVNETA_MAX_DECODE_WIN) return -ENOMEM;
} else {
i = pp->bm_win_id;
}
/* Get BM window information */
err = mvebu_mbus_get_io_win_info(pp->bm_priv->bppi_phys_addr, &wsize,
&target, &attr); if (err < 0) return err;
pp->bm_win_id = -1;
/* Open NETA -> BM window */
err = mvneta_mbus_io_win_set(pp, pp->bm_priv->bppi_phys_addr, wsize,
target, attr); if (err < 0) {
netdev_info(pp->dev, "fail to configure mbus window to BM\n"); return err;
} return 0;
}
/* Assign and initialize pools for port. In case of fail * buffer manager will remain disabled for current port.
*/ staticint mvneta_bm_port_init(struct platform_device *pdev, struct mvneta_port *pp)
{ struct device_node *dn = pdev->dev.of_node;
u32 long_pool_id, short_pool_id;
if (!pp->neta_armada3700) { int ret;
ret = mvneta_bm_port_mbus_init(pp); if (ret) return ret;
}
if (of_property_read_u32(dn, "bm,pool-long", &long_pool_id)) {
netdev_info(pp->dev, "missing long pool id\n"); return -EINVAL;
}
/* Create port's long pool depending on mtu */
pp->pool_long = mvneta_bm_pool_use(pp->bm_priv, long_pool_id,
MVNETA_BM_LONG, pp->id,
MVNETA_RX_PKT_SIZE(pp->dev->mtu)); if (!pp->pool_long) {
netdev_info(pp->dev, "fail to obtain long pool for port\n"); return -ENOMEM;
}
/* If short pool id is not defined, assume using single pool */ if (of_property_read_u32(dn, "bm,pool-short", &short_pool_id))
short_pool_id = long_pool_id;
/* Create port's short pool */
pp->pool_short = mvneta_bm_pool_use(pp->bm_priv, short_pool_id,
MVNETA_BM_SHORT, pp->id,
MVNETA_BM_SHORT_PKT_SIZE); if (!pp->pool_short) {
netdev_info(pp->dev, "fail to obtain short pool for port\n");
mvneta_bm_pool_destroy(pp->bm_priv, pp->pool_long, 1 << pp->id); return -ENOMEM;
}
/* Update settings of a pool for bigger packets */ staticvoid mvneta_bm_update_mtu(struct mvneta_port *pp, int mtu)
{ struct mvneta_bm_pool *bm_pool = pp->pool_long; struct hwbm_pool *hwbm_pool = &bm_pool->hwbm_pool; int num;
/* Release all buffers from long pool */
mvneta_bm_bufs_free(pp->bm_priv, bm_pool, 1 << pp->id); if (hwbm_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n",
bm_pool->id); goto bm_mtu_err;
}
pp->bm_priv = NULL;
pp->rx_offset_correction = MVNETA_SKB_HEADROOM;
mvreg_write(pp, MVNETA_ACC_MODE, MVNETA_ACC_MODE_EXT1);
netdev_info(pp->dev, "fail to update MTU, fall back to software BM\n");
}
/* Start the Ethernet port RX and TX activity */ staticvoid mvneta_port_up(struct mvneta_port *pp)
{ int queue;
u32 q_map;
/* Stop the Ethernet port activity */ staticvoid mvneta_port_down(struct mvneta_port *pp)
{
u32 val; int count;
/* Stop Rx port activity. Check port Rx activity. */
val = mvreg_read(pp, MVNETA_RXQ_CMD) & MVNETA_RXQ_ENABLE_MASK;
/* Issue stop command for active channels only */ if (val != 0)
mvreg_write(pp, MVNETA_RXQ_CMD,
val << MVNETA_RXQ_DISABLE_SHIFT);
/* Wait for all Rx activity to terminate. */
count = 0; do { if (count++ >= MVNETA_RX_DISABLE_TIMEOUT_MSEC) {
netdev_warn(pp->dev, "TIMEOUT for RX stopped ! rx_queue_cmd: 0x%08x\n",
val); break;
}
mdelay(1);
val = mvreg_read(pp, MVNETA_RXQ_CMD);
} while (val & MVNETA_RXQ_ENABLE_MASK);
/* Stop Tx port activity. Check port Tx activity. Issue stop * command for active channels only
*/
val = (mvreg_read(pp, MVNETA_TXQ_CMD)) & MVNETA_TXQ_ENABLE_MASK;
if (val != 0)
mvreg_write(pp, MVNETA_TXQ_CMD,
(val << MVNETA_TXQ_DISABLE_SHIFT));
/* Wait for all Tx activity to terminate. */
count = 0; do { if (count++ >= MVNETA_TX_DISABLE_TIMEOUT_MSEC) {
netdev_warn(pp->dev, "TIMEOUT for TX stopped status=0x%08x\n",
val); break;
}
mdelay(1);
/* Check TX Command reg that all Txqs are stopped */
val = mvreg_read(pp, MVNETA_TXQ_CMD);
} while (val & MVNETA_TXQ_ENABLE_MASK);
/* Double check to verify that TX FIFO is empty */
count = 0; do { if (count++ >= MVNETA_TX_FIFO_EMPTY_TIMEOUT) {
netdev_warn(pp->dev, "TX FIFO empty timeout status=0x%08x\n",
val); break;
}
mdelay(1);
val = mvreg_read(pp, MVNETA_PORT_STATUS);
} while (!(val & MVNETA_TX_FIFO_EMPTY) &&
(val & MVNETA_TX_IN_PRGRS));
udelay(200);
}
/* Enable the port by setting the port enable bit of the MAC control register */ staticvoid mvneta_port_enable(struct mvneta_port *pp)
{
u32 val;
/* Enable port */
val = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
val |= MVNETA_GMAC0_PORT_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CTRL_0, val);
}
/* Disable the port and wait for about 200 usec before retuning */ staticvoid mvneta_port_disable(struct mvneta_port *pp)
{
u32 val;
/* Reset the Enable bit in the Serial Control Register */
val = mvreg_read(pp, MVNETA_GMAC_CTRL_0);
val &= ~MVNETA_GMAC0_PORT_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CTRL_0, val);
udelay(200);
}
/* Multicast tables methods */
/* Set all entries in Unicast MAC Table; queue==-1 means reject all */ staticvoid mvneta_set_ucast_table(struct mvneta_port *pp, int queue)
{ int offset;
u32 val;
if (queue == -1) {
val = 0;
} else {
val = 0x1 | (queue << 1);
val |= (val << 24) | (val << 16) | (val << 8);
}
/* Set all entries in Special Multicast MAC Table; queue==-1 means reject all */ staticvoid mvneta_set_special_mcast_table(struct mvneta_port *pp, int queue)
{ int offset;
u32 val;
if (queue == -1) {
val = 0;
} else {
val = 0x1 | (queue << 1);
val |= (val << 24) | (val << 16) | (val << 8);
}
/* Set all entries in Other Multicast MAC Table. queue==-1 means reject all */ staticvoid mvneta_set_other_mcast_table(struct mvneta_port *pp, int queue)
{ int offset;
u32 val;
if (queue == -1) {
memset(pp->mcast_count, 0, sizeof(pp->mcast_count));
val = 0;
} else {
memset(pp->mcast_count, 1, sizeof(pp->mcast_count));
val = 0x1 | (queue << 1);
val |= (val << 24) | (val << 16) | (val << 8);
}
/* All the queue are unmasked, but actually only the ones * mapped to this CPU will be unmasked
*/
mvreg_write(pp, MVNETA_INTR_NEW_MASK,
MVNETA_RX_INTR_MASK_ALL |
MVNETA_TX_INTR_MASK_ALL |
MVNETA_MISCINTR_INTR_MASK);
}
/* All the queue are masked, but actually only the ones * mapped to this CPU will be masked
*/
mvreg_write(pp, MVNETA_INTR_NEW_MASK, 0);
mvreg_write(pp, MVNETA_INTR_OLD_MASK, 0);
mvreg_write(pp, MVNETA_INTR_MISC_MASK, 0);
}
/* All the queue are cleared, but actually only the ones * mapped to this CPU will be cleared
*/
mvreg_write(pp, MVNETA_INTR_NEW_CAUSE, 0);
mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
mvreg_write(pp, MVNETA_INTR_OLD_CAUSE, 0);
}
/* This method sets defaults to the NETA port: * Clears interrupt Cause and Mask registers. * Clears all MAC tables. * Sets defaults to all registers. * Resets RX and TX descriptor rings. * Resets PHY. * This method can be called after mvneta_port_down() to return the port * settings to defaults.
*/ staticvoid mvneta_defaults_set(struct mvneta_port *pp)
{ int cpu; int queue;
u32 val; int max_cpu = num_present_cpus();
/* Clear all Cause registers */
on_each_cpu(mvneta_percpu_clear_intr_cause, pp, true);
/* Set CPU queue access map. CPUs are assigned to the RX and * TX queues modulo their number. If there is only one TX * queue then it is assigned to the CPU associated to the * default RX queue.
*/
for_each_present_cpu(cpu) { int rxq_map = 0, txq_map = 0; int rxq, txq; if (!pp->neta_armada3700) { for (rxq = 0; rxq < rxq_number; rxq++) if ((rxq % max_cpu) == cpu)
rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
for (txq = 0; txq < txq_number; txq++) if ((txq % max_cpu) == cpu)
txq_map |= MVNETA_CPU_TXQ_ACCESS(txq);
/* With only one TX queue we configure a special case * which will allow to get all the irq on a single * CPU
*/ if (txq_number == 1)
txq_map = (cpu == pp->rxq_def) ?
MVNETA_CPU_TXQ_ACCESS(0) : 0;
/* Set Port Acceleration Mode */ if (pp->bm_priv) /* HW buffer management + legacy parser */
val = MVNETA_ACC_MODE_EXT2; else /* SW buffer management + legacy parser */
val = MVNETA_ACC_MODE_EXT1;
mvreg_write(pp, MVNETA_ACC_MODE, val);
if (pp->bm_priv)
mvreg_write(pp, MVNETA_BM_ADDRESS, pp->bm_priv->bppi_phys_addr);
/* Update val of portCfg register accordingly with all RxQueue types */
val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def);
mvreg_write(pp, MVNETA_PORT_CONFIG, val);
val = 0;
mvreg_write(pp, MVNETA_PORT_CONFIG_EXTEND, val);
mvreg_write(pp, MVNETA_RX_MIN_FRAME_SIZE, 64);
/* Build PORT_SDMA_CONFIG_REG */
val = 0;
/* Default burst size */
val |= MVNETA_TX_BRST_SZ_MASK(MVNETA_SDMA_BRST_SIZE_16);
val |= MVNETA_RX_BRST_SZ_MASK(MVNETA_SDMA_BRST_SIZE_16);
val |= MVNETA_RX_NO_DATA_SWAP | MVNETA_TX_NO_DATA_SWAP;
#ifdefined(__BIG_ENDIAN)
val |= MVNETA_DESC_SWAP; #endif
/* Assign port SDMA configuration */
mvreg_write(pp, MVNETA_SDMA_CONFIG, val);
/* Disable PHY polling in hardware, since we're using the * kernel phylib to do this.
*/
val = mvreg_read(pp, MVNETA_UNIT_CONTROL);
val &= ~MVNETA_PHY_POLLING_ENABLE;
mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
/* Accept frames of this address */
mvneta_set_ucast_addr(pp, addr[5], queue);
}
/* Set the number of packets that will be received before RX interrupt * will be generated by HW.
*/ staticvoid mvneta_rx_pkts_coal_set(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, u32 value)
{
mvreg_write(pp, MVNETA_RXQ_THRESHOLD_REG(rxq->id),
value | MVNETA_RXQ_NON_OCCUPIED(0));
}
/* Set the time delay in usec before RX interrupt will be generated by * HW.
*/ staticvoid mvneta_rx_time_coal_set(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, u32 value)
{
u32 val; unsignedlong clk_rate;
clk_rate = clk_get_rate(pp->clk);
val = (clk_rate / 1000000) * value;
/* Decrement sent descriptors counter */ staticvoid mvneta_txq_sent_desc_dec(struct mvneta_port *pp, struct mvneta_tx_queue *txq, int sent_desc)
{
u32 val;
/* Only 255 TX descriptors can be updated at once */ while (sent_desc > 0xff) {
val = 0xff << MVNETA_TXQ_DEC_SENT_SHIFT;
mvreg_write(pp, MVNETA_TXQ_UPDATE_REG(txq->id), val);
sent_desc = sent_desc - 0xff;
}
val = sent_desc << MVNETA_TXQ_DEC_SENT_SHIFT;
mvreg_write(pp, MVNETA_TXQ_UPDATE_REG(txq->id), val);
}
/* Get number of TX descriptors already sent by HW */ staticint mvneta_txq_sent_desc_num_get(struct mvneta_port *pp, struct mvneta_tx_queue *txq)
{
u32 val; int sent_desc;
/* Get number of sent descriptors and decrement counter. * The number of sent descriptors is returned.
*/ staticint mvneta_txq_sent_desc_proc(struct mvneta_port *pp, struct mvneta_tx_queue *txq)
{ int sent_desc;
/* Get number of sent descriptors */
sent_desc = mvneta_txq_sent_desc_num_get(pp, txq);
/* Decrement sent descriptors counter */ if (sent_desc)
mvneta_txq_sent_desc_dec(pp, txq, sent_desc);
return sent_desc;
}
/* Set TXQ descriptors fields relevant for CSUM calculation */ static u32 mvneta_txq_desc_csum(int l3_offs, __be16 l3_proto, int ip_hdr_len, int l4_proto)
{
u32 command;
switch (status & MVNETA_RXD_ERR_CODE_MASK) { case MVNETA_RXD_ERR_CRC:
netdev_err(pp->dev, "bad rx status %08x (crc error), size=%d\n",
status, rx_desc->data_size); break; case MVNETA_RXD_ERR_OVERRUN:
netdev_err(pp->dev, "bad rx status %08x (overrun error), size=%d\n",
status, rx_desc->data_size); break; case MVNETA_RXD_ERR_LEN:
netdev_err(pp->dev, "bad rx status %08x (max frame length error), size=%d\n",
status, rx_desc->data_size); break; case MVNETA_RXD_ERR_RESOURCE:
netdev_err(pp->dev, "bad rx status %08x (resource error), size=%d\n",
status, rx_desc->data_size); break;
}
}
/* Handle RX checksum offload based on the descriptor's status */ staticint mvneta_rx_csum(struct mvneta_port *pp, u32 status)
{ if ((pp->dev->features & NETIF_F_RXCSUM) &&
(status & MVNETA_RXD_L3_IP4) &&
(status & MVNETA_RXD_L4_CSUM_OK)) return CHECKSUM_UNNECESSARY;
return CHECKSUM_NONE;
}
/* Return tx queue pointer (find last set bit) according to <cause> returned * form tx_done reg. <cause> must not be null. The return value is always a * valid queue for matching the first one found in <cause>.
*/ staticstruct mvneta_tx_queue *mvneta_tx_done_policy(struct mvneta_port *pp,
u32 cause)
{ int queue = fls(cause) - 1;
/* Drop packets received by the RXQ and free buffers */ staticvoid mvneta_rxq_drop_pkts(struct mvneta_port *pp, struct mvneta_rx_queue *rxq)
{ int rx_done, i;
rx_done = mvneta_rxq_busy_desc_num_get(pp, rxq); if (rx_done)
mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done);
if (pp->bm_priv) { for (i = 0; i < rx_done; i++) { struct mvneta_rx_desc *rx_desc =
mvneta_rxq_next_desc_get(rxq);
u8 pool_id = MVNETA_RX_GET_BM_POOL_ID(rx_desc); struct mvneta_bm_pool *bm_pool;
bm_pool = &pp->bm_priv->bm_pools[pool_id]; /* Return dropped buffer to the pool */
mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
rx_desc->buf_phys_addr);
} return;
}
for (i = 0; i < rxq->size; i++) { struct mvneta_rx_desc *rx_desc = rxq->descs + i; void *data = rxq->buf_virt_addr[i]; if (!data || !(rx_desc->buf_phys_addr)) continue;
staticinline int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq)
{ struct mvneta_rx_desc *rx_desc; int curr_desc = rxq->first_to_refill; int i;
for (i = 0; (i < rxq->refill_num) && (i < 64); i++) {
rx_desc = rxq->descs + curr_desc; if (!(rx_desc->buf_phys_addr)) { if (mvneta_rx_refill(pp, rx_desc, rxq, GFP_ATOMIC)) { struct mvneta_pcpu_stats *stats;
pr_err("Can't refill queue %d. Done %d from %d\n",
rxq->id, i, rxq->refill_num);
if (unlikely(xdp_frame_has_frags(xdpf)))
num_frames += sinfo->nr_frags;
if (txq->count + num_frames >= txq->size) return MVNETA_XDP_DROPPED;
for (i = 0; i < num_frames; i++) { struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
skb_frag_t *frag = NULL; int len = xdpf->len;
dma_addr_t dma_addr;
if (unlikely(i)) { /* paged area */
frag = &sinfo->frags[i - 1];
len = skb_frag_size(frag);
}
__netif_tx_lock(nq, cpu); for (i = 0; i < num_frame; i++) {
ret = mvneta_xdp_submit_frame(pp, txq, frames[i], &nxmit_byte, true); if (ret != MVNETA_XDP_TX) break;
nxmit++;
}
if (unlikely(flags & XDP_XMIT_FLUSH))
mvneta_txq_pend_desc_add(pp, txq, 0);
__netif_tx_unlock(nq);
if (rx_status & MVNETA_RXD_FIRST_DESC) { /* Check errors only for FIRST descriptor */ if (rx_status & MVNETA_RXD_ERR_SUMMARY) {
mvneta_rx_error(pp, rx_desc); goto next;
}
if (!mvneta_rxq_desc_is_first_last(rx_status) ||
(rx_status & MVNETA_RXD_ERR_SUMMARY)) {
err_drop_frame_ret_pool: /* Return the buffer to the pool */
mvneta_bm_pool_put_bp(pp->bm_priv, bm_pool,
rx_desc->buf_phys_addr);
err_drop_frame:
mvneta_rx_error(pp, rx_desc); /* leave the descriptor untouched */ continue;
}
if (rx_bytes <= rx_copybreak) { /* better copy a small frame and not unmap the DMA region */
skb = netdev_alloc_skb_ip_align(dev, rx_bytes); if (unlikely(!skb)) goto err_drop_frame_ret_pool;
/* After refill old buffer has to be unmapped regardless * the skb is successfully built or not.
*/
dma_unmap_single(&pp->bm_priv->pdev->dev, phys_addr,
bm_pool->buf_size, DMA_FROM_DEVICE); if (!skb) goto err_drop_frame;
rcvd_pkts++;
rcvd_bytes += rx_bytes;
/* Linux processing */
skb_reserve(skb, MVNETA_MH_SIZE + NET_SKB_PAD);
skb_put(skb, rx_bytes);
err_release: /* Release all used data descriptors; header descriptors must not * be DMA-unmapped.
*/
mvneta_release_descs(pp, txq, first_desc, desc_count - 1); return 0;
}
/* Handle tx fragmentation processing */ staticint mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, struct mvneta_tx_queue *txq)
{ struct mvneta_tx_desc *tx_desc; int i, nr_frags = skb_shinfo(skb)->nr_frags; int first_desc = txq->txq_put_index;
for (i = 0; i < nr_frags; i++) { struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; void *addr = skb_frag_address(frag);
if (dma_mapping_error(pp->dev->dev.parent,
tx_desc->buf_phys_addr)) {
mvneta_txq_desc_put(txq); goto error;
}
if (i == nr_frags - 1) { /* Last descriptor */
tx_desc->command = MVNETA_TXD_L_DESC | MVNETA_TXD_Z_PAD;
buf->skb = skb;
} else { /* Descriptor in the middle: Not First, Not Last */
tx_desc->command = 0;
buf->skb = NULL;
}
buf->type = MVNETA_TYPE_SKB;
mvneta_txq_inc_put(txq);
}
return 0;
error: /* Release all descriptors that were used to map fragments of * this packet, as well as the corresponding DMA mappings
*/
mvneta_release_descs(pp, txq, first_desc, i - 1); return -ENOMEM;
}
/* Handle tx done - called in softirq context. The <cause_tx_done> argument * must be a valid cause according to MVNETA_TXQ_INTR_MASK_ALL.
*/ staticvoid mvneta_tx_done_gbe(struct mvneta_port *pp, u32 cause_tx_done)
{ struct mvneta_tx_queue *txq; struct netdev_queue *nq; int cpu = smp_processor_id();
while (cause_tx_done) {
txq = mvneta_tx_done_policy(pp, cause_tx_done);
/* Compute crc8 of the specified address, using a unique algorithm , * according to hw spec, different than generic crc8 algorithm
*/ staticint mvneta_addr_crc(unsignedchar *addr)
{ int crc = 0; int i;
/* This method controls the net device special MAC multicast support. * The Special Multicast Table for MAC addresses supports MAC of the form * 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF). * The MAC DA[7:0] bits are used as a pointer to the Special Multicast * Table entries in the DA-Filter table. This method set the Special * Multicast Table appropriate entry.
*/ staticvoid mvneta_set_special_mcast_addr(struct mvneta_port *pp, unsignedchar last_byte, int queue)
{ unsignedint smc_table_reg; unsignedint tbl_offset; unsignedint reg_offset;
/* Register offset from SMC table base */
tbl_offset = (last_byte / 4); /* Entry offset within the above reg */
reg_offset = last_byte % 4;
/* This method controls the network device Other MAC multicast support. * The Other Multicast Table is used for multicast of another type. * A CRC-8 is used as an index to the Other Multicast Table entries * in the DA-Filter table. * The method gets the CRC-8 value from the calling routine and * sets the Other Multicast Table appropriate entry according to the * specified CRC-8 .
*/ staticvoid mvneta_set_other_mcast_addr(struct mvneta_port *pp, unsignedchar crc8, int queue)
{ unsignedint omc_table_reg; unsignedint tbl_offset; unsignedint reg_offset;
tbl_offset = (crc8 / 4) * 4; /* Register offset from OMC table base */
reg_offset = crc8 % 4; /* Entry offset within the above reg */
/* The network device supports multicast using two tables: * 1) Special Multicast Table for MAC addresses of the form * 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0xFF). * The MAC DA[7:0] bits are used as a pointer to the Special Multicast * Table entries in the DA-Filter table. * 2) Other Multicast Table for multicast of another type. A CRC-8 value * is used as an index to the Other Multicast Table entries in the * DA-Filter table.
*/ staticint mvneta_mcast_addr_set(struct mvneta_port *pp, unsignedchar *p_addr, int queue)
{ unsignedchar crc_result = 0;
/* NAPI handler * Bits 0 - 7 of the causeRxTx register indicate that are transmitted * packets on the corresponding TXQ (Bit 0 is for TX queue 1). * Bits 8 -15 of the cause Rx Tx register indicate that are received * packets on the corresponding RXQ (Bit 8 is for RX queue 0). * Each CPU has its own causeRxTx register
*/ staticint mvneta_poll(struct napi_struct *napi, int budget)
{ int rx_done = 0;
u32 cause_rx_tx; int rx_queue; struct mvneta_port *pp = netdev_priv(napi->dev); struct mvneta_pcpu_port *port = this_cpu_ptr(pp->ports);
if (!netif_running(pp->dev)) {
napi_complete(napi); return rx_done;
}
/* Read cause register */
cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE); if (cause_rx_tx & MVNETA_MISCINTR_INTR_MASK) {
u32 cause_misc = mvreg_read(pp, MVNETA_INTR_MISC_CAUSE);
mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
if (cause_misc & (MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE))
mvneta_link_change(pp);
}
/* For the case where the last mvneta_poll did not process all * RX packets
*/
cause_rx_tx |= pp->neta_armada3700 ? pp->cause_rx_tx :
port->cause_rx_tx;
/* Handle rxq fill: allocates rxq skbs; called when initializing a port */ staticint mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int num)
{ int i, err;
for (i = 0; i < num; i++) {
memset(rxq->descs + i, 0, sizeof(struct mvneta_rx_desc)); if (mvneta_rx_refill(pp, rxq->descs + i, rxq,
GFP_KERNEL) != 0) {
netdev_err(pp->dev, "%s:rxq %d, %d of %d buffs filled\n",
__func__, rxq->id, i, num); break;
}
}
/* Add this number of RX descriptors as non occupied (ready to * get packets)
*/
mvneta_rxq_non_occup_desc_add(pp, rxq, i);
return i;
}
/* Free all packets pending transmit from all TXQs and reset TX port */ staticvoid mvneta_tx_reset(struct mvneta_port *pp)
{ int queue;
/* free the skb's in the tx ring */ for (queue = 0; queue < txq_number; queue++)
mvneta_txq_done_force(pp, &pp->txqs[queue]);
mvneta_rxq_bm_enable(pp, rxq); /* Fill RXQ with buffers from RX pool */
mvneta_rxq_long_pool_set(pp, rxq);
mvneta_rxq_short_pool_set(pp, rxq);
mvneta_rxq_non_occup_desc_add(pp, rxq, rxq->size);
}
}
/* A queue must always have room for at least one skb. * Therefore, stop the queue when the free entries reaches * the maximum number of descriptors per skb.
*/
txq->tx_stop_threshold = txq->size - MVNETA_MAX_SKB_DESCS;
txq->tx_wake_threshold = txq->tx_stop_threshold / 2;
/* Allocate memory for TX descriptors */
txq->descs = dma_alloc_coherent(pp->dev->dev.parent,
txq->size * MVNETA_DESC_ALIGNED_SIZE,
&txq->descs_phys, GFP_KERNEL); if (!txq->descs) return -ENOMEM;
txq->last_desc = txq->size - 1;
txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL); if (!txq->buf) return -ENOMEM;
/* Allocate DMA buffers for TSO MAC/IP/TCP headers */
err = mvneta_alloc_tso_hdrs(pp, txq); if (err) return err;
/* Setup XPS mapping */ if (pp->neta_armada3700)
cpu = 0; elseif (txq_number > 1)
cpu = txq->id % num_present_cpus(); else
cpu = pp->rxq_def % num_present_cpus();
cpumask_set_cpu(cpu, &txq->affinity_mask);
netif_set_xps_queue(pp->dev, &txq->affinity_mask, txq->id);
return 0;
}
staticvoid mvneta_txq_hw_init(struct mvneta_port *pp, struct mvneta_tx_queue *txq)
{ /* Set maximum bandwidth for enabled TXQs */
mvreg_write(pp, MVETH_TXQ_TOKEN_CFG_REG(txq->id), 0x03ffffff);
mvreg_write(pp, MVETH_TXQ_TOKEN_COUNT_REG(txq->id), 0x3fffffff);
/* Change the device mtu */ staticint mvneta_change_mtu(struct net_device *dev, int mtu)
{ struct mvneta_port *pp = netdev_priv(dev); struct bpf_prog *prog = pp->xdp_prog; int ret;
if (!IS_ALIGNED(MVNETA_RX_PKT_SIZE(mtu), 8)) {
netdev_info(dev, "Illegal MTU value %d, rounding to %d\n",
mtu, ALIGN(MVNETA_RX_PKT_SIZE(mtu), 8));
mtu = ALIGN(MVNETA_RX_PKT_SIZE(mtu), 8);
}
if (prog && !prog->aux->xdp_has_frags &&
mtu > MVNETA_MAX_RX_BUF_SIZE) {
netdev_info(dev, "Illegal MTU %d for XDP prog without frags\n",
mtu);
return -EINVAL;
}
WRITE_ONCE(dev->mtu, mtu);
if (!netif_running(dev)) { if (pp->bm_priv)
mvneta_bm_update_mtu(pp, mtu);
netdev_update_features(dev); return 0;
}
/* The interface is running, so we have to force a * reallocation of the queues
*/
mvneta_stop_dev(pp);
on_each_cpu(mvneta_percpu_disable, pp, true);
mvneta_cleanup_txqs(pp);
mvneta_cleanup_rxqs(pp);
if (pp->bm_priv)
mvneta_bm_update_mtu(pp, mtu);
pp->pkt_size = MVNETA_RX_PKT_SIZE(dev->mtu);
ret = mvneta_setup_rxqs(pp); if (ret) {
netdev_err(dev, "unable to setup rxqs after MTU change\n"); return ret;
}
ret = mvneta_setup_txqs(pp); if (ret) {
netdev_err(dev, "unable to setup txqs after MTU change\n"); return ret;
}
if (pp->tx_csum_limit && dev->mtu > pp->tx_csum_limit) {
features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
netdev_info(dev, "Disable IP checksum for MTU greater than %dB\n",
pp->tx_csum_limit);
}
return features;
}
/* Get mac address */ staticvoid mvneta_get_mac_addr(struct mvneta_port *pp, unsignedchar *addr)
{
u32 mac_addr_l, mac_addr_h;
staticunsignedint mvneta_pcs_inband_caps(struct phylink_pcs *pcs,
phy_interface_t interface)
{ /* When operating in an 802.3z mode, we must have AN enabled: * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... * When <PortType> = 1 (1000BASE-X) this field must be set to 1." * Therefore, inband is "required".
*/ if (phy_interface_mode_is_8023z(interface)) return LINK_INBAND_ENABLE;
/* QSGMII, SGMII and RGMII can be configured to use inband * signalling of the AN result. Indicate these as "possible".
*/ if (interface == PHY_INTERFACE_MODE_SGMII ||
interface == PHY_INTERFACE_MODE_QSGMII ||
phy_interface_mode_is_rgmii(interface)) return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
/* For any other modes, indicate that inband is not supported. */ return LINK_INBAND_DISABLE;
}
if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
mask |= MVNETA_GMAC_CONFIG_MII_SPEED |
MVNETA_GMAC_CONFIG_GMII_SPEED |
MVNETA_GMAC_CONFIG_FULL_DUPLEX;
val = MVNETA_GMAC_INBAND_AN_ENABLE;
if (interface == PHY_INTERFACE_MODE_SGMII) { /* SGMII mode receives the speed and duplex from PHY */
val |= MVNETA_GMAC_AN_SPEED_EN |
MVNETA_GMAC_AN_DUPLEX_EN;
} else { /* 802.3z mode has fixed speed and duplex */
val |= MVNETA_GMAC_CONFIG_GMII_SPEED |
MVNETA_GMAC_CONFIG_FULL_DUPLEX;
/* The FLOW_CTRL_EN bit selects either the hardware * automatically or the CONFIG_FLOW_CTRL manually * controls the GMAC pause mode.
*/ if (permit_pause_to_mac)
val |= MVNETA_GMAC_AN_FLOW_CTRL_EN;
/* Update the advertisement bits */
mask |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL; if (phylink_test(advertising, Pause))
val |= MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL;
}
} else { /* Phy or fixed speed - disable in-band AN modes */
val = 0;
}
old_an = an = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
an = (an & ~mask) | val;
changed = old_an ^ an; if (changed)
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, an);
/* We are only interested in the advertisement bits changing */ return !!(changed & MVNETA_GMAC_ADVERT_SYM_FLOW_CTRL);
}
if (pp->phy_interface != interface ||
phylink_autoneg_inband(mode)) { /* Force the link down when changing the interface or if in * in-band mode. According to Armada 370 documentation, we * can only change the port mode and in-band enable when the * link is down.
*/
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
val |= MVNETA_GMAC_FORCE_LINK_DOWN;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}
if (pp->phy_interface != interface)
WARN_ON(phy_power_off(pp->comphy));
/* Enable the 1ms clock */ if (phylink_autoneg_inband(mode)) { unsignedlong rate = clk_get_rate(pp->clk);
/* Even though it might look weird, when we're configured in * SGMII or QSGMII mode, the RGMII bit needs to be set.
*/
new_ctrl2 |= MVNETA_GMAC2_PORT_RGMII;
if (!phylink_autoneg_inband(mode)) { /* Phy or fixed speed - nothing to do, leave the * configured speed, duplex and flow control as-is.
*/
} elseif (state->interface == PHY_INTERFACE_MODE_SGMII) { /* SGMII mode receives the state from the PHY */
new_ctrl2 |= MVNETA_GMAC2_INBAND_AN_ENABLE;
} else { /* 802.3z negotiation - only 1000base-X */
new_ctrl0 |= MVNETA_GMAC0_PORT_1000BASE_X;
}
/* When at 2.5G, the link partner can send frames with shortened * preambles.
*/ if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
new_ctrl4 |= MVNETA_GMAC4_SHORT_PREAMBLE_ENABLE;
if (new_ctrl0 != gmac_ctrl0)
mvreg_write(pp, MVNETA_GMAC_CTRL_0, new_ctrl0); if (new_ctrl2 != gmac_ctrl2)
mvreg_write(pp, MVNETA_GMAC_CTRL_2, new_ctrl2); if (new_ctrl4 != gmac_ctrl4)
mvreg_write(pp, MVNETA_GMAC_CTRL_4, new_ctrl4);
if (gmac_ctrl2 & MVNETA_GMAC2_PORT_RESET) { while ((mvreg_read(pp, MVNETA_GMAC_CTRL_2) &
MVNETA_GMAC2_PORT_RESET) != 0) continue;
}
}
/* Disable 1ms clock if not in in-band mode */ if (!phylink_autoneg_inband(mode)) {
clk = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
clk &= ~MVNETA_GMAC_1MS_CLOCK_ENABLE;
mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, clk);
}
if (pp->phy_interface != interface) /* Enable the Serdes PHY */
WARN_ON(mvneta_config_interface(pp, interface));
/* Allow the link to come up if in in-band mode, otherwise the * link is forced via mac_link_down()/mac_link_up()
*/ if (phylink_autoneg_inband(mode)) {
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~MVNETA_GMAC_FORCE_LINK_DOWN;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}
if (!phylink_autoneg_inband(mode)) {
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
val |= MVNETA_GMAC_FORCE_LINK_DOWN;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}
}
if (!phylink_autoneg_inband(mode)) {
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~(MVNETA_GMAC_FORCE_LINK_DOWN |
MVNETA_GMAC_CONFIG_MII_SPEED |
MVNETA_GMAC_CONFIG_GMII_SPEED |
MVNETA_GMAC_CONFIG_FLOW_CTRL |
MVNETA_GMAC_CONFIG_FULL_DUPLEX);
val |= MVNETA_GMAC_FORCE_LINK_PASS;
if (speed == SPEED_1000 || speed == SPEED_2500)
val |= MVNETA_GMAC_CONFIG_GMII_SPEED; elseif (speed == SPEED_100)
val |= MVNETA_GMAC_CONFIG_MII_SPEED;
if (duplex == DUPLEX_FULL)
val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
if (tx_pause || rx_pause)
val |= MVNETA_GMAC_CONFIG_FLOW_CTRL;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
} else { /* When inband doesn't cover flow control or flow control is * disabled, we need to manually configure it. This bit will * only have effect if MVNETA_GMAC_AN_FLOW_CTRL_EN is unset.
*/
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~MVNETA_GMAC_CONFIG_FLOW_CTRL;
if (tx_pause || rx_pause)
val |= MVNETA_GMAC_CONFIG_FLOW_CTRL;
status = mvreg_read(pp, MVNETA_GMAC_STATUS); if (status & MVNETA_GMAC_SPEED_1000) { /* At 1G speeds, the timer resolution are 1us, and * 802.3 says tw is 16.5us. Round up to 17us.
*/
tw = 17;
ts = timer;
} else { /* At 100M speeds, the timer resolutions are 10us, and * 802.3 says tw is 30us.
*/
tw = 3;
ts = DIV_ROUND_UP(timer, 10);
}
/* Electing a CPU must be done in an atomic way: it should be done * after or before the removal/insertion of a CPU and this function is * not reentrant.
*/ staticvoid mvneta_percpu_elect(struct mvneta_port *pp)
{ int elected_cpu = 0, max_cpu, cpu;
/* Use the cpu associated to the rxq when it is online, in all * the other cases, use the cpu 0 which can't be offline.
*/ if (pp->rxq_def < nr_cpu_ids && cpu_online(pp->rxq_def))
elected_cpu = pp->rxq_def;
max_cpu = num_present_cpus();
for_each_online_cpu(cpu) { int rxq_map = 0, txq_map = 0; int rxq;
for (rxq = 0; rxq < rxq_number; rxq++) if ((rxq % max_cpu) == cpu)
rxq_map |= MVNETA_CPU_RXQ_ACCESS(rxq);
if (cpu == elected_cpu) /* Map the default receive queue to the elected CPU */
rxq_map |= MVNETA_CPU_RXQ_ACCESS(pp->rxq_def);
/* We update the TX queue map only if we have one * queue. In this case we associate the TX queue to * the CPU bound to the default RX queue
*/ if (txq_number == 1)
txq_map = (cpu == elected_cpu) ?
MVNETA_CPU_TXQ_ACCESS(0) : 0; else
txq_map = mvreg_read(pp, MVNETA_CPU_MAP(cpu)) &
MVNETA_CPU_TXQ_ACCESS_ALL_MASK;
/* Armada 3700's per-cpu interrupt for mvneta is broken, all interrupts * are routed to CPU 0, so we don't need all the cpu-hotplug support
*/ if (pp->neta_armada3700) return 0;
netdev_lock(port->napi.dev);
spin_lock(&pp->lock); /* * Configuring the driver for a new CPU while the driver is * stopping is racy, so just avoid it.
*/ if (pp->is_stopped) {
spin_unlock(&pp->lock);
netdev_unlock(port->napi.dev); return 0;
}
netif_tx_stop_all_queues(pp->dev);
/* * We have to synchronise on tha napi of each CPU except the one * just being woken up
*/
for_each_online_cpu(other_cpu) { if (other_cpu != cpu) { struct mvneta_pcpu_port *other_port =
per_cpu_ptr(pp->ports, other_cpu);
napi_synchronize(&other_port->napi);
}
}
/* Mask all ethernet port interrupts */
on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
napi_enable_locked(&port->napi);
/* * Enable per-CPU interrupts on the CPU that is * brought up.
*/
mvneta_percpu_enable(pp);
/* * Enable per-CPU interrupt on the one CPU we care * about.
*/
mvneta_percpu_elect(pp);
/* Unmask all ethernet port interrupts */
on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
mvreg_write(pp, MVNETA_INTR_MISC_MASK,
MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE);
netif_tx_start_all_queues(pp->dev);
spin_unlock(&pp->lock);
netdev_unlock(port->napi.dev);
/* * Thanks to this lock we are sure that any pending cpu election is * done.
*/
spin_lock(&pp->lock); /* Mask all ethernet port interrupts */
on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
spin_unlock(&pp->lock);
napi_synchronize(&port->napi);
napi_disable(&port->napi); /* Disable per-CPU interrupts on the CPU that is brought down. */
mvneta_percpu_disable(pp); return 0;
}
/* Check if a new CPU must be elected now this on is down */
spin_lock(&pp->lock);
mvneta_percpu_elect(pp);
spin_unlock(&pp->lock); /* Unmask all ethernet port interrupts */
on_each_cpu(mvneta_percpu_unmask_interrupt, pp, true);
mvreg_write(pp, MVNETA_INTR_MISC_MASK,
MVNETA_CAUSE_PHY_STATUS_CHANGE |
MVNETA_CAUSE_LINK_CHANGE);
netif_tx_start_all_queues(pp->dev); return 0;
}
ret = mvneta_setup_txqs(pp); if (ret) goto err_cleanup_rxqs;
/* Connect to port interrupt line */ if (pp->neta_armada3700)
ret = request_irq(pp->dev->irq, mvneta_isr, 0,
dev->name, pp); else
ret = request_percpu_irq(pp->dev->irq, mvneta_percpu_isr,
dev->name, pp->ports); if (ret) {
netdev_err(pp->dev, "cannot request irq %d\n", pp->dev->irq); goto err_cleanup_txqs;
}
if (!pp->neta_armada3700) { /* Enable per-CPU interrupt on all the CPU to handle our RX * queue interrupts
*/
on_each_cpu(mvneta_percpu_enable, pp, true);
pp->is_stopped = false; /* Register a CPU notifier to handle the case where our CPU * might be taken offline.
*/
ret = cpuhp_state_add_instance_nocalls(online_hpstate,
&pp->node_online); if (ret) goto err_free_irq;
ret = cpuhp_state_add_instance_nocalls(CPUHP_NET_MVNETA_DEAD,
&pp->node_dead); if (ret) goto err_free_online_hp;
}
ret = mvneta_mdio_probe(pp); if (ret < 0) {
netdev_err(dev, "cannot probe MDIO bus\n"); goto err_free_dead_hp;
}
/* Stop the port, free port interrupt line */ staticint mvneta_stop(struct net_device *dev)
{ struct mvneta_port *pp = netdev_priv(dev);
if (!pp->neta_armada3700) { /* Inform that we are stopping so we don't want to setup the * driver for new CPUs in the notifiers. The code of the * notifier for CPU online is protected by the same spinlock, * so when we get the lock, the notifier work is done.
*/
spin_lock(&pp->lock);
pp->is_stopped = true;
spin_unlock(&pp->lock);
if (prog && !prog->aux->xdp_has_frags &&
dev->mtu > MVNETA_MAX_RX_BUF_SIZE) {
NL_SET_ERR_MSG_MOD(extack, "prog does not support XDP frags"); return -EOPNOTSUPP;
}
if (pp->bm_priv) {
NL_SET_ERR_MSG_MOD(extack, "Hardware Buffer Management not supported on XDP"); return -EOPNOTSUPP;
}
need_update = !!pp->xdp_prog != !!prog; if (running && need_update)
mvneta_stop(dev);
old_prog = xchg(&pp->xdp_prog, prog); if (old_prog)
bpf_prog_put(old_prog);
if (running && need_update) return mvneta_open(dev);
pp->tx_ring_size = clamp_t(u16, ring->tx_pending,
MVNETA_MAX_SKB_DESCS * 2, MVNETA_MAX_TXD); if (pp->tx_ring_size != ring->tx_pending)
netdev_warn(dev, "TX queue size set to %u (requested %u)\n",
pp->tx_ring_size, ring->tx_pending);
if (netif_running(dev)) {
mvneta_stop(dev); if (mvneta_open(dev)) {
netdev_err(dev, "error on opening device after ring param change\n"); return -ENOMEM;
}
}
if (!pp->neta_armada3700) { /* We have to synchronise on the napi of each CPU */
for_each_online_cpu(cpu) { struct mvneta_pcpu_port *pcpu_port =
per_cpu_ptr(pp->ports, cpu);
/* Update val of portCfg register accordingly with all RxQueue types */
val = MVNETA_PORT_CONFIG_DEFL_VALUE(pp->rxq_def);
mvreg_write(pp, MVNETA_PORT_CONFIG, val);
/* Update the elected CPU matching the new rxq_def */
spin_lock(&pp->lock);
mvneta_percpu_elect(pp);
spin_unlock(&pp->lock);
if (!pp->neta_armada3700) { /* We have to synchronise on the napi of each CPU */
for_each_online_cpu(cpu) { struct mvneta_pcpu_port *pcpu_port =
per_cpu_ptr(pp->ports, cpu);
/* Current code for Armada 3700 doesn't support RSS features yet */ if (pp->neta_armada3700) return -EOPNOTSUPP;
/* We require at least one supported parameter to be changed * and no change in any of the unsupported parameters
*/ if (rxfh->key ||
(rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
rxfh->hfunc != ETH_RSS_HASH_TOP)) return -EOPNOTSUPP;
/* The Armada 37x documents do not give limits for this other than * it being an 8-bit register.
*/ if (eee->tx_lpi_enabled && eee->tx_lpi_timer > 255) return -EINVAL;
/* Power up the port */ staticint mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
{ /* MAC Cause register should be cleared */
mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
phy_interface_set_rgmii(pp->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_QSGMII,
pp->phylink_config.supported_interfaces); if (comphy) { /* If a COMPHY is present, we can support any of the serdes * modes and switch between them.
*/
__set_bit(PHY_INTERFACE_MODE_SGMII,
pp->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX,
pp->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_2500BASEX,
pp->phylink_config.supported_interfaces);
} elseif (phy_mode == PHY_INTERFACE_MODE_2500BASEX) { /* No COMPHY, with only 2500BASE-X mode supported */
__set_bit(PHY_INTERFACE_MODE_2500BASEX,
pp->phylink_config.supported_interfaces);
} elseif (phy_mode == PHY_INTERFACE_MODE_1000BASEX ||
phy_mode == PHY_INTERFACE_MODE_SGMII) { /* No COMPHY, we can switch between 1000BASE-X and SGMII */
__set_bit(PHY_INTERFACE_MODE_1000BASEX,
pp->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII,
pp->phylink_config.supported_interfaces);
}
/* Obtain access to BM resources if enabled and already initialized */
bm_node = of_parse_phandle(dn, "buffer-manager", 0); if (bm_node) {
pp->bm_priv = mvneta_bm_get(bm_node); if (pp->bm_priv) {
err = mvneta_bm_port_init(pdev, pp); if (err < 0) {
dev_info(&pdev->dev, "use SW buffer management\n");
mvneta_bm_put(pp->bm_priv);
pp->bm_priv = NULL;
}
} /* Set RX packet offset correction for platforms, whose * NET_SKB_PAD, exceeds 64B. It should be 64B for 64-bit * platforms and 0B for 32-bit ones.
*/
pp->rx_offset_correction = max(0,
NET_SKB_PAD -
MVNETA_RX_PKT_OFFSET_CORRECTION);
}
of_node_put(bm_node);
/* sw buffer management */ if (!pp->bm_priv)
pp->rx_offset_correction = MVNETA_SKB_HEADROOM;
err = mvneta_init(&pdev->dev, pp); if (err < 0) goto err_netdev;
err = mvneta_port_power_up(pp, pp->phy_interface); if (err < 0) {
dev_err(&pdev->dev, "can't power up port\n"); goto err_netdev;
}
/* Armada3700 network controller does not support per-cpu * operation, so only single NAPI should be initialized.
*/ if (pp->neta_armada3700) {
netif_napi_add(dev, &pp->napi, mvneta_poll);
} else {
for_each_present_cpu(cpu) { struct mvneta_pcpu_port *port =
per_cpu_ptr(pp->ports, cpu);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.111Bemerkung:
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.