// SPDX-License-Identifier: GPL-2.0+ /* * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) * * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which * will be much more memory efficient and will easily handle lots of * small packets. * * Much better multiple PHY support by Magnus Damm. * Copyright (c) 2000 Ericsson Radio Systems AB. * * Support for FEC controller of ColdFire processors. * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) * * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) * Copyright (c) 2004-2006 Macq Electronique SA. * * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
*/
#ifdefined(CONFIG_M5272) /* * Some hardware gets it MAC address out of local flash memory. * if this is non-zero then assume it is the address to get MAC from.
*/ #ifdefined(CONFIG_NETtel) #define FEC_FLASHMAC 0xf0006006 #elifdefined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES) #define FEC_FLASHMAC 0xf0006000 #elifdefined(CONFIG_CANCam) #define FEC_FLASHMAC 0xf0020000 #elifdefined (CONFIG_M5272C3) #define FEC_FLASHMAC (0xffe04000 + 4) #elifdefined(CONFIG_MOD5272) #define FEC_FLASHMAC 0xffc0406b #else #define FEC_FLASHMAC 0 #endif #endif/* CONFIG_M5272 */
/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets. * * 2048 byte skbufs are allocated. However, alignment requirements * varies between FEC variants. Worst case is 64, so round down by 64.
*/ #define PKT_MAXBUF_SIZE (round_down(2048 - 64, 64)) #define PKT_MINBUF_SIZE 64
/* MIB Control Register */ #define FEC_MIB_CTRLSTAT_DISABLE BIT(31)
/* * The 5270/5271/5280/5282/532x RX control register also contains maximum frame * size bits. Other FEC hardware does not, so we need to take that into * account when setting it.
*/ #ifdefined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \ defined(CONFIG_ARM64) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 #endif
/* * Coldfire does not support DMA coherent allocations, and has historically used * a band-aid with a manual flush in fec_enet_rx_queue.
*/ #ifdefined(CONFIG_COLDFIRE) && !defined(CONFIG_COLDFIRE_COHERENT_DMA) staticvoid *fec_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
gfp_t gfp)
{ return dma_alloc_noncoherent(dev, size, handle, DMA_BIDIRECTIONAL, gfp);
}
staticint
fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
{ /* Only run for packets requiring a checksum. */ if (skb->ip_summed != CHECKSUM_PARTIAL) return 0;
status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
status |= (BD_ENET_TX_TC | BD_ENET_TX_READY);
frag_len = skb_frag_size(&skb_shinfo(skb)->frags[frag]);
/* Handle the last BD specially */ if (frag == nr_frags - 1) {
status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); if (fep->bufdesc_ex) {
estatus |= BD_ENET_TX_INT; if (unlikely(skb_shinfo(skb)->tx_flags &
SKBTX_HW_TSTAMP && fep->hwts_tx_en))
estatus |= BD_ENET_TX_TS;
}
}
if (fep->bufdesc_ex) { if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(txq->bd.qid); if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
bdp->cbd_bufaddr = cpu_to_fec32(addr);
bdp->cbd_datlen = cpu_to_fec16(frag_len); /* Make sure the updates to rest of the descriptor are * performed before transferring ownership.
*/
wmb();
bdp->cbd_sc = cpu_to_fec16(status);
}
return bdp;
dma_mapping_error:
bdp = txq->bd.cur; for (i = 0; i < frag; i++) {
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
dma_unmap_single(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen), DMA_TO_DEVICE);
} return ERR_PTR(-ENOMEM);
}
entries_free = fec_enet_get_free_txdesc_num(txq); if (entries_free < MAX_SKB_FRAGS + 1) {
dev_kfree_skb_any(skb); if (net_ratelimit())
netdev_err(ndev, "NOT enough BD for SG!\n"); return NETDEV_TX_OK;
}
/* Protocol checksum off-load for TCP and UDP. */ if (fec_enet_clear_csum(skb, ndev)) {
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
}
/* Fill in a Tx ring entry */
bdp = txq->bd.cur;
last_bdp = bdp;
status = fec16_to_cpu(bdp->cbd_sc);
status &= ~BD_ENET_TX_STATS;
/* Set buffer length and buffer pointer */
bufaddr = skb->data;
buflen = skb_headlen(skb);
index = fec_enet_get_bd_index(bdp, &txq->bd); if (((unsignedlong) bufaddr) & fep->tx_align ||
fep->quirks & FEC_QUIRK_SWAP_FRAME) {
memcpy(txq->tx_bounce[index], skb->data, buflen);
bufaddr = txq->tx_bounce[index];
if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
swap_buffer(bufaddr, buflen);
}
/* Push the data cache so the CPM does not get stale memory data. */
addr = dma_map_single(&fep->pdev->dev, bufaddr, buflen, DMA_TO_DEVICE); if (dma_mapping_error(&fep->pdev->dev, addr)) {
dev_kfree_skb_any(skb); if (net_ratelimit())
netdev_err(ndev, "Tx DMA memory map failed\n"); return NETDEV_TX_OK;
}
if (nr_frags) {
last_bdp = fec_enet_txq_submit_frag_skb(txq, skb, ndev); if (IS_ERR(last_bdp)) {
dma_unmap_single(&fep->pdev->dev, addr,
buflen, DMA_TO_DEVICE);
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
}
} else {
status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); if (fep->bufdesc_ex) {
estatus = BD_ENET_TX_INT; if (unlikely(skb_shinfo(skb)->tx_flags &
SKBTX_HW_TSTAMP && fep->hwts_tx_en))
estatus |= BD_ENET_TX_TS;
}
}
bdp->cbd_bufaddr = cpu_to_fec32(addr);
bdp->cbd_datlen = cpu_to_fec16(buflen);
index = fec_enet_get_bd_index(last_bdp, &txq->bd); /* Save skb pointer */
txq->tx_buf[index].buf_p = skb;
/* Make sure the updates to rest of the descriptor are performed before * transferring ownership.
*/
wmb();
/* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end.
*/
status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
bdp->cbd_sc = cpu_to_fec16(status);
/* If this was the last BD in the ring, start at the beginning again. */
bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd);
skb_tx_timestamp(skb);
/* Make sure the update to bdp is performed before txq->bd.cur. */
wmb();
txq->bd.cur = bdp;
if (fep->bufdesc_ex) { if (fep->quirks & FEC_QUIRK_HAS_AVB)
estatus |= FEC_TX_BD_FTYPE(txq->bd.qid); if (skb->ip_summed == CHECKSUM_PARTIAL)
estatus |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
ebdp->cbd_bdu = 0;
ebdp->cbd_esc = cpu_to_fec32(estatus);
}
/* Handle the last BD specially */ if (last_tcp)
status |= (BD_ENET_TX_LAST | BD_ENET_TX_TC); if (is_last) {
status |= BD_ENET_TX_INTR; if (fep->bufdesc_ex)
ebdp->cbd_esc |= cpu_to_fec32(BD_ENET_TX_INT);
}
/* Initialize the BD for every fragment in the page. */ if (bdp->cbd_bufaddr)
bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY); else
bdp->cbd_sc = cpu_to_fec16(0);
bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
}
/* Set the last buffer to wrap */
bdp = fec_enet_get_prevdesc(bdp, &rxq->bd);
bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
rxq->bd.cur = rxq->bd.base;
}
for (q = 0; q < fep->num_tx_queues; q++) { /* ...and the same for transmit */
txq = fep->tx_queue[q];
bdp = txq->bd.base;
txq->bd.cur = bdp;
for (i = 0; i < txq->bd.ring_size; i++) { /* Initialize the BD for every fragment in the page. */
bdp->cbd_sc = cpu_to_fec16(0); if (txq->tx_buf[i].type == FEC_TXBUF_T_SKB) { if (bdp->cbd_bufaddr &&
!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
dma_unmap_single(&fep->pdev->dev,
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
DMA_TO_DEVICE); if (txq->tx_buf[i].buf_p)
dev_kfree_skb_any(txq->tx_buf[i].buf_p);
} elseif (txq->tx_buf[i].type == FEC_TXBUF_T_XDP_NDO) { if (bdp->cbd_bufaddr)
dma_unmap_single(&fep->pdev->dev,
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
DMA_TO_DEVICE);
/* Whack a reset. We should wait for this. * For i.MX6SX SOC, enet use AXI bus, we use disable MAC * instead of reset MAC itself.
*/ staticvoid fec_ctrl_reset(struct fec_enet_private *fep, bool allow_wol)
{
u32 val;
/* * This function is called to start or restart the FEC during a link * change, transmit timeout, or to reconfigure the FEC. The network * packet processing for this device must be stopped before this call.
*/ staticvoid
fec_restart(struct net_device *ndev)
{ struct fec_enet_private *fep = netdev_priv(ndev);
u32 rcntl = OPT_FRAME_SIZE | FEC_RCR_MII;
u32 ecntl = FEC_ECR_ETHEREN;
if (fep->bufdesc_ex)
fec_ptp_save_state(fep);
fec_ctrl_reset(fep, false);
/* * enet-mac reset will reset mac address registers too, * so need to reconfigure it.
*/
fec_set_hw_mac_addr(ndev);
/* Enable MII mode */ if (fep->full_duplex == DUPLEX_FULL) { /* FD enable */
writel(0x04, fep->hwp + FEC_X_CNTRL);
} else { /* No Rcv on Xmit */
rcntl |= FEC_RCR_DRT;
writel(0x0, fep->hwp + FEC_X_CNTRL);
}
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
#if !defined(CONFIG_M5272) if (fep->quirks & FEC_QUIRK_HAS_RACC) {
u32 val = readl(fep->hwp + FEC_RACC);
/* align IP header */
val |= FEC_RACC_SHIFT16; if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) /* set RX checksum */
val |= FEC_RACC_OPTIONS; else
val &= ~FEC_RACC_OPTIONS;
writel(val, fep->hwp + FEC_RACC);
writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
} #endif
/* * The phy interface and speed need to get configured * differently on enet-mac.
*/ if (fep->quirks & FEC_QUIRK_ENET_MAC) { /* Enable flow control and length check */
rcntl |= FEC_RCR_NLC | FEC_RCR_FLOWCTL;
/* RGMII, RMII or MII */ if (phy_interface_mode_is_rgmii(fep->phy_interface))
rcntl |= FEC_RCR_RGMII; elseif (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
rcntl |= FEC_RCR_RMII; else
rcntl &= ~FEC_RCR_RMII;
/* 1G, 100M or 10M */ if (ndev->phydev) { if (ndev->phydev->speed == SPEED_1000)
ecntl |= FEC_ECR_SPEED; elseif (ndev->phydev->speed == SPEED_100)
rcntl &= ~FEC_RCR_10BASET; else
rcntl |= FEC_RCR_10BASET;
}
} else { #ifdef FEC_MIIGSK_ENR if (fep->quirks & FEC_QUIRK_USE_GASKET) {
u32 cfgr; /* disable the gasket and wait */
writel(0, fep->hwp + FEC_MIIGSK_ENR); while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
udelay(1);
/* * configure the gasket: * RMII, 50 MHz, no loopback, no echo * MII, 25 MHz, no loopback, no echo
*/
cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII; if (ndev->phydev && ndev->phydev->speed == SPEED_10)
cfgr |= BM_MIIGSK_CFGR_FRCONT_10M;
writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR);
/* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) {
writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
udelay(10); if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
netdev_err(ndev, "Graceful transmit stop did not complete!\n");
}
/* We have to keep ENET enabled to have MII interrupt stay working */ if (fep->quirks & FEC_QUIRK_ENET_MAC &&
!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
writel(FEC_ECR_ETHEREN, fep->hwp + FEC_ECNTRL);
writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
}
if (fep->bufdesc_ex) {
val = readl(fep->hwp + FEC_ECNTRL);
val |= FEC_ECR_EN1588;
writel(val, fep->hwp + FEC_ECNTRL);
staticvoid
fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
{ struct fec_enet_private *fep; struct xdp_frame *xdpf; struct bufdesc *bdp; unsignedshort status; struct sk_buff *skb; struct fec_enet_priv_tx_q *txq; struct netdev_queue *nq; int index = 0; int entries_free; struct page *page; int frame_len;
fep = netdev_priv(ndev);
txq = fep->tx_queue[queue_id]; /* get next bdp of dirty_tx */
nq = netdev_get_tx_queue(ndev, queue_id);
bdp = txq->dirty_tx;
/* get next bdp of dirty_tx */
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
while (bdp != READ_ONCE(txq->bd.cur)) { /* Order the load of bd.cur and cbd_sc */
rmb();
status = fec16_to_cpu(READ_ONCE(bdp->cbd_sc)); if (status & BD_ENET_TX_READY) break;
index = fec_enet_get_bd_index(bdp, &txq->bd);
if (txq->tx_buf[index].type == FEC_TXBUF_T_SKB) {
skb = txq->tx_buf[index].buf_p; if (bdp->cbd_bufaddr &&
!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
dma_unmap_single(&fep->pdev->dev,
fec32_to_cpu(bdp->cbd_bufaddr),
fec16_to_cpu(bdp->cbd_datlen),
DMA_TO_DEVICE);
bdp->cbd_bufaddr = cpu_to_fec32(0); if (!skb) goto tx_buf_done;
} else { /* Tx processing cannot call any XDP (or page pool) APIs if * the "budget" is 0. Because NAPI is called with budget of * 0 (such as netpoll) indicates we may be in an IRQ context, * however, we can't use the page pool from IRQ context.
*/ if (unlikely(!budget)) break;
/* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK.
*/ if (status & BD_ENET_TX_DEF)
ndev->stats.collisions++;
if (txq->tx_buf[index].type == FEC_TXBUF_T_SKB) { /* NOTE: SKBTX_IN_PROGRESS being set does not imply it's we who * are to time stamp the packet, so we still need to check time * stamping enabled flag.
*/ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS &&
fep->hwts_tx_en) && fep->bufdesc_ex) { struct skb_shared_hwtstamps shhwtstamps; struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
tx_buf_done: /* Make sure the update to bdp and tx_buf are performed * before dirty_tx
*/
wmb();
txq->dirty_tx = bdp;
/* Update pointer to next buffer descriptor to be transmitted */
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
/* Since we have freed up a buffer, the ring is no longer full
*/ if (netif_tx_queue_stopped(nq)) {
entries_free = fec_enet_get_free_txdesc_num(txq); if (entries_free >= txq->tx_wake_threshold)
netif_tx_wake_queue(nq);
}
}
/* ERR006358: Keep the transmitter going */ if (bdp != txq->bd.cur &&
readl(txq->bd.reg_desc_active) == 0)
writel(0, txq->bd.reg_desc_active);
}
staticvoid fec_enet_tx(struct net_device *ndev, int budget)
{ struct fec_enet_private *fep = netdev_priv(ndev); int i;
/* Make sure that AVB queues are processed first. */ for (i = fep->num_tx_queues - 1; i >= 0; i--)
fec_enet_tx_queue(ndev, i, budget);
}
/* During a receive, the bd_rx.cur points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet.
*/ staticint
fec_enet_rx_queue(struct net_device *ndev, u16 queue_id, int budget)
{ struct fec_enet_private *fep = netdev_priv(ndev); struct fec_enet_priv_rx_q *rxq; struct bufdesc *bdp; unsignedshort status; struct sk_buff *skb;
ushort pkt_len; int pkt_received = 0; struct bufdesc_ex *ebdp = NULL; int index = 0; bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME; struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog);
u32 ret, xdp_result = FEC_ENET_XDP_PASS;
u32 data_start = FEC_ENET_XDP_HEADROOM; int cpu = smp_processor_id(); struct xdp_buff xdp; struct page *page;
__fec32 cbd_bufaddr;
u32 sub_len = 4;
#if !defined(CONFIG_M5272) /*If it has the FEC_QUIRK_HAS_RACC quirk property, the bit of * FEC_RACC_SHIFT16 is set by default in the probe function.
*/ if (fep->quirks & FEC_QUIRK_HAS_RACC) {
data_start += 2;
sub_len += 2;
} #endif
#ifdefined(CONFIG_COLDFIRE) && !defined(CONFIG_COLDFIRE_COHERENT_DMA) /* * Hacky flush of all caches instead of using the DMA API for the TSO * headers.
*/
flush_cache_all(); #endif
rxq = fep->rx_queue[queue_id];
/* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition.
*/
bdp = rxq->bd.cur;
xdp_init_buff(&xdp, PAGE_SIZE, &rxq->xdp_rxq);
while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) {
if (pkt_received >= budget) break;
pkt_received++;
if (xdp_prog) {
xdp_buff_clear_frags_flag(&xdp); /* subtract 16bit shift and FCS */
xdp_prepare_buff(&xdp, page_address(page),
data_start, pkt_len - sub_len, false);
ret = fec_enet_run_xdp(fep, xdp_prog, &xdp, rxq, cpu);
xdp_result |= ret; if (ret != FEC_ENET_XDP_PASS) goto rx_processing_done;
}
/* The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up * bridging applications.
*/
skb = build_skb(page_address(page), PAGE_SIZE); if (unlikely(!skb)) {
page_pool_recycle_direct(rxq->page_pool, page);
ndev->stats.rx_dropped++;
data = page_address(page) + FEC_ENET_XDP_HEADROOM;
swap_buffer(data, pkt_len);
}
/* Extract the enhanced buffer descriptor */
ebdp = NULL; if (fep->bufdesc_ex)
ebdp = (struct bufdesc_ex *)bdp;
/* If this is a VLAN packet remove the VLAN Tag */ if (fep->bufdesc_ex &&
(ebdp->cbd_esc & cpu_to_fec32(BD_ENET_RX_VLAN)))
fec_enet_rx_vlan(ndev, skb);
skb->protocol = eth_type_trans(skb, ndev);
/* Get receive timestamp from the skb */ if (fep->hwts_rx_en && fep->bufdesc_ex)
fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts),
skb_hwtstamps(skb));
if (fep->bufdesc_ex &&
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { if (!(ebdp->cbd_esc & cpu_to_fec32(FLAG_RX_CSUM_ERROR))) { /* don't check it */
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
skb_checksum_none_assert(skb);
}
}
rx_processing_done: /* Clear the status flags for this buffer */
status &= ~BD_ENET_RX_STATS;
/* Mark the buffer empty */
status |= BD_ENET_RX_EMPTY;
if (fep->bufdesc_ex) { struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);
ebdp->cbd_prot = 0;
ebdp->cbd_bdu = 0;
} /* Make sure the updates to rest of the descriptor are * performed before transferring ownership.
*/
wmb();
bdp->cbd_sc = cpu_to_fec16(status);
/* Update BD pointer to next entry */
bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
/* Doing this here will keep the FEC running while we process * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources.
*/
writel(0, rxq->bd.reg_desc_active);
}
rxq->bd.cur = bdp;
if (xdp_result & FEC_ENET_XDP_REDIR)
xdp_do_flush();
return pkt_received;
}
staticint fec_enet_rx(struct net_device *ndev, int budget)
{ struct fec_enet_private *fep = netdev_priv(ndev); int i, done = 0;
/* Make sure that AVB queues are processed first. */ for (i = fep->num_rx_queues - 1; i >= 0; i--)
done += fec_enet_rx_queue(ndev, i, budget - done);
/* * try to get mac address in following order: * * 1) module parameter via kernel command line in form * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0
*/
iap = macaddr;
/* * 2) from device tree data
*/ if (!is_valid_ether_addr(iap)) { struct device_node *np = fep->pdev->dev.of_node; if (np) {
ret = of_get_mac_address(np, tmpaddr); if (!ret)
iap = tmpaddr; elseif (ret == -EPROBE_DEFER) return ret;
}
}
/* * 3) from flash or fuse (via platform data)
*/ if (!is_valid_ether_addr(iap)) { #ifdef CONFIG_M5272 if (FEC_FLASHMAC)
iap = (unsignedchar *)FEC_FLASHMAC; #else struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
if (pdata)
iap = (unsignedchar *)&pdata->mac; #endif
}
/* * 4) FEC mac registers set by bootloader
*/ if (!is_valid_ether_addr(iap)) {
*((__be32 *) &tmpaddr[0]) =
cpu_to_be32(readl(fep->hwp + FEC_ADDR_LOW));
*((__be16 *) &tmpaddr[4]) =
cpu_to_be16(readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
iap = &tmpaddr[0];
}
/* * 5) random mac address
*/ if (!is_valid_ether_addr(iap)) { /* Report it and use a random ethernet address instead */
dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap);
eth_hw_addr_random(ndev);
dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
ndev->dev_addr); return 0;
}
/* Adjust MAC if using macaddr */
eth_hw_addr_gen(ndev, iap, iap == macaddr ? fep->dev_id : 0);
/* LPI Sleep Ts count base on tx clk (clk_ref). * The lpi sleep cnt value = X us / (cycle_ns).
*/ staticint fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
{ struct fec_enet_private *fep = netdev_priv(ndev);
/* * If the netdev is down, or is going down, we're not interested * in link state events, so just mark our idea of the link as down * and ignore the event.
*/ if (!netif_running(ndev) || !netif_device_present(ndev)) {
fep->link = 0;
} elseif (phy_dev->link) { if (!fep->link) {
fep->link = phy_dev->link;
status_change = 1;
}
if (phy_dev) {
phy_reset_after_clk_enable(phy_dev);
} elseif (fep->phy_node) { /* * If the PHY still is not bound to the MAC, but there is * OF PHY node and a matching PHY device instance already, * use the OF PHY node to obtain the PHY device instance, * and then use that PHY device instance when triggering * the PHY reset.
*/
phy_dev = of_phy_find_device(fep->phy_node);
phy_reset_after_clk_enable(phy_dev); if (phy_dev)
put_device(&phy_dev->mdio.dev);
}
}
if (fep->phy_node) {
phy_dev = of_phy_connect(ndev, fep->phy_node,
&fec_enet_adjust_link, 0,
fep->phy_interface); if (!phy_dev) {
netdev_err(ndev, "Unable to connect to phy\n"); return -ENODEV;
}
} else { /* check for attached phy */ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { if (!mdiobus_is_registered_device(fep->mii_bus, phy_id)) continue; if (dev_id--) continue;
strscpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); break;
}
if (phy_id >= PHY_MAX_ADDR) {
netdev_info(ndev, "no PHY, assuming direct connection to switch\n");
strscpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);
phy_id = 0;
}
/* * The i.MX28 dual fec interfaces are not equal. * Here are the differences: * * - fec0 supports MII & RMII modes while fec1 only supports RMII * - fec0 acts as the 1588 time master while fec1 is slave * - external phys can only be configured by fec0 * * That is to say fec1 can not work independently. It only works * when fec0 is working. The reason behind this design is that the * second interface is added primarily for Switch mode. * * Because of the last point above, both phys are attached on fec0 * mdio interface in board design, and need to be configured by * fec0 mii_bus.
*/ if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) { /* fec1 uses fec0 mii_bus */ if (mii_cnt && fec0_mii_bus) {
fep->mii_bus = fec0_mii_bus;
mii_cnt++; return 0;
} return -ENOENT;
}
/* * Set MII speed (= clk_get_rate() / 2 * phy_speed) * * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28 * Reference Manual has an error on this, and gets fixed on i.MX6Q * document.
*/
mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), bus_freq * 2); if (fep->quirks & FEC_QUIRK_ENET_MAC)
mii_speed--; if (mii_speed > 63) {
dev_err(&pdev->dev, "fec clock (%lu) too fast to get right mii speed\n",
clk_get_rate(fep->clk_ipg));
err = -EINVAL; goto err_out;
}
/* * The i.MX28 and i.MX6 types have another filed in the MSCR (aka * MII_SPEED) register that defines the MDIO output hold time. Earlier * versions are RAZ there, so just ignore the difference and write the * register always. * The minimal hold time according to IEE802.3 (clause 22) is 10 ns. * HOLDTIME + 1 is the number of clk cycles the fec is holding the * output. * The HOLDTIME bitfield takes values between 0 and 7 (inclusive). * Given that ceil(clkrate / 5000000) <= 64, the calculation for * holdtime cannot result in a value greater than 3.
*/
holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
fep->phy_speed = mii_speed << 1 | holdtime << 8;
if (suppress_preamble)
fep->phy_speed |= BIT(7);
if (fep->quirks & FEC_QUIRK_CLEAR_SETUP_MII) { /* Clear MMFR to avoid to generate MII event by writing MSCR. * MII event generation condition: * - writing MSCR: * - mmfr[31:0]_not_zero & mscr[7:0]_is_zero & * mscr_reg_data_in[7:0] != 0 * - writing MMFR: * - mscr[7:0]_not_zero
*/
writel(0, fep->hwp + FEC_MII_DATA);
}
err = of_mdiobus_register(fep->mii_bus, node); if (err) goto err_out_free_mdiobus;
of_node_put(node);
/* find all the PHY devices on the bus and set mac_managed_pm to true */ for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
phydev = mdiobus_get_phy(fep->mii_bus, addr); if (phydev)
phydev->mac_managed_pm = true;
}
mii_cnt++;
/* save fec0 mii_bus */ if (fep->quirks & FEC_QUIRK_SINGLE_MDIO)
fec0_mii_bus = fep->mii_bus;
/* ITR clock source is enet system clock (clk_ahb). * TCTT unit is cycle_ns * 64 cycle * So, the ICTT value = X us / (cycle_ns * 64)
*/ staticint fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
{ struct fec_enet_private *fep = netdev_priv(ndev);
return us * (fep->itr_clk_rate / 64000) / 1000;
}
/* Set threshold for interrupt coalescing */ staticvoid fec_enet_itr_coal_set(struct net_device *ndev)
{ struct fec_enet_private *fep = netdev_priv(ndev);
u32 rx_itr = 0, tx_itr = 0; int rx_ictt, tx_ictt;
txq->tso_hdrs = fec_dma_alloc(&fep->pdev->dev,
txq->bd.ring_size * TSO_HEADER_SIZE,
&txq->tso_hdrs_dma, GFP_KERNEL); if (!txq->tso_hdrs) {
ret = -ENOMEM; goto alloc_failed;
}
}
for (i = 0; i < fep->num_rx_queues; i++) {
fep->rx_queue[i] = kzalloc(sizeof(*fep->rx_queue[i]),
GFP_KERNEL); if (!fep->rx_queue[i]) {
ret = -ENOMEM; goto alloc_failed;
}
ret = pm_runtime_resume_and_get(&fep->pdev->dev); if (ret < 0) return ret;
pinctrl_pm_select_default_state(&fep->pdev->dev);
ret = fec_enet_clk_enable(ndev, true); if (ret) goto clk_enable;
/* During the first fec_enet_open call the PHY isn't probed at this * point. Therefore the phy_reset_after_clk_enable() call within * fec_enet_clk_enable() fails. As we need this reset in order to be * sure the PHY is working correctly we check if we need to reset again * later when the PHY is probed
*/ if (ndev->phydev && ndev->phydev->drv)
reset_again = false; else
reset_again = true;
/* I should reset the ring buffers here, but I don't yet know * a simple way to do that.
*/
ret = fec_enet_alloc_buffers(ndev); if (ret) goto err_enet_alloc;
/* Init MAC prior to mii bus probe */
fec_restart(ndev);
/* Call phy_reset_after_clk_enable() again if it failed during * phy_reset_after_clk_enable() before because the PHY wasn't probed.
*/ if (reset_again)
fec_enet_phy_reset_after_clk_enable(ndev);
/* Probe and connect to PHY when open the interface */
ret = fec_enet_mii_probe(ndev); if (ret) goto err_enet_mii_probe;
if (fep->quirks & FEC_QUIRK_ERR006687)
imx6q_cpuidle_fec_irqs_used();
if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
cpu_latency_qos_add_request(&fep->pm_qos_req, 0);
/* Set or clear the multicast filter for this adaptor. * Skeleton taken from sunlance driver. * The CPM Ethernet implementation allows Multicast as well as individual * MAC address filtering. Some of the drivers check to make sure it is * a group multicast address, and discard those that are not. I guess I * will do the same for now, but just remove the test if you want * individual filtering as well (do the upper net layers want or support * this kind of feature?).
*/
if (ndev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the * filter to all 1's
*/
writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
return;
}
/* Add the addresses in hash register */
netdev_for_each_mc_addr(ha, ndev) { /* calculate crc32 value of mac address */
crc = ether_crc_le(ndev->addr_len, ha->addr);
/* only upper 6 bits (FEC_HASH_BITS) are used * which point to specific bit in the hash registers
*/
hash = (crc >> (32 - FEC_HASH_BITS)) & 0x3f;
/* Set a MAC change in hardware. */ staticint
fec_set_mac_address(struct net_device *ndev, void *p)
{ struct sockaddr *addr = p;
if (addr) { if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
eth_hw_addr_set(ndev, addr->sa_data);
}
/* Add netif status check here to avoid system hang in below case: * ifconfig ethx down; ifconfig ethx hw ether xx:xx:xx:xx:xx:xx; * After ethx down, fec all clocks are gated off and then register * access causes system hang.
*/ if (!netif_running(ndev)) return 0;
if (!(fep->quirks & FEC_QUIRK_HAS_AVB)) return netdev_pick_tx(ndev, skb, NULL);
/* VLAN is present in the payload.*/ if (eth_type_vlan(skb->protocol)) { struct vlan_ethhdr *vhdr = skb_vlan_eth_hdr(skb);
vlan_tag = ntohs(vhdr->h_vlan_TCI); /* VLAN is present in the skb but not yet pushed in the payload.*/
} elseif (skb_vlan_tag_present(skb)) {
vlan_tag = skb->vlan_tci;
} else { return vlan_tag;
}
switch (bpf->command) { case XDP_SETUP_PROG: /* No need to support the SoCs that require to * do the frame swap because the performance wouldn't be * better than the skb mode.
*/ if (fep->quirks & FEC_QUIRK_SWAP_FRAME) return -EOPNOTSUPP;
if (!bpf->prog)
xdp_features_clear_redirect_target(dev);
if (is_run) {
napi_disable(&fep->napi);
netif_tx_disable(dev);
}
old_prog = xchg(&fep->xdp_prog, bpf->prog); if (old_prog)
bpf_prog_put(old_prog);
fec_restart(dev);
if (is_run) {
napi_enable(&fep->napi);
netif_tx_start_all_queues(dev);
}
if (bpf->prog)
xdp_features_set_redirect_target(dev, false);
return 0;
case XDP_SETUP_XSK_POOL: return -EOPNOTSUPP;
default: return -EOPNOTSUPP;
}
}
staticint
fec_enet_xdp_get_tx_queue(struct fec_enet_private *fep, int index)
{ if (unlikely(index < 0)) return 0;
/* Make sure the updates to rest of the descriptor are performed before * transferring ownership.
*/
dma_wmb();
/* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end.
*/
status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
bdp->cbd_sc = cpu_to_fec16(status);
/* If this was the last BD in the ring, start at the beginning again. */
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
/* Make sure the update to bdp are performed before txq->bd.cur. */
dma_wmb();
/* Avoid tx timeout as XDP shares the queue with kernel stack */
txq_trans_cond_update(nq); for (i = 0; i < num_frames; i++) { if (fec_enet_txq_xmit_frame(fep, txq, frames[i], 0, true) < 0) break;
sent_frames++;
}
/* Check mask of the streaming and coherent API */
ret = dma_set_mask_and_coherent(&fep->pdev->dev, DMA_BIT_MASK(32)); if (ret < 0) {
dev_warn(&fep->pdev->dev, "No suitable DMA available\n"); return ret;
}
ret = fec_enet_alloc_queue(ndev); if (ret) return ret;
/* The FEC Ethernet specific entries in the device structure */
ndev->watchdog_timeo = TX_TIMEOUT;
ndev->netdev_ops = &fec_netdev_ops;
ndev->ethtool_ops = &fec_enet_ethtool_ops;
err = of_property_read_u32(np, "phy-reset-duration", &msec); /* A sane reset duration should not be longer than 1s */ if (!err && msec > 1000)
msec = 1;
err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay); /* valid reset duration should be less than 1s */ if (!err && phy_post_delay > 1000) return -EINVAL;
phy_reset = devm_gpiod_get_optional(&pdev->dev, "phy-reset",
GPIOD_OUT_HIGH); if (IS_ERR(phy_reset)) return dev_err_probe(&pdev->dev, PTR_ERR(phy_reset), "failed to get phy-reset-gpios\n");
return 0;
} #else/* CONFIG_OF */ staticint fec_reset_phy(struct platform_device *pdev)
{ /* * In case of platform probe, the reset has been done * by machine code.
*/ return 0;
} #endif/* CONFIG_OF */
staticvoid
fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
{ struct device_node *np = pdev->dev.of_node;
*num_tx = *num_rx = 1;
if (!np || !of_device_is_available(np)) return;
/* parse the num of tx and rx queues */
of_property_read_u32(np, "fsl,num-tx-queues", num_tx);
ret = fec_reset_phy(pdev); if (ret) goto failed_reset;
irq_cnt = fec_enet_get_irq_cnt(pdev); if (fep->bufdesc_ex)
fec_ptp_init(pdev, irq_cnt);
ret = fec_enet_init(ndev); if (ret) goto failed_init;
for (i = 0; i < irq_cnt; i++) {
snprintf(irq_name, sizeof(irq_name), "int%d", i);
irq = platform_get_irq_byname_optional(pdev, irq_name); if (irq < 0)
irq = platform_get_irq(pdev, i); if (irq < 0) {
ret = irq; goto failed_irq;
}
ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
0, pdev->name, ndev); if (ret) goto failed_irq;
fep->irq[i] = irq;
}
/* Decide which interrupt line is wakeup capable */
fec_enet_get_wakeup_irq(pdev);
ret = fec_enet_mii_init(pdev); if (ret) goto failed_mii_init;
/* Carrier starts down, phylib will bring it up */
netif_carrier_off(ndev);
fec_enet_clk_enable(ndev, false);
pinctrl_pm_select_sleep_state(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0)
dev_err(&pdev->dev, "Failed to resume device in remove callback (%pe)\n",
ERR_PTR(ret));
cancel_work_sync(&fep->tx_timeout_work);
fec_ptp_stop(pdev);
unregister_netdev(ndev);
fec_enet_mii_remove(fep); if (fep->reg_phy)
regulator_disable(fep->reg_phy);
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(fep->phy_node);
/* After pm_runtime_get_sync() failed, the clks are still off, so skip * disabling them again.
*/ if (ret >= 0) {
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
}
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
rtnl_lock(); if (netif_running(ndev)) { if (fep->wol_flag & FEC_WOL_FLAG_ENABLE)
fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON;
phy_stop(ndev->phydev);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
netif_device_detach(ndev);
netif_tx_unlock_bh(ndev);
fec_stop(ndev); if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
fec_irqs_disable(ndev);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
} else {
fec_irqs_disable_except_wakeup(ndev); if (fep->wake_irq > 0) {
disable_irq(fep->wake_irq);
enable_irq_wake(fep->wake_irq);
}
fec_enet_stop_mode(fep, true);
} /* It's safe to disable clocks since interrupts are masked */
fec_enet_clk_enable(ndev, false);
fep->rpm_active = !pm_runtime_status_suspended(dev); if (fep->rpm_active) {
ret = pm_runtime_force_suspend(dev); if (ret < 0) {
rtnl_unlock(); return ret;
}
}
}
rtnl_unlock();
if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
regulator_disable(fep->reg_phy);
/* SOC supply clock to phy, when clock is disabled, phy link down * SOC control phy regulator, when regulator is disabled, phy link down
*/ if (fep->clk_enet_out || fep->reg_phy)
fep->link = 0;
return 0;
}
staticint fec_resume(struct device *dev)
{ struct net_device *ndev = dev_get_drvdata(dev); struct fec_enet_private *fep = netdev_priv(ndev); int ret; int val;
if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
ret = regulator_enable(fep->reg_phy); if (ret) return ret;
}
rtnl_lock(); if (netif_running(ndev)) { if (fep->rpm_active)
pm_runtime_force_resume(dev);
ret = fec_enet_clk_enable(ndev, true); if (ret) {
rtnl_unlock(); goto failed_clk;
} if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
fec_enet_stop_mode(fep, false); if (fep->wake_irq) {
disable_irq_wake(fep->wake_irq);
enable_irq(fep->wake_irq);
}
MODULE_DESCRIPTION("NXP Fast Ethernet Controller (FEC) driver");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ 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.65Bemerkung:
(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.