// SPDX-License-Identifier: GPL-2.0-only /* * This is the driver for the GMAC on-chip Ethernet controller for ST SoCs. * DWC Ether MAC version 4.00 has been used for developing this code. * * This only implements the mac core functions for this chip. * * Copyright (C) 2015 STMicroelectronics Ltd * * Author: Alexandre Torgue <alexandre.torgue@st.com>
*/
value &= hw->link.speed_mask; switch (hw->ps) { case SPEED_1000:
value |= hw->link.speed1000; break; case SPEED_100:
value |= hw->link.speed100; break; case SPEED_10:
value |= hw->link.speed10; break;
}
}
writel(value, ioaddr + GMAC_CONFIG);
/* Configure LPI 1us counter to number of CSR clock ticks in 1us - 1 */
clk_rate = clk_get_rate(priv->plat->stmmac_clk);
writel((clk_rate / 1000000) - 1, ioaddr + GMAC4_MAC_ONEUS_TIC_COUNTER);
/* Enable GMAC interrupts */
value = GMAC_INT_DEFAULT_ENABLE;
if (hw->pcs)
value |= GMAC_PCS_IRQ_DEFAULT;
writel(value, ioaddr + GMAC_INT_EN);
if (GMAC_INT_DEFAULT_ENABLE & GMAC_INT_TSIE)
init_waitqueue_head(&priv->tstamp_busy_wait);
}
value &= GMAC_RX_QUEUE_CLEAR(queue); if (mode == MTL_QUEUE_AVB)
value |= GMAC_RX_AV_QUEUE_ENABLE(queue); elseif (mode == MTL_QUEUE_DCB)
value |= GMAC_RX_DCB_QUEUE_ENABLE(queue);
/* The software must ensure that the same priority * is not mapped to multiple Rx queues
*/ for (i = 0; i < 4; i++)
clear_mask |= ((prio << GMAC_RXQCTRL_PSRQX_SHIFT(i)) &
GMAC_RXQCTRL_PSRQX_MASK(i));
ctrl2 &= ~clear_mask;
ctrl3 &= ~clear_mask;
/* First assign new priorities to a queue, then * clear them from others queues
*/ if (queue < 4) {
ctrl2 |= (prio << GMAC_RXQCTRL_PSRQX_SHIFT(queue)) &
GMAC_RXQCTRL_PSRQX_MASK(queue);
/* routing configuration */
value &= ~route_possibilities[packet - 1].reg_mask;
value |= (queue << route_possibilities[packet-1].reg_shift) &
route_possibilities[packet - 1].reg_mask;
/* some packets require extra ops */ if (packet == PACKET_AVCPQ) {
value &= ~GMAC_RXQCTRL_TACPQE;
value |= 0x1 << GMAC_RXQCTRL_TACPQE_SHIFT;
} elseif (packet == PACKET_MCBCQ) {
value &= ~GMAC_RXQCTRL_MCBCQEN;
value |= 0x1 << GMAC_RXQCTRL_MCBCQEN_SHIFT;
}
value &= ~MTL_OPERATION_RAA; switch (rx_alg) { case MTL_RX_ALGORITHM_SP:
value |= MTL_OPERATION_RAA_SP; break; case MTL_RX_ALGORITHM_WSP:
value |= MTL_OPERATION_RAA_WSP; break; default: break;
}
value &= ~MTL_OPERATION_SCHALG_MASK; switch (tx_alg) { case MTL_TX_ALGORITHM_WRR:
value |= MTL_OPERATION_SCHALG_WRR; break; case MTL_TX_ALGORITHM_WFQ:
value |= MTL_OPERATION_SCHALG_WFQ; break; case MTL_TX_ALGORITHM_DWRR:
value |= MTL_OPERATION_SCHALG_DWRR; break; case MTL_TX_ALGORITHM_SP:
value |= MTL_OPERATION_SCHALG_SP; break; default: break;
}
if (mode & WAKE_MAGIC) {
pr_debug("GMAC: WOL Magic frame\n");
pmt |= power_down | magic_pkt_en;
} if (mode & WAKE_UCAST) {
pr_debug("GMAC: WOL on global unicast\n");
pmt |= power_down | global_unicast | wake_up_frame_en;
}
if (pmt) { /* The receiver must be enabled for WOL before powering down */
config = readl(ioaddr + GMAC_CONFIG);
config |= GMAC_CONFIG_RE;
writel(config, ioaddr + GMAC_CONFIG);
}
writel(pmt, ioaddr + GMAC_PMT);
}
if (link)
value |= LPI_CTRL_STATUS_PLS; else
value &= ~LPI_CTRL_STATUS_PLS;
writel(value, ioaddr + GMAC4_LPI_CTRL_STATUS);
}
staticvoid dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
{ void __iomem *ioaddr = hw->pcsr; int value = ((tw & 0xffff)) | ((ls & 0x3ff) << 16);
/* Program the timers in the LPI timer control register: * LS: minimum time (ms) for which the link * status from PHY should be ok before transmitting * the LPI pattern. * TW: minimum time (us) for which the core waits * after it has stopped transmitting the LPI pattern.
*/
writel(value, ioaddr + GMAC4_LPI_TIMER_CTRL);
}
value = readl(ioaddr + GMAC_PACKET_FILTER);
value &= ~GMAC_PACKET_FILTER_HMC;
value &= ~GMAC_PACKET_FILTER_HPF;
value &= ~GMAC_PACKET_FILTER_PCF;
value &= ~GMAC_PACKET_FILTER_PM;
value &= ~GMAC_PACKET_FILTER_PR;
value &= ~GMAC_PACKET_FILTER_RA; if (dev->flags & IFF_PROMISC) { /* VLAN Tag Filter Fail Packets Queuing */ if (hw->vlan_fail_q_en) {
value = readl(ioaddr + GMAC_RXQ_CTRL4);
value &= ~GMAC_RXQCTRL_VFFQ_MASK;
value |= GMAC_RXQCTRL_VFFQE |
(hw->vlan_fail_q << GMAC_RXQCTRL_VFFQ_SHIFT);
writel(value, ioaddr + GMAC_RXQ_CTRL4);
value = GMAC_PACKET_FILTER_PR | GMAC_PACKET_FILTER_RA;
} else {
value = GMAC_PACKET_FILTER_PR | GMAC_PACKET_FILTER_PCF;
}
} elseif ((dev->flags & IFF_ALLMULTI) ||
(netdev_mc_count(dev) > hw->multicast_filter_bins)) { /* Pass all multi */
value |= GMAC_PACKET_FILTER_PM; /* Set all the bits of the HASH tab */
memset(mc_filter, 0xff, sizeof(mc_filter));
} elseif (!netdev_mc_empty(dev) && (dev->flags & IFF_MULTICAST)) { struct netdev_hw_addr *ha;
/* Hash filter for multicast */
value |= GMAC_PACKET_FILTER_HMC;
netdev_for_each_mc_addr(ha, dev) { /* The upper n bits of the calculated CRC are used to * index the contents of the hash table. The number of * bits used depends on the hardware configuration * selected at core configuration time.
*/
u32 bit_nr = bitrev32(~crc32_le(~0, ha->addr,
ETH_ALEN)) >> (32 - mcbitslog2); /* The most significant bit determines the register to * use (H/L) while the other 5 bits determine the bit * within the register.
*/
mc_filter[bit_nr >> 5] |= (1 << (bit_nr & 0x1f));
}
}
for (i = 0; i < numhashregs; i++)
writel(mc_filter[i], ioaddr + GMAC_HASH_TAB(i));
value |= GMAC_PACKET_FILTER_HPF;
/* Handle multiple unicast addresses */ if (netdev_uc_count(dev) > hw->unicast_filter_entries) { /* Switch to promiscuous mode if more than 128 addrs * are required
*/
value |= GMAC_PACKET_FILTER_PR;
} else { struct netdev_hw_addr *ha; int reg = 1;
/* Not used events (e.g. MMC interrupts) are not handled. */ if ((intr_status & mmc_tx_irq))
x->mmc_tx_irq_n++; if (unlikely(intr_status & mmc_rx_irq))
x->mmc_rx_irq_n++; if (unlikely(intr_status & mmc_rx_csum_offload_irq))
x->mmc_rx_csum_offload_irq_n++; /* Clear the PMT bits 5 and 6 by reading the PMT status reg */ if (unlikely(intr_status & pmt_irq)) {
readl(ioaddr + GMAC_PMT);
x->irq_receive_pmt_irq_n++;
}
/* MAC tx/rx EEE LPI entry/exit interrupts */ if (intr_status & lpi_irq) { /* Clear LPI interrupt by reading MAC_LPI_Control_Status */
u32 status = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
if (status & LPI_CTRL_STATUS_TLPIEN) {
ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
x->irq_tx_path_in_lpi_mode_n++;
} if (status & LPI_CTRL_STATUS_TLPIEX) {
ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
x->irq_tx_path_exit_lpi_mode_n++;
} if (status & LPI_CTRL_STATUS_RLPIEN)
x->irq_rx_path_in_lpi_mode_n++; if (status & LPI_CTRL_STATUS_RLPIEX)
x->irq_rx_path_exit_lpi_mode_n++;
}
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x); if (intr_status & PCS_RGSMIIIS_IRQ)
dwmac4_phystatus(ioaddr, x);
value = readl(ioaddr + GMAC_PACKET_FILTER);
value |= GMAC_PACKET_FILTER_IPFE;
writel(value, ioaddr + GMAC_PACKET_FILTER);
value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no));
/* For IPv6 not both SA/DA filters can be active */ if (ipv6) {
value |= GMAC_L3PEN0;
value &= ~(GMAC_L3SAM0 | GMAC_L3SAIM0);
value &= ~(GMAC_L3DAM0 | GMAC_L3DAIM0); if (sa) {
value |= GMAC_L3SAM0; if (inv)
value |= GMAC_L3SAIM0;
} else {
value |= GMAC_L3DAM0; if (inv)
value |= GMAC_L3DAIM0;
}
} else {
value &= ~GMAC_L3PEN0; if (sa) {
value |= GMAC_L3SAM0; if (inv)
value |= GMAC_L3SAIM0;
} else {
value |= GMAC_L3DAM0; if (inv)
value |= GMAC_L3DAIM0;
}
}
value = readl(ioaddr + GMAC_PACKET_FILTER);
value |= GMAC_PACKET_FILTER_IPFE;
writel(value, ioaddr + GMAC_PACKET_FILTER);
value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no)); if (udp) {
value |= GMAC_L4PEN0;
} else {
value &= ~GMAC_L4PEN0;
}
value &= ~(GMAC_L4SPM0 | GMAC_L4SPIM0);
value &= ~(GMAC_L4DPM0 | GMAC_L4DPIM0); if (sa) {
value |= GMAC_L4SPM0; if (inv)
value |= GMAC_L4SPIM0;
} else {
value |= GMAC_L4DPM0; if (inv)
value |= GMAC_L4DPIM0;
}
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.