/* The values of the bucket refill base period and refill period are taken from *thereferencemanual,andaddsuptoabaseresolutionof10Kbps.Thisallows *tocoverallrate-limitvaluesfrom10Kbpsupto5Gbps
*/
/* 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 *amultipleofthatvalue.
*/ #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 *byMarvellswitcheswhenaspecifichardwaremodeisenabled(not *supportedbythisdriver)orisfilledautomaticallybyzeroeson *theRXside.ThosetwobytesbeingatthefrontoftheEthernet *header,theyallowtohavetheIPheaderalignedona4bytes *boundaryautomatically:thehardwareskipsthosetwobytesonits *own.
*/ #define MVNETA_MH_SIZE 2
/* Number of bytes to be taken into account by HW when putting incoming data *tothebuffers.ItisneededincaseNET_SKB_PADexceedsmaximumpacket *offsetsupportedinMVNETA_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 *layoutofthetransmitandreceptionDMAdescriptors,andtheir *layoutisthereforedefinedbythehardwaredesign
*/
/* Checks whether the RX descriptor having this status is both the first *andthelastdescriptorfortheRXpacket.EachRXpacketiscurrently *receivedthroughasingleRXdescriptor,sonothavingeachRX *descriptorwithitsfirstandlastbitssetisanerror
*/ 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 *beaddedatonce
*/ 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 *frommvneta_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;
} return0;
}
/* Assign and initialize pools for port. In case of fail *buffermanagerwillremaindisabledforcurrentport.
*/ 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 *commandforactivechannelsonly
*/
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 *mappedtothisCPUwillbeunmasked
*/
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 *mappedtothisCPUwillbemasked
*/
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 *mappedtothisCPUwillbecleared
*/
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: *ClearsinterruptCauseandMaskregisters. *ClearsallMACtables. *Setsdefaultstoallregisters. *ResetsRXandTXdescriptorrings. *ResetsPHY. *Thismethodcanbecalledaftermvneta_port_down()toreturntheport *settingstodefaults.
*/ 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 *TXqueuesmodulotheirnumber.IfthereisonlyoneTX *queuethenitisassignedtotheCPUassociatedtothe *defaultRXqueue.
*/
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 *whichwillallowtogetalltheirqonasingle *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 *kernelphylibtodothis.
*/
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 *willbegeneratedbyHW.
*/ 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. *Thenumberofsentdescriptorsisreturned.
*/ 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 *formtx_donereg.<cause>mustnotbenull.Thereturnvalueisalwaysa *validqueueformatchingthefirstonefoundin<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 *theskbissuccessfullybuiltornot.
*/
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 *beDMA-unmapped.
*/
mvneta_release_descs(pp, txq, first_desc, desc_count - 1); return0;
}
/* 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);
}
return0;
error: /* Release all descriptors that were used to map fragments of *thispacket,aswellasthecorrespondingDMAmappings
*/
mvneta_release_descs(pp, txq, first_desc, i - 1); return -ENOMEM;
}
/* Compute crc8 of the specified address, using a unique algorithm , *accordingtohwspec,differentthangenericcrc8algorithm
*/ staticint mvneta_addr_crc(unsignedchar *addr)
{ int crc = 0; int i;
/* 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 *getpackets)
*/
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,stopthequeuewhenthefreeentriesreaches *themaximumnumberofdescriptorsperskb.
*/
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);
return0;
}
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); return0;
}
/* The interface is running, so we have to force a *reallocationofthequeues
*/
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: *"Bit2FieldInBandAnEnIn-bandAuto-Negotiationenable.... *When<PortType>=1(1000BASE-X)thisfieldmustbesetto1." *Therefore,inbandis"required".
*/ if (phy_interface_mode_is_8023z(interface)) return LINK_INBAND_ENABLE;
/* QSGMII, SGMII and RGMII can be configured to use inband *signallingoftheANresult.Indicatetheseas"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 *automaticallyortheCONFIG_FLOW_CTRLmanually *controlstheGMACpausemode.
*/ 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-bandmode.AccordingtoArmada370documentation,we *canonlychangetheportmodeandin-bandenablewhenthe *linkisdown.
*/
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);
if (!phylink_autoneg_inband(mode)) { /* Phy or fixed speed - nothing to do, leave the *configuredspeed,duplexandflowcontrolas-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 *linkisforcedviamac_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,weneedtomanuallyconfigureit.Thisbitwill *onlyhaveeffectifMVNETA_GMAC_AN_FLOW_CTRL_ENisunset.
*/
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.3saystwis16.5us.Roundupto17us.
*/
tw = 17;
ts = timer;
} else { /* At 100M speeds, the timer resolutions are 10us, and *802.3saystwis30us.
*/
tw = 3;
ts = DIV_ROUND_UP(timer, 10);
}
/* Electing a CPU must be done in an atomic way: it should be done *afterorbeforetheremoval/insertionofaCPUandthisfunctionis *notreentrant.
*/ 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 *theothercases,usethecpu0whichcan'tbeoffline.
*/ 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.InthiscaseweassociatetheTXqueueto *theCPUboundtothedefaultRXqueue
*/ 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 *areroutedtoCPU0,sowedon'tneedallthecpu-hotplugsupport
*/ if (pp->neta_armada3700) return0;
/* *Thankstothislockwearesurethatanypendingcpuelectionis *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); return0;
}
/* 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); return0;
}
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 *queueinterrupts
*/
on_each_cpu(mvneta_percpu_enable, pp, true);
pp->is_stopped = false; /* Register a CPU notifier to handle the case where our CPU *mightbetakenoffline.
*/
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 *driverfornewCPUsinthenotifiers.Thecodeofthe *notifierforCPUonlineisprotectedbythesamespinlock, *sowhenwegetthelock,thenotifierworkisdone.
*/
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 *andnochangeinanyoftheunsupportedparameters
*/ 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 *itbeingan8-bitregister.
*/ 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 *modesandswitchbetweenthem.
*/
__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);
}
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.