18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* drivers/net/ethernet/freescale/gianfar.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Gianfar Ethernet Driver
58c2ecf20Sopenharmony_ci * This driver is designed for the non-CPM ethernet controllers
68c2ecf20Sopenharmony_ci * on the 85xx and 83xx family of integrated processors
78c2ecf20Sopenharmony_ci * Based on 8260_io/fcc_enet.c
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Author: Andy Fleming
108c2ecf20Sopenharmony_ci * Maintainer: Kumar Gala
118c2ecf20Sopenharmony_ci * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc.
148c2ecf20Sopenharmony_ci * Copyright 2007 MontaVista Software, Inc.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  Gianfar:  AKA Lambda Draconis, "Dragon"
178c2ecf20Sopenharmony_ci *  RA 11 31 24.2
188c2ecf20Sopenharmony_ci *  Dec +69 19 52
198c2ecf20Sopenharmony_ci *  V 3.84
208c2ecf20Sopenharmony_ci *  B-V +1.62
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci *  Theory of operation
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *  The driver is initialized through of_device. Configuration information
258c2ecf20Sopenharmony_ci *  is therefore conveyed through an OF-style device tree.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *  The Gianfar Ethernet Controller uses a ring of buffer
288c2ecf20Sopenharmony_ci *  descriptors.  The beginning is indicated by a register
298c2ecf20Sopenharmony_ci *  pointing to the physical address of the start of the ring.
308c2ecf20Sopenharmony_ci *  The end is determined by a "wrap" bit being set in the
318c2ecf20Sopenharmony_ci *  last descriptor of the ring.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci *  When a packet is received, the RXF bit in the
348c2ecf20Sopenharmony_ci *  IEVENT register is set, triggering an interrupt when the
358c2ecf20Sopenharmony_ci *  corresponding bit in the IMASK register is also set (if
368c2ecf20Sopenharmony_ci *  interrupt coalescing is active, then the interrupt may not
378c2ecf20Sopenharmony_ci *  happen immediately, but will wait until either a set number
388c2ecf20Sopenharmony_ci *  of frames or amount of time have passed).  In NAPI, the
398c2ecf20Sopenharmony_ci *  interrupt handler will signal there is work to be done, and
408c2ecf20Sopenharmony_ci *  exit. This method will start at the last known empty
418c2ecf20Sopenharmony_ci *  descriptor, and process every subsequent descriptor until there
428c2ecf20Sopenharmony_ci *  are none left with data (NAPI will stop after a set number of
438c2ecf20Sopenharmony_ci *  packets to give time to other tasks, but will eventually
448c2ecf20Sopenharmony_ci *  process all the packets).  The data arrives inside a
458c2ecf20Sopenharmony_ci *  pre-allocated skb, and so after the skb is passed up to the
468c2ecf20Sopenharmony_ci *  stack, a new skb must be allocated, and the address field in
478c2ecf20Sopenharmony_ci *  the buffer descriptor must be updated to indicate this new
488c2ecf20Sopenharmony_ci *  skb.
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci *  When the kernel requests that a packet be transmitted, the
518c2ecf20Sopenharmony_ci *  driver starts where it left off last time, and points the
528c2ecf20Sopenharmony_ci *  descriptor at the buffer which was passed in.  The driver
538c2ecf20Sopenharmony_ci *  then informs the DMA engine that there are packets ready to
548c2ecf20Sopenharmony_ci *  be transmitted.  Once the controller is finished transmitting
558c2ecf20Sopenharmony_ci *  the packet, an interrupt may be triggered (under the same
568c2ecf20Sopenharmony_ci *  conditions as for reception, but depending on the TXF bit).
578c2ecf20Sopenharmony_ci *  The driver then cleans up the buffer.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
618c2ecf20Sopenharmony_ci#define DEBUG
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#include <linux/kernel.h>
648c2ecf20Sopenharmony_ci#include <linux/string.h>
658c2ecf20Sopenharmony_ci#include <linux/errno.h>
668c2ecf20Sopenharmony_ci#include <linux/unistd.h>
678c2ecf20Sopenharmony_ci#include <linux/slab.h>
688c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
698c2ecf20Sopenharmony_ci#include <linux/delay.h>
708c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
718c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
728c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
738c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
748c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
758c2ecf20Sopenharmony_ci#include <linux/mm.h>
768c2ecf20Sopenharmony_ci#include <linux/of_address.h>
778c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
788c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
798c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
808c2ecf20Sopenharmony_ci#include <linux/ip.h>
818c2ecf20Sopenharmony_ci#include <linux/tcp.h>
828c2ecf20Sopenharmony_ci#include <linux/udp.h>
838c2ecf20Sopenharmony_ci#include <linux/in.h>
848c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h>
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#include <asm/io.h>
878c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
888c2ecf20Sopenharmony_ci#include <asm/reg.h>
898c2ecf20Sopenharmony_ci#include <asm/mpc85xx.h>
908c2ecf20Sopenharmony_ci#endif
918c2ecf20Sopenharmony_ci#include <asm/irq.h>
928c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
938c2ecf20Sopenharmony_ci#include <linux/module.h>
948c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
958c2ecf20Sopenharmony_ci#include <linux/crc32.h>
968c2ecf20Sopenharmony_ci#include <linux/mii.h>
978c2ecf20Sopenharmony_ci#include <linux/phy.h>
988c2ecf20Sopenharmony_ci#include <linux/phy_fixed.h>
998c2ecf20Sopenharmony_ci#include <linux/of.h>
1008c2ecf20Sopenharmony_ci#include <linux/of_net.h>
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#include "gianfar.h"
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define TX_TIMEOUT      (5*HZ)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor, Inc");
1078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Gianfar Ethernet Driver");
1088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
1118c2ecf20Sopenharmony_ci			    dma_addr_t buf)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	u32 lstatus;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	bdp->bufPtr = cpu_to_be32(buf);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
1188c2ecf20Sopenharmony_ci	if (bdp == rx_queue->rx_bd_base + rx_queue->rx_ring_size - 1)
1198c2ecf20Sopenharmony_ci		lstatus |= BD_LFLAG(RXBD_WRAP);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	gfar_wmb();
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	bdp->lstatus = cpu_to_be32(lstatus);
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic void gfar_init_tx_rx_base(struct gfar_private *priv)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
1298c2ecf20Sopenharmony_ci	u32 __iomem *baddr;
1308c2ecf20Sopenharmony_ci	int i;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	baddr = &regs->tbase0;
1338c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
1348c2ecf20Sopenharmony_ci		gfar_write(baddr, priv->tx_queue[i]->tx_bd_dma_base);
1358c2ecf20Sopenharmony_ci		baddr += 2;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	baddr = &regs->rbase0;
1398c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
1408c2ecf20Sopenharmony_ci		gfar_write(baddr, priv->rx_queue[i]->rx_bd_dma_base);
1418c2ecf20Sopenharmony_ci		baddr += 2;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void gfar_init_rqprm(struct gfar_private *priv)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
1488c2ecf20Sopenharmony_ci	u32 __iomem *baddr;
1498c2ecf20Sopenharmony_ci	int i;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	baddr = &regs->rqprm0;
1528c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
1538c2ecf20Sopenharmony_ci		gfar_write(baddr, priv->rx_queue[i]->rx_ring_size |
1548c2ecf20Sopenharmony_ci			   (DEFAULT_RX_LFC_THR << FBTHR_SHIFT));
1558c2ecf20Sopenharmony_ci		baddr++;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic void gfar_rx_offload_en(struct gfar_private *priv)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	/* set this when rx hw offload (TOE) functions are being used */
1628c2ecf20Sopenharmony_ci	priv->uses_rxfcb = 0;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
1658c2ecf20Sopenharmony_ci		priv->uses_rxfcb = 1;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (priv->hwts_rx_en || priv->rx_filer_enable)
1688c2ecf20Sopenharmony_ci		priv->uses_rxfcb = 1;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic void gfar_mac_rx_config(struct gfar_private *priv)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
1748c2ecf20Sopenharmony_ci	u32 rctrl = 0;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (priv->rx_filer_enable) {
1778c2ecf20Sopenharmony_ci		rctrl |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
1788c2ecf20Sopenharmony_ci		/* Program the RIR0 reg with the required distribution */
1798c2ecf20Sopenharmony_ci		if (priv->poll_mode == GFAR_SQ_POLLING)
1808c2ecf20Sopenharmony_ci			gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
1818c2ecf20Sopenharmony_ci		else /* GFAR_MQ_POLLING */
1828c2ecf20Sopenharmony_ci			gfar_write(&regs->rir0, DEFAULT_8RXQ_RIR0);
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	/* Restore PROMISC mode */
1868c2ecf20Sopenharmony_ci	if (priv->ndev->flags & IFF_PROMISC)
1878c2ecf20Sopenharmony_ci		rctrl |= RCTRL_PROM;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (priv->ndev->features & NETIF_F_RXCSUM)
1908c2ecf20Sopenharmony_ci		rctrl |= RCTRL_CHECKSUMMING;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (priv->extended_hash)
1938c2ecf20Sopenharmony_ci		rctrl |= RCTRL_EXTHASH | RCTRL_EMEN;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (priv->padding) {
1968c2ecf20Sopenharmony_ci		rctrl &= ~RCTRL_PAL_MASK;
1978c2ecf20Sopenharmony_ci		rctrl |= RCTRL_PADDING(priv->padding);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Enable HW time stamping if requested from user space */
2018c2ecf20Sopenharmony_ci	if (priv->hwts_rx_en)
2028c2ecf20Sopenharmony_ci		rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
2058c2ecf20Sopenharmony_ci		rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Clear the LFC bit */
2088c2ecf20Sopenharmony_ci	gfar_write(&regs->rctrl, rctrl);
2098c2ecf20Sopenharmony_ci	/* Init flow control threshold values */
2108c2ecf20Sopenharmony_ci	gfar_init_rqprm(priv);
2118c2ecf20Sopenharmony_ci	gfar_write(&regs->ptv, DEFAULT_LFC_PTVVAL);
2128c2ecf20Sopenharmony_ci	rctrl |= RCTRL_LFC;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* Init rctrl based on our settings */
2158c2ecf20Sopenharmony_ci	gfar_write(&regs->rctrl, rctrl);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void gfar_mac_tx_config(struct gfar_private *priv)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
2218c2ecf20Sopenharmony_ci	u32 tctrl = 0;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (priv->ndev->features & NETIF_F_IP_CSUM)
2248c2ecf20Sopenharmony_ci		tctrl |= TCTRL_INIT_CSUM;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (priv->prio_sched_en)
2278c2ecf20Sopenharmony_ci		tctrl |= TCTRL_TXSCHED_PRIO;
2288c2ecf20Sopenharmony_ci	else {
2298c2ecf20Sopenharmony_ci		tctrl |= TCTRL_TXSCHED_WRRS;
2308c2ecf20Sopenharmony_ci		gfar_write(&regs->tr03wt, DEFAULT_WRRS_WEIGHT);
2318c2ecf20Sopenharmony_ci		gfar_write(&regs->tr47wt, DEFAULT_WRRS_WEIGHT);
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
2358c2ecf20Sopenharmony_ci		tctrl |= TCTRL_VLINS;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	gfar_write(&regs->tctrl, tctrl);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic void gfar_configure_coalescing(struct gfar_private *priv,
2418c2ecf20Sopenharmony_ci			       unsigned long tx_mask, unsigned long rx_mask)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
2448c2ecf20Sopenharmony_ci	u32 __iomem *baddr;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (priv->mode == MQ_MG_MODE) {
2478c2ecf20Sopenharmony_ci		int i = 0;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci		baddr = &regs->txic0;
2508c2ecf20Sopenharmony_ci		for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
2518c2ecf20Sopenharmony_ci			gfar_write(baddr + i, 0);
2528c2ecf20Sopenharmony_ci			if (likely(priv->tx_queue[i]->txcoalescing))
2538c2ecf20Sopenharmony_ci				gfar_write(baddr + i, priv->tx_queue[i]->txic);
2548c2ecf20Sopenharmony_ci		}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		baddr = &regs->rxic0;
2578c2ecf20Sopenharmony_ci		for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
2588c2ecf20Sopenharmony_ci			gfar_write(baddr + i, 0);
2598c2ecf20Sopenharmony_ci			if (likely(priv->rx_queue[i]->rxcoalescing))
2608c2ecf20Sopenharmony_ci				gfar_write(baddr + i, priv->rx_queue[i]->rxic);
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci	} else {
2638c2ecf20Sopenharmony_ci		/* Backward compatible case -- even if we enable
2648c2ecf20Sopenharmony_ci		 * multiple queues, there's only single reg to program
2658c2ecf20Sopenharmony_ci		 */
2668c2ecf20Sopenharmony_ci		gfar_write(&regs->txic, 0);
2678c2ecf20Sopenharmony_ci		if (likely(priv->tx_queue[0]->txcoalescing))
2688c2ecf20Sopenharmony_ci			gfar_write(&regs->txic, priv->tx_queue[0]->txic);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		gfar_write(&regs->rxic, 0);
2718c2ecf20Sopenharmony_ci		if (unlikely(priv->rx_queue[0]->rxcoalescing))
2728c2ecf20Sopenharmony_ci			gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void gfar_configure_coalescing_all(struct gfar_private *priv)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	gfar_configure_coalescing(priv, 0xFF, 0xFF);
2798c2ecf20Sopenharmony_ci}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic struct net_device_stats *gfar_get_stats(struct net_device *dev)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
2848c2ecf20Sopenharmony_ci	unsigned long rx_packets = 0, rx_bytes = 0, rx_dropped = 0;
2858c2ecf20Sopenharmony_ci	unsigned long tx_packets = 0, tx_bytes = 0;
2868c2ecf20Sopenharmony_ci	int i;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
2898c2ecf20Sopenharmony_ci		rx_packets += priv->rx_queue[i]->stats.rx_packets;
2908c2ecf20Sopenharmony_ci		rx_bytes   += priv->rx_queue[i]->stats.rx_bytes;
2918c2ecf20Sopenharmony_ci		rx_dropped += priv->rx_queue[i]->stats.rx_dropped;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	dev->stats.rx_packets = rx_packets;
2958c2ecf20Sopenharmony_ci	dev->stats.rx_bytes   = rx_bytes;
2968c2ecf20Sopenharmony_ci	dev->stats.rx_dropped = rx_dropped;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
2998c2ecf20Sopenharmony_ci		tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
3008c2ecf20Sopenharmony_ci		tx_packets += priv->tx_queue[i]->stats.tx_packets;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	dev->stats.tx_bytes   = tx_bytes;
3048c2ecf20Sopenharmony_ci	dev->stats.tx_packets = tx_packets;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return &dev->stats;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci/* Set the appropriate hash bit for the given addr */
3108c2ecf20Sopenharmony_ci/* The algorithm works like so:
3118c2ecf20Sopenharmony_ci * 1) Take the Destination Address (ie the multicast address), and
3128c2ecf20Sopenharmony_ci * do a CRC on it (little endian), and reverse the bits of the
3138c2ecf20Sopenharmony_ci * result.
3148c2ecf20Sopenharmony_ci * 2) Use the 8 most significant bits as a hash into a 256-entry
3158c2ecf20Sopenharmony_ci * table.  The table is controlled through 8 32-bit registers:
3168c2ecf20Sopenharmony_ci * gaddr0-7.  gaddr0's MSB is entry 0, and gaddr7's LSB is
3178c2ecf20Sopenharmony_ci * gaddr7.  This means that the 3 most significant bits in the
3188c2ecf20Sopenharmony_ci * hash index which gaddr register to use, and the 5 other bits
3198c2ecf20Sopenharmony_ci * indicate which bit (assuming an IBM numbering scheme, which
3208c2ecf20Sopenharmony_ci * for PowerPC (tm) is usually the case) in the register holds
3218c2ecf20Sopenharmony_ci * the entry.
3228c2ecf20Sopenharmony_ci */
3238c2ecf20Sopenharmony_cistatic void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	u32 tempval;
3268c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
3278c2ecf20Sopenharmony_ci	u32 result = ether_crc(ETH_ALEN, addr);
3288c2ecf20Sopenharmony_ci	int width = priv->hash_width;
3298c2ecf20Sopenharmony_ci	u8 whichbit = (result >> (32 - width)) & 0x1f;
3308c2ecf20Sopenharmony_ci	u8 whichreg = result >> (32 - width + 5);
3318c2ecf20Sopenharmony_ci	u32 value = (1 << (31-whichbit));
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	tempval = gfar_read(priv->hash_regs[whichreg]);
3348c2ecf20Sopenharmony_ci	tempval |= value;
3358c2ecf20Sopenharmony_ci	gfar_write(priv->hash_regs[whichreg], tempval);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci/* There are multiple MAC Address register pairs on some controllers
3398c2ecf20Sopenharmony_ci * This function sets the numth pair to a given address
3408c2ecf20Sopenharmony_ci */
3418c2ecf20Sopenharmony_cistatic void gfar_set_mac_for_addr(struct net_device *dev, int num,
3428c2ecf20Sopenharmony_ci				  const u8 *addr)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
3458c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
3468c2ecf20Sopenharmony_ci	u32 tempval;
3478c2ecf20Sopenharmony_ci	u32 __iomem *macptr = &regs->macstnaddr1;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	macptr += num*2;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* For a station address of 0x12345678ABCD in transmission
3528c2ecf20Sopenharmony_ci	 * order (BE), MACnADDR1 is set to 0xCDAB7856 and
3538c2ecf20Sopenharmony_ci	 * MACnADDR2 is set to 0x34120000.
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	tempval = (addr[5] << 24) | (addr[4] << 16) |
3568c2ecf20Sopenharmony_ci		  (addr[3] << 8)  |  addr[2];
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	gfar_write(macptr, tempval);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	tempval = (addr[1] << 24) | (addr[0] << 16);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	gfar_write(macptr+1, tempval);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int gfar_set_mac_addr(struct net_device *dev, void *p)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	int ret;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	ret = eth_mac_addr(dev, p);
3708c2ecf20Sopenharmony_ci	if (ret)
3718c2ecf20Sopenharmony_ci		return ret;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void gfar_ints_disable(struct gfar_private *priv)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	int i;
3818c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
3828c2ecf20Sopenharmony_ci		struct gfar __iomem *regs = priv->gfargrp[i].regs;
3838c2ecf20Sopenharmony_ci		/* Clear IEVENT */
3848c2ecf20Sopenharmony_ci		gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci		/* Initialize IMASK */
3878c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, IMASK_INIT_CLEAR);
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic void gfar_ints_enable(struct gfar_private *priv)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	int i;
3948c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
3958c2ecf20Sopenharmony_ci		struct gfar __iomem *regs = priv->gfargrp[i].regs;
3968c2ecf20Sopenharmony_ci		/* Unmask the interrupts we look for */
3978c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, IMASK_DEFAULT);
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic int gfar_alloc_tx_queues(struct gfar_private *priv)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	int i;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
4068c2ecf20Sopenharmony_ci		priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
4078c2ecf20Sopenharmony_ci					    GFP_KERNEL);
4088c2ecf20Sopenharmony_ci		if (!priv->tx_queue[i])
4098c2ecf20Sopenharmony_ci			return -ENOMEM;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci		priv->tx_queue[i]->tx_skbuff = NULL;
4128c2ecf20Sopenharmony_ci		priv->tx_queue[i]->qindex = i;
4138c2ecf20Sopenharmony_ci		priv->tx_queue[i]->dev = priv->ndev;
4148c2ecf20Sopenharmony_ci		spin_lock_init(&(priv->tx_queue[i]->txlock));
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	return 0;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic int gfar_alloc_rx_queues(struct gfar_private *priv)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	int i;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
4248c2ecf20Sopenharmony_ci		priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
4258c2ecf20Sopenharmony_ci					    GFP_KERNEL);
4268c2ecf20Sopenharmony_ci		if (!priv->rx_queue[i])
4278c2ecf20Sopenharmony_ci			return -ENOMEM;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		priv->rx_queue[i]->qindex = i;
4308c2ecf20Sopenharmony_ci		priv->rx_queue[i]->ndev = priv->ndev;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic void gfar_free_tx_queues(struct gfar_private *priv)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	int i;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++)
4408c2ecf20Sopenharmony_ci		kfree(priv->tx_queue[i]);
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void gfar_free_rx_queues(struct gfar_private *priv)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	int i;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++)
4488c2ecf20Sopenharmony_ci		kfree(priv->rx_queue[i]);
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic void unmap_group_regs(struct gfar_private *priv)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	int i;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	for (i = 0; i < MAXGROUPS; i++)
4568c2ecf20Sopenharmony_ci		if (priv->gfargrp[i].regs)
4578c2ecf20Sopenharmony_ci			iounmap(priv->gfargrp[i].regs);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic void free_gfar_dev(struct gfar_private *priv)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	int i, j;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++)
4658c2ecf20Sopenharmony_ci		for (j = 0; j < GFAR_NUM_IRQS; j++) {
4668c2ecf20Sopenharmony_ci			kfree(priv->gfargrp[i].irqinfo[j]);
4678c2ecf20Sopenharmony_ci			priv->gfargrp[i].irqinfo[j] = NULL;
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	free_netdev(priv->ndev);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic void disable_napi(struct gfar_private *priv)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	int i;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
4788c2ecf20Sopenharmony_ci		napi_disable(&priv->gfargrp[i].napi_rx);
4798c2ecf20Sopenharmony_ci		napi_disable(&priv->gfargrp[i].napi_tx);
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic void enable_napi(struct gfar_private *priv)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	int i;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
4888c2ecf20Sopenharmony_ci		napi_enable(&priv->gfargrp[i].napi_rx);
4898c2ecf20Sopenharmony_ci		napi_enable(&priv->gfargrp[i].napi_tx);
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int gfar_parse_group(struct device_node *np,
4948c2ecf20Sopenharmony_ci			    struct gfar_private *priv, const char *model)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
4978c2ecf20Sopenharmony_ci	int i;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	for (i = 0; i < GFAR_NUM_IRQS; i++) {
5008c2ecf20Sopenharmony_ci		grp->irqinfo[i] = kzalloc(sizeof(struct gfar_irqinfo),
5018c2ecf20Sopenharmony_ci					  GFP_KERNEL);
5028c2ecf20Sopenharmony_ci		if (!grp->irqinfo[i])
5038c2ecf20Sopenharmony_ci			return -ENOMEM;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	grp->regs = of_iomap(np, 0);
5078c2ecf20Sopenharmony_ci	if (!grp->regs)
5088c2ecf20Sopenharmony_ci		return -ENOMEM;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	gfar_irq(grp, TX)->irq = irq_of_parse_and_map(np, 0);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	/* If we aren't the FEC we have multiple interrupts */
5138c2ecf20Sopenharmony_ci	if (model && strcasecmp(model, "FEC")) {
5148c2ecf20Sopenharmony_ci		gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
5158c2ecf20Sopenharmony_ci		gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
5168c2ecf20Sopenharmony_ci		if (!gfar_irq(grp, TX)->irq ||
5178c2ecf20Sopenharmony_ci		    !gfar_irq(grp, RX)->irq ||
5188c2ecf20Sopenharmony_ci		    !gfar_irq(grp, ER)->irq)
5198c2ecf20Sopenharmony_ci			return -EINVAL;
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	grp->priv = priv;
5238c2ecf20Sopenharmony_ci	spin_lock_init(&grp->grplock);
5248c2ecf20Sopenharmony_ci	if (priv->mode == MQ_MG_MODE) {
5258c2ecf20Sopenharmony_ci		u32 rxq_mask, txq_mask;
5268c2ecf20Sopenharmony_ci		int ret;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci		grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
5298c2ecf20Sopenharmony_ci		grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci		ret = of_property_read_u32(np, "fsl,rx-bit-map", &rxq_mask);
5328c2ecf20Sopenharmony_ci		if (!ret) {
5338c2ecf20Sopenharmony_ci			grp->rx_bit_map = rxq_mask ?
5348c2ecf20Sopenharmony_ci			rxq_mask : (DEFAULT_MAPPING >> priv->num_grps);
5358c2ecf20Sopenharmony_ci		}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci		ret = of_property_read_u32(np, "fsl,tx-bit-map", &txq_mask);
5388c2ecf20Sopenharmony_ci		if (!ret) {
5398c2ecf20Sopenharmony_ci			grp->tx_bit_map = txq_mask ?
5408c2ecf20Sopenharmony_ci			txq_mask : (DEFAULT_MAPPING >> priv->num_grps);
5418c2ecf20Sopenharmony_ci		}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (priv->poll_mode == GFAR_SQ_POLLING) {
5448c2ecf20Sopenharmony_ci			/* One Q per interrupt group: Q0 to G0, Q1 to G1 */
5458c2ecf20Sopenharmony_ci			grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
5468c2ecf20Sopenharmony_ci			grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
5478c2ecf20Sopenharmony_ci		}
5488c2ecf20Sopenharmony_ci	} else {
5498c2ecf20Sopenharmony_ci		grp->rx_bit_map = 0xFF;
5508c2ecf20Sopenharmony_ci		grp->tx_bit_map = 0xFF;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	/* bit_map's MSB is q0 (from q0 to q7) but, for_each_set_bit parses
5548c2ecf20Sopenharmony_ci	 * right to left, so we need to revert the 8 bits to get the q index
5558c2ecf20Sopenharmony_ci	 */
5568c2ecf20Sopenharmony_ci	grp->rx_bit_map = bitrev8(grp->rx_bit_map);
5578c2ecf20Sopenharmony_ci	grp->tx_bit_map = bitrev8(grp->tx_bit_map);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
5608c2ecf20Sopenharmony_ci	 * also assign queues to groups
5618c2ecf20Sopenharmony_ci	 */
5628c2ecf20Sopenharmony_ci	for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
5638c2ecf20Sopenharmony_ci		if (!grp->rx_queue)
5648c2ecf20Sopenharmony_ci			grp->rx_queue = priv->rx_queue[i];
5658c2ecf20Sopenharmony_ci		grp->num_rx_queues++;
5668c2ecf20Sopenharmony_ci		grp->rstat |= (RSTAT_CLEAR_RHALT >> i);
5678c2ecf20Sopenharmony_ci		priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
5688c2ecf20Sopenharmony_ci		priv->rx_queue[i]->grp = grp;
5698c2ecf20Sopenharmony_ci	}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
5728c2ecf20Sopenharmony_ci		if (!grp->tx_queue)
5738c2ecf20Sopenharmony_ci			grp->tx_queue = priv->tx_queue[i];
5748c2ecf20Sopenharmony_ci		grp->num_tx_queues++;
5758c2ecf20Sopenharmony_ci		grp->tstat |= (TSTAT_CLEAR_THALT >> i);
5768c2ecf20Sopenharmony_ci		priv->tqueue |= (TQUEUE_EN0 >> i);
5778c2ecf20Sopenharmony_ci		priv->tx_queue[i]->grp = grp;
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	priv->num_grps++;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return 0;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic int gfar_of_group_count(struct device_node *np)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	struct device_node *child;
5888c2ecf20Sopenharmony_ci	int num = 0;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	for_each_available_child_of_node(np, child)
5918c2ecf20Sopenharmony_ci		if (of_node_name_eq(child, "queue-group"))
5928c2ecf20Sopenharmony_ci			num++;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	return num;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci/* Reads the controller's registers to determine what interface
5988c2ecf20Sopenharmony_ci * connects it to the PHY.
5998c2ecf20Sopenharmony_ci */
6008c2ecf20Sopenharmony_cistatic phy_interface_t gfar_get_interface(struct net_device *dev)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
6038c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
6048c2ecf20Sopenharmony_ci	u32 ecntrl;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	ecntrl = gfar_read(&regs->ecntrl);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (ecntrl & ECNTRL_SGMII_MODE)
6098c2ecf20Sopenharmony_ci		return PHY_INTERFACE_MODE_SGMII;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (ecntrl & ECNTRL_TBI_MODE) {
6128c2ecf20Sopenharmony_ci		if (ecntrl & ECNTRL_REDUCED_MODE)
6138c2ecf20Sopenharmony_ci			return PHY_INTERFACE_MODE_RTBI;
6148c2ecf20Sopenharmony_ci		else
6158c2ecf20Sopenharmony_ci			return PHY_INTERFACE_MODE_TBI;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (ecntrl & ECNTRL_REDUCED_MODE) {
6198c2ecf20Sopenharmony_ci		if (ecntrl & ECNTRL_REDUCED_MII_MODE) {
6208c2ecf20Sopenharmony_ci			return PHY_INTERFACE_MODE_RMII;
6218c2ecf20Sopenharmony_ci		}
6228c2ecf20Sopenharmony_ci		else {
6238c2ecf20Sopenharmony_ci			phy_interface_t interface = priv->interface;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci			/* This isn't autodetected right now, so it must
6268c2ecf20Sopenharmony_ci			 * be set by the device tree or platform code.
6278c2ecf20Sopenharmony_ci			 */
6288c2ecf20Sopenharmony_ci			if (interface == PHY_INTERFACE_MODE_RGMII_ID)
6298c2ecf20Sopenharmony_ci				return PHY_INTERFACE_MODE_RGMII_ID;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci			return PHY_INTERFACE_MODE_RGMII;
6328c2ecf20Sopenharmony_ci		}
6338c2ecf20Sopenharmony_ci	}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
6368c2ecf20Sopenharmony_ci		return PHY_INTERFACE_MODE_GMII;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return PHY_INTERFACE_MODE_MII;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	const char *model;
6448c2ecf20Sopenharmony_ci	const void *mac_addr;
6458c2ecf20Sopenharmony_ci	int err = 0, i;
6468c2ecf20Sopenharmony_ci	phy_interface_t interface;
6478c2ecf20Sopenharmony_ci	struct net_device *dev = NULL;
6488c2ecf20Sopenharmony_ci	struct gfar_private *priv = NULL;
6498c2ecf20Sopenharmony_ci	struct device_node *np = ofdev->dev.of_node;
6508c2ecf20Sopenharmony_ci	struct device_node *child = NULL;
6518c2ecf20Sopenharmony_ci	u32 stash_len = 0;
6528c2ecf20Sopenharmony_ci	u32 stash_idx = 0;
6538c2ecf20Sopenharmony_ci	unsigned int num_tx_qs, num_rx_qs;
6548c2ecf20Sopenharmony_ci	unsigned short mode, poll_mode;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (!np)
6578c2ecf20Sopenharmony_ci		return -ENODEV;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,etsec2")) {
6608c2ecf20Sopenharmony_ci		mode = MQ_MG_MODE;
6618c2ecf20Sopenharmony_ci		poll_mode = GFAR_SQ_POLLING;
6628c2ecf20Sopenharmony_ci	} else {
6638c2ecf20Sopenharmony_ci		mode = SQ_SG_MODE;
6648c2ecf20Sopenharmony_ci		poll_mode = GFAR_SQ_POLLING;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (mode == SQ_SG_MODE) {
6688c2ecf20Sopenharmony_ci		num_tx_qs = 1;
6698c2ecf20Sopenharmony_ci		num_rx_qs = 1;
6708c2ecf20Sopenharmony_ci	} else { /* MQ_MG_MODE */
6718c2ecf20Sopenharmony_ci		/* get the actual number of supported groups */
6728c2ecf20Sopenharmony_ci		unsigned int num_grps = gfar_of_group_count(np);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci		if (num_grps == 0 || num_grps > MAXGROUPS) {
6758c2ecf20Sopenharmony_ci			dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
6768c2ecf20Sopenharmony_ci				num_grps);
6778c2ecf20Sopenharmony_ci			pr_err("Cannot do alloc_etherdev, aborting\n");
6788c2ecf20Sopenharmony_ci			return -EINVAL;
6798c2ecf20Sopenharmony_ci		}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		if (poll_mode == GFAR_SQ_POLLING) {
6828c2ecf20Sopenharmony_ci			num_tx_qs = num_grps; /* one txq per int group */
6838c2ecf20Sopenharmony_ci			num_rx_qs = num_grps; /* one rxq per int group */
6848c2ecf20Sopenharmony_ci		} else { /* GFAR_MQ_POLLING */
6858c2ecf20Sopenharmony_ci			u32 tx_queues, rx_queues;
6868c2ecf20Sopenharmony_ci			int ret;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci			/* parse the num of HW tx and rx queues */
6898c2ecf20Sopenharmony_ci			ret = of_property_read_u32(np, "fsl,num_tx_queues",
6908c2ecf20Sopenharmony_ci						   &tx_queues);
6918c2ecf20Sopenharmony_ci			num_tx_qs = ret ? 1 : tx_queues;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci			ret = of_property_read_u32(np, "fsl,num_rx_queues",
6948c2ecf20Sopenharmony_ci						   &rx_queues);
6958c2ecf20Sopenharmony_ci			num_rx_qs = ret ? 1 : rx_queues;
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (num_tx_qs > MAX_TX_QS) {
7008c2ecf20Sopenharmony_ci		pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n",
7018c2ecf20Sopenharmony_ci		       num_tx_qs, MAX_TX_QS);
7028c2ecf20Sopenharmony_ci		pr_err("Cannot do alloc_etherdev, aborting\n");
7038c2ecf20Sopenharmony_ci		return -EINVAL;
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if (num_rx_qs > MAX_RX_QS) {
7078c2ecf20Sopenharmony_ci		pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n",
7088c2ecf20Sopenharmony_ci		       num_rx_qs, MAX_RX_QS);
7098c2ecf20Sopenharmony_ci		pr_err("Cannot do alloc_etherdev, aborting\n");
7108c2ecf20Sopenharmony_ci		return -EINVAL;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	*pdev = alloc_etherdev_mq(sizeof(*priv), num_tx_qs);
7148c2ecf20Sopenharmony_ci	dev = *pdev;
7158c2ecf20Sopenharmony_ci	if (NULL == dev)
7168c2ecf20Sopenharmony_ci		return -ENOMEM;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	priv = netdev_priv(dev);
7198c2ecf20Sopenharmony_ci	priv->ndev = dev;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	priv->mode = mode;
7228c2ecf20Sopenharmony_ci	priv->poll_mode = poll_mode;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	priv->num_tx_queues = num_tx_qs;
7258c2ecf20Sopenharmony_ci	netif_set_real_num_rx_queues(dev, num_rx_qs);
7268c2ecf20Sopenharmony_ci	priv->num_rx_queues = num_rx_qs;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	err = gfar_alloc_tx_queues(priv);
7298c2ecf20Sopenharmony_ci	if (err)
7308c2ecf20Sopenharmony_ci		goto tx_alloc_failed;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	err = gfar_alloc_rx_queues(priv);
7338c2ecf20Sopenharmony_ci	if (err)
7348c2ecf20Sopenharmony_ci		goto rx_alloc_failed;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	err = of_property_read_string(np, "model", &model);
7378c2ecf20Sopenharmony_ci	if (err) {
7388c2ecf20Sopenharmony_ci		pr_err("Device model property missing, aborting\n");
7398c2ecf20Sopenharmony_ci		goto rx_alloc_failed;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	/* Init Rx queue filer rule set linked list */
7438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&priv->rx_list.list);
7448c2ecf20Sopenharmony_ci	priv->rx_list.count = 0;
7458c2ecf20Sopenharmony_ci	mutex_init(&priv->rx_queue_access);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	for (i = 0; i < MAXGROUPS; i++)
7488c2ecf20Sopenharmony_ci		priv->gfargrp[i].regs = NULL;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/* Parse and initialize group specific information */
7518c2ecf20Sopenharmony_ci	if (priv->mode == MQ_MG_MODE) {
7528c2ecf20Sopenharmony_ci		for_each_available_child_of_node(np, child) {
7538c2ecf20Sopenharmony_ci			if (!of_node_name_eq(child, "queue-group"))
7548c2ecf20Sopenharmony_ci				continue;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci			err = gfar_parse_group(child, priv, model);
7578c2ecf20Sopenharmony_ci			if (err) {
7588c2ecf20Sopenharmony_ci				of_node_put(child);
7598c2ecf20Sopenharmony_ci				goto err_grp_init;
7608c2ecf20Sopenharmony_ci			}
7618c2ecf20Sopenharmony_ci		}
7628c2ecf20Sopenharmony_ci	} else { /* SQ_SG_MODE */
7638c2ecf20Sopenharmony_ci		err = gfar_parse_group(np, priv, model);
7648c2ecf20Sopenharmony_ci		if (err)
7658c2ecf20Sopenharmony_ci			goto err_grp_init;
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "bd-stash")) {
7698c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_BD_STASHING;
7708c2ecf20Sopenharmony_ci		priv->bd_stash_en = 1;
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	err = of_property_read_u32(np, "rx-stash-len", &stash_len);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (err == 0)
7768c2ecf20Sopenharmony_ci		priv->rx_stash_size = stash_len;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	err = of_property_read_u32(np, "rx-stash-idx", &stash_idx);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (err == 0)
7818c2ecf20Sopenharmony_ci		priv->rx_stash_index = stash_idx;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	if (stash_len || stash_idx)
7848c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_BUF_STASHING;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	mac_addr = of_get_mac_address(np);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (!IS_ERR(mac_addr)) {
7898c2ecf20Sopenharmony_ci		ether_addr_copy(dev->dev_addr, mac_addr);
7908c2ecf20Sopenharmony_ci	} else {
7918c2ecf20Sopenharmony_ci		eth_hw_addr_random(dev);
7928c2ecf20Sopenharmony_ci		dev_info(&ofdev->dev, "Using random MAC address: %pM\n", dev->dev_addr);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (model && !strcasecmp(model, "TSEC"))
7968c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
7978c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_COALESCE |
7988c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_RMON |
7998c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_MULTI_INTR;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	if (model && !strcasecmp(model, "eTSEC"))
8028c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
8038c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_COALESCE |
8048c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_RMON |
8058c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_MULTI_INTR |
8068c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_CSUM |
8078c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_VLAN |
8088c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
8098c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
8108c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_TIMER |
8118c2ecf20Sopenharmony_ci				     FSL_GIANFAR_DEV_HAS_RX_FILER;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	/* Use PHY connection type from the DT node if one is specified there.
8148c2ecf20Sopenharmony_ci	 * rgmii-id really needs to be specified. Other types can be
8158c2ecf20Sopenharmony_ci	 * detected by hardware
8168c2ecf20Sopenharmony_ci	 */
8178c2ecf20Sopenharmony_ci	err = of_get_phy_mode(np, &interface);
8188c2ecf20Sopenharmony_ci	if (!err)
8198c2ecf20Sopenharmony_ci		priv->interface = interface;
8208c2ecf20Sopenharmony_ci	else
8218c2ecf20Sopenharmony_ci		priv->interface = gfar_get_interface(dev);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (of_find_property(np, "fsl,magic-packet", NULL))
8248c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (of_get_property(np, "fsl,wake-on-filer", NULL))
8278c2ecf20Sopenharmony_ci		priv->device_flags |= FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	priv->phy_node = of_parse_phandle(np, "phy-handle", 0);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* In the case of a fixed PHY, the DT node associated
8328c2ecf20Sopenharmony_ci	 * to the PHY is the Ethernet MAC DT node.
8338c2ecf20Sopenharmony_ci	 */
8348c2ecf20Sopenharmony_ci	if (!priv->phy_node && of_phy_is_fixed_link(np)) {
8358c2ecf20Sopenharmony_ci		err = of_phy_register_fixed_link(np);
8368c2ecf20Sopenharmony_ci		if (err)
8378c2ecf20Sopenharmony_ci			goto err_grp_init;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		priv->phy_node = of_node_get(np);
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/* Find the TBI PHY.  If it's not there, we don't support SGMII */
8438c2ecf20Sopenharmony_ci	priv->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	return 0;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cierr_grp_init:
8488c2ecf20Sopenharmony_ci	unmap_group_regs(priv);
8498c2ecf20Sopenharmony_cirx_alloc_failed:
8508c2ecf20Sopenharmony_ci	gfar_free_rx_queues(priv);
8518c2ecf20Sopenharmony_citx_alloc_failed:
8528c2ecf20Sopenharmony_ci	gfar_free_tx_queues(priv);
8538c2ecf20Sopenharmony_ci	free_gfar_dev(priv);
8548c2ecf20Sopenharmony_ci	return err;
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar,
8588c2ecf20Sopenharmony_ci				   u32 class)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	u32 rqfpr = FPR_FILER_MASK;
8618c2ecf20Sopenharmony_ci	u32 rqfcr = 0x0;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	rqfar--;
8648c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CLE | RQFCR_PID_MASK | RQFCR_CMP_EXACT;
8658c2ecf20Sopenharmony_ci	priv->ftp_rqfpr[rqfar] = rqfpr;
8668c2ecf20Sopenharmony_ci	priv->ftp_rqfcr[rqfar] = rqfcr;
8678c2ecf20Sopenharmony_ci	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	rqfar--;
8708c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CMP_NOMATCH;
8718c2ecf20Sopenharmony_ci	priv->ftp_rqfpr[rqfar] = rqfpr;
8728c2ecf20Sopenharmony_ci	priv->ftp_rqfcr[rqfar] = rqfcr;
8738c2ecf20Sopenharmony_ci	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	rqfar--;
8768c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_PARSE | RQFCR_CLE | RQFCR_AND;
8778c2ecf20Sopenharmony_ci	rqfpr = class;
8788c2ecf20Sopenharmony_ci	priv->ftp_rqfcr[rqfar] = rqfcr;
8798c2ecf20Sopenharmony_ci	priv->ftp_rqfpr[rqfar] = rqfpr;
8808c2ecf20Sopenharmony_ci	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	rqfar--;
8838c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CMP_EXACT | RQFCR_PID_MASK | RQFCR_AND;
8848c2ecf20Sopenharmony_ci	rqfpr = class;
8858c2ecf20Sopenharmony_ci	priv->ftp_rqfcr[rqfar] = rqfcr;
8868c2ecf20Sopenharmony_ci	priv->ftp_rqfpr[rqfar] = rqfpr;
8878c2ecf20Sopenharmony_ci	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return rqfar;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic void gfar_init_filer_table(struct gfar_private *priv)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	int i = 0x0;
8958c2ecf20Sopenharmony_ci	u32 rqfar = MAX_FILER_IDX;
8968c2ecf20Sopenharmony_ci	u32 rqfcr = 0x0;
8978c2ecf20Sopenharmony_ci	u32 rqfpr = FPR_FILER_MASK;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	/* Default rule */
9008c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CMP_MATCH;
9018c2ecf20Sopenharmony_ci	priv->ftp_rqfcr[rqfar] = rqfcr;
9028c2ecf20Sopenharmony_ci	priv->ftp_rqfpr[rqfar] = rqfpr;
9038c2ecf20Sopenharmony_ci	gfar_write_filer(priv, rqfar, rqfcr, rqfpr);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6);
9068c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_UDP);
9078c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV6 | RQFPR_TCP);
9088c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4);
9098c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_UDP);
9108c2ecf20Sopenharmony_ci	rqfar = cluster_entry_per_class(priv, rqfar, RQFPR_IPV4 | RQFPR_TCP);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* cur_filer_idx indicated the first non-masked rule */
9138c2ecf20Sopenharmony_ci	priv->cur_filer_idx = rqfar;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/* Rest are masked rules */
9168c2ecf20Sopenharmony_ci	rqfcr = RQFCR_CMP_NOMATCH;
9178c2ecf20Sopenharmony_ci	for (i = 0; i < rqfar; i++) {
9188c2ecf20Sopenharmony_ci		priv->ftp_rqfcr[i] = rqfcr;
9198c2ecf20Sopenharmony_ci		priv->ftp_rqfpr[i] = rqfpr;
9208c2ecf20Sopenharmony_ci		gfar_write_filer(priv, i, rqfcr, rqfpr);
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
9258c2ecf20Sopenharmony_cistatic void __gfar_detect_errata_83xx(struct gfar_private *priv)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	unsigned int pvr = mfspr(SPRN_PVR);
9288c2ecf20Sopenharmony_ci	unsigned int svr = mfspr(SPRN_SVR);
9298c2ecf20Sopenharmony_ci	unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
9308c2ecf20Sopenharmony_ci	unsigned int rev = svr & 0xffff;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* MPC8313 Rev 2.0 and higher; All MPC837x */
9338c2ecf20Sopenharmony_ci	if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
9348c2ecf20Sopenharmony_ci	    (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
9358c2ecf20Sopenharmony_ci		priv->errata |= GFAR_ERRATA_74;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	/* MPC8313 and MPC837x all rev */
9388c2ecf20Sopenharmony_ci	if ((pvr == 0x80850010 && mod == 0x80b0) ||
9398c2ecf20Sopenharmony_ci	    (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
9408c2ecf20Sopenharmony_ci		priv->errata |= GFAR_ERRATA_76;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/* MPC8313 Rev < 2.0 */
9438c2ecf20Sopenharmony_ci	if (pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020)
9448c2ecf20Sopenharmony_ci		priv->errata |= GFAR_ERRATA_12;
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_cistatic void __gfar_detect_errata_85xx(struct gfar_private *priv)
9488c2ecf20Sopenharmony_ci{
9498c2ecf20Sopenharmony_ci	unsigned int svr = mfspr(SPRN_SVR);
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	if ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) == 0x20))
9528c2ecf20Sopenharmony_ci		priv->errata |= GFAR_ERRATA_12;
9538c2ecf20Sopenharmony_ci	/* P2020/P1010 Rev 1; MPC8548 Rev 2 */
9548c2ecf20Sopenharmony_ci	if (((SVR_SOC_VER(svr) == SVR_P2020) && (SVR_REV(svr) < 0x20)) ||
9558c2ecf20Sopenharmony_ci	    ((SVR_SOC_VER(svr) == SVR_P2010) && (SVR_REV(svr) < 0x20)) ||
9568c2ecf20Sopenharmony_ci	    ((SVR_SOC_VER(svr) == SVR_8548) && (SVR_REV(svr) < 0x31)))
9578c2ecf20Sopenharmony_ci		priv->errata |= GFAR_ERRATA_76; /* aka eTSEC 20 */
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci#endif
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic void gfar_detect_errata(struct gfar_private *priv)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct device *dev = &priv->ofdev->dev;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	/* no plans to fix */
9668c2ecf20Sopenharmony_ci	priv->errata |= GFAR_ERRATA_A002;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC
9698c2ecf20Sopenharmony_ci	if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2))
9708c2ecf20Sopenharmony_ci		__gfar_detect_errata_85xx(priv);
9718c2ecf20Sopenharmony_ci	else /* non-mpc85xx parts, i.e. e300 core based */
9728c2ecf20Sopenharmony_ci		__gfar_detect_errata_83xx(priv);
9738c2ecf20Sopenharmony_ci#endif
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (priv->errata)
9768c2ecf20Sopenharmony_ci		dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
9778c2ecf20Sopenharmony_ci			 priv->errata);
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cistatic void gfar_init_addr_hash_table(struct gfar_private *priv)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
9858c2ecf20Sopenharmony_ci		priv->extended_hash = 1;
9868c2ecf20Sopenharmony_ci		priv->hash_width = 9;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		priv->hash_regs[0] = &regs->igaddr0;
9898c2ecf20Sopenharmony_ci		priv->hash_regs[1] = &regs->igaddr1;
9908c2ecf20Sopenharmony_ci		priv->hash_regs[2] = &regs->igaddr2;
9918c2ecf20Sopenharmony_ci		priv->hash_regs[3] = &regs->igaddr3;
9928c2ecf20Sopenharmony_ci		priv->hash_regs[4] = &regs->igaddr4;
9938c2ecf20Sopenharmony_ci		priv->hash_regs[5] = &regs->igaddr5;
9948c2ecf20Sopenharmony_ci		priv->hash_regs[6] = &regs->igaddr6;
9958c2ecf20Sopenharmony_ci		priv->hash_regs[7] = &regs->igaddr7;
9968c2ecf20Sopenharmony_ci		priv->hash_regs[8] = &regs->gaddr0;
9978c2ecf20Sopenharmony_ci		priv->hash_regs[9] = &regs->gaddr1;
9988c2ecf20Sopenharmony_ci		priv->hash_regs[10] = &regs->gaddr2;
9998c2ecf20Sopenharmony_ci		priv->hash_regs[11] = &regs->gaddr3;
10008c2ecf20Sopenharmony_ci		priv->hash_regs[12] = &regs->gaddr4;
10018c2ecf20Sopenharmony_ci		priv->hash_regs[13] = &regs->gaddr5;
10028c2ecf20Sopenharmony_ci		priv->hash_regs[14] = &regs->gaddr6;
10038c2ecf20Sopenharmony_ci		priv->hash_regs[15] = &regs->gaddr7;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	} else {
10068c2ecf20Sopenharmony_ci		priv->extended_hash = 0;
10078c2ecf20Sopenharmony_ci		priv->hash_width = 8;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		priv->hash_regs[0] = &regs->gaddr0;
10108c2ecf20Sopenharmony_ci		priv->hash_regs[1] = &regs->gaddr1;
10118c2ecf20Sopenharmony_ci		priv->hash_regs[2] = &regs->gaddr2;
10128c2ecf20Sopenharmony_ci		priv->hash_regs[3] = &regs->gaddr3;
10138c2ecf20Sopenharmony_ci		priv->hash_regs[4] = &regs->gaddr4;
10148c2ecf20Sopenharmony_ci		priv->hash_regs[5] = &regs->gaddr5;
10158c2ecf20Sopenharmony_ci		priv->hash_regs[6] = &regs->gaddr6;
10168c2ecf20Sopenharmony_ci		priv->hash_regs[7] = &regs->gaddr7;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_cistatic int __gfar_is_rx_idle(struct gfar_private *priv)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	u32 res;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	/* Normaly TSEC should not hang on GRS commands, so we should
10258c2ecf20Sopenharmony_ci	 * actually wait for IEVENT_GRSC flag.
10268c2ecf20Sopenharmony_ci	 */
10278c2ecf20Sopenharmony_ci	if (!gfar_has_errata(priv, GFAR_ERRATA_A002))
10288c2ecf20Sopenharmony_ci		return 0;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	/* Read the eTSEC register at offset 0xD1C. If bits 7-14 are
10318c2ecf20Sopenharmony_ci	 * the same as bits 23-30, the eTSEC Rx is assumed to be idle
10328c2ecf20Sopenharmony_ci	 * and the Rx can be safely reset.
10338c2ecf20Sopenharmony_ci	 */
10348c2ecf20Sopenharmony_ci	res = gfar_read((void __iomem *)priv->gfargrp[0].regs + 0xd1c);
10358c2ecf20Sopenharmony_ci	res &= 0x7f807f80;
10368c2ecf20Sopenharmony_ci	if ((res & 0xffff) == (res >> 16))
10378c2ecf20Sopenharmony_ci		return 1;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return 0;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci/* Halt the receive and transmit queues */
10438c2ecf20Sopenharmony_cistatic void gfar_halt_nodisable(struct gfar_private *priv)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
10468c2ecf20Sopenharmony_ci	u32 tempval;
10478c2ecf20Sopenharmony_ci	unsigned int timeout;
10488c2ecf20Sopenharmony_ci	int stopped;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	gfar_ints_disable(priv);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (gfar_is_dma_stopped(priv))
10538c2ecf20Sopenharmony_ci		return;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Stop the DMA, and wait for it to stop */
10568c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->dmactrl);
10578c2ecf20Sopenharmony_ci	tempval |= (DMACTRL_GRS | DMACTRL_GTS);
10588c2ecf20Sopenharmony_ci	gfar_write(&regs->dmactrl, tempval);
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ciretry:
10618c2ecf20Sopenharmony_ci	timeout = 1000;
10628c2ecf20Sopenharmony_ci	while (!(stopped = gfar_is_dma_stopped(priv)) && timeout) {
10638c2ecf20Sopenharmony_ci		cpu_relax();
10648c2ecf20Sopenharmony_ci		timeout--;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	if (!timeout)
10688c2ecf20Sopenharmony_ci		stopped = gfar_is_dma_stopped(priv);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (!stopped && !gfar_is_rx_dma_stopped(priv) &&
10718c2ecf20Sopenharmony_ci	    !__gfar_is_rx_idle(priv))
10728c2ecf20Sopenharmony_ci		goto retry;
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci/* Halt the receive and transmit queues */
10768c2ecf20Sopenharmony_cistatic void gfar_halt(struct gfar_private *priv)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
10798c2ecf20Sopenharmony_ci	u32 tempval;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	/* Dissable the Rx/Tx hw queues */
10828c2ecf20Sopenharmony_ci	gfar_write(&regs->rqueue, 0);
10838c2ecf20Sopenharmony_ci	gfar_write(&regs->tqueue, 0);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	mdelay(10);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	gfar_halt_nodisable(priv);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	/* Disable Rx/Tx DMA */
10908c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->maccfg1);
10918c2ecf20Sopenharmony_ci	tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
10928c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg1, tempval);
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	struct txbd8 *txbdp;
10988c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(tx_queue->dev);
10998c2ecf20Sopenharmony_ci	int i, j;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	txbdp = tx_queue->tx_bd_base;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	for (i = 0; i < tx_queue->tx_ring_size; i++) {
11048c2ecf20Sopenharmony_ci		if (!tx_queue->tx_skbuff[i])
11058c2ecf20Sopenharmony_ci			continue;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci		dma_unmap_single(priv->dev, be32_to_cpu(txbdp->bufPtr),
11088c2ecf20Sopenharmony_ci				 be16_to_cpu(txbdp->length), DMA_TO_DEVICE);
11098c2ecf20Sopenharmony_ci		txbdp->lstatus = 0;
11108c2ecf20Sopenharmony_ci		for (j = 0; j < skb_shinfo(tx_queue->tx_skbuff[i])->nr_frags;
11118c2ecf20Sopenharmony_ci		     j++) {
11128c2ecf20Sopenharmony_ci			txbdp++;
11138c2ecf20Sopenharmony_ci			dma_unmap_page(priv->dev, be32_to_cpu(txbdp->bufPtr),
11148c2ecf20Sopenharmony_ci				       be16_to_cpu(txbdp->length),
11158c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
11168c2ecf20Sopenharmony_ci		}
11178c2ecf20Sopenharmony_ci		txbdp++;
11188c2ecf20Sopenharmony_ci		dev_kfree_skb_any(tx_queue->tx_skbuff[i]);
11198c2ecf20Sopenharmony_ci		tx_queue->tx_skbuff[i] = NULL;
11208c2ecf20Sopenharmony_ci	}
11218c2ecf20Sopenharmony_ci	kfree(tx_queue->tx_skbuff);
11228c2ecf20Sopenharmony_ci	tx_queue->tx_skbuff = NULL;
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	int i;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	struct rxbd8 *rxbdp = rx_queue->rx_bd_base;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	dev_kfree_skb(rx_queue->skb);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	for (i = 0; i < rx_queue->rx_ring_size; i++) {
11348c2ecf20Sopenharmony_ci		struct	gfar_rx_buff *rxb = &rx_queue->rx_buff[i];
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci		rxbdp->lstatus = 0;
11378c2ecf20Sopenharmony_ci		rxbdp->bufPtr = 0;
11388c2ecf20Sopenharmony_ci		rxbdp++;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci		if (!rxb->page)
11418c2ecf20Sopenharmony_ci			continue;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci		dma_unmap_page(rx_queue->dev, rxb->dma,
11448c2ecf20Sopenharmony_ci			       PAGE_SIZE, DMA_FROM_DEVICE);
11458c2ecf20Sopenharmony_ci		__free_page(rxb->page);
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci		rxb->page = NULL;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	kfree(rx_queue->rx_buff);
11518c2ecf20Sopenharmony_ci	rx_queue->rx_buff = NULL;
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/* If there are any tx skbs or rx skbs still around, free them.
11558c2ecf20Sopenharmony_ci * Then free tx_skbuff and rx_skbuff
11568c2ecf20Sopenharmony_ci */
11578c2ecf20Sopenharmony_cistatic void free_skb_resources(struct gfar_private *priv)
11588c2ecf20Sopenharmony_ci{
11598c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = NULL;
11608c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = NULL;
11618c2ecf20Sopenharmony_ci	int i;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	/* Go through all the buffer descriptors and free their data buffers */
11648c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
11658c2ecf20Sopenharmony_ci		struct netdev_queue *txq;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci		tx_queue = priv->tx_queue[i];
11688c2ecf20Sopenharmony_ci		txq = netdev_get_tx_queue(tx_queue->dev, tx_queue->qindex);
11698c2ecf20Sopenharmony_ci		if (tx_queue->tx_skbuff)
11708c2ecf20Sopenharmony_ci			free_skb_tx_queue(tx_queue);
11718c2ecf20Sopenharmony_ci		netdev_tx_reset_queue(txq);
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
11758c2ecf20Sopenharmony_ci		rx_queue = priv->rx_queue[i];
11768c2ecf20Sopenharmony_ci		if (rx_queue->rx_buff)
11778c2ecf20Sopenharmony_ci			free_skb_rx_queue(rx_queue);
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	dma_free_coherent(priv->dev,
11818c2ecf20Sopenharmony_ci			  sizeof(struct txbd8) * priv->total_tx_ring_size +
11828c2ecf20Sopenharmony_ci			  sizeof(struct rxbd8) * priv->total_rx_ring_size,
11838c2ecf20Sopenharmony_ci			  priv->tx_queue[0]->tx_bd_base,
11848c2ecf20Sopenharmony_ci			  priv->tx_queue[0]->tx_bd_dma_base);
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_civoid stop_gfar(struct net_device *dev)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(dev);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
11948c2ecf20Sopenharmony_ci	set_bit(GFAR_DOWN, &priv->state);
11958c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	disable_napi(priv);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	/* disable ints and gracefully shut down Rx/Tx DMA */
12008c2ecf20Sopenharmony_ci	gfar_halt(priv);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	phy_stop(dev->phydev);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	free_skb_resources(priv);
12058c2ecf20Sopenharmony_ci}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_cistatic void gfar_start(struct gfar_private *priv)
12088c2ecf20Sopenharmony_ci{
12098c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
12108c2ecf20Sopenharmony_ci	u32 tempval;
12118c2ecf20Sopenharmony_ci	int i = 0;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	/* Enable Rx/Tx hw queues */
12148c2ecf20Sopenharmony_ci	gfar_write(&regs->rqueue, priv->rqueue);
12158c2ecf20Sopenharmony_ci	gfar_write(&regs->tqueue, priv->tqueue);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	/* Initialize DMACTRL to have WWR and WOP */
12188c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->dmactrl);
12198c2ecf20Sopenharmony_ci	tempval |= DMACTRL_INIT_SETTINGS;
12208c2ecf20Sopenharmony_ci	gfar_write(&regs->dmactrl, tempval);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	/* Make sure we aren't stopped */
12238c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->dmactrl);
12248c2ecf20Sopenharmony_ci	tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
12258c2ecf20Sopenharmony_ci	gfar_write(&regs->dmactrl, tempval);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
12288c2ecf20Sopenharmony_ci		regs = priv->gfargrp[i].regs;
12298c2ecf20Sopenharmony_ci		/* Clear THLT/RHLT, so that the DMA starts polling now */
12308c2ecf20Sopenharmony_ci		gfar_write(&regs->tstat, priv->gfargrp[i].tstat);
12318c2ecf20Sopenharmony_ci		gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
12328c2ecf20Sopenharmony_ci	}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	/* Enable Rx/Tx DMA */
12358c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->maccfg1);
12368c2ecf20Sopenharmony_ci	tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
12378c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg1, tempval);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	gfar_ints_enable(priv);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	netif_trans_update(priv->ndev); /* prevent tx timeout */
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cistatic bool gfar_new_page(struct gfar_priv_rx_q *rxq, struct gfar_rx_buff *rxb)
12458c2ecf20Sopenharmony_ci{
12468c2ecf20Sopenharmony_ci	struct page *page;
12478c2ecf20Sopenharmony_ci	dma_addr_t addr;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	page = dev_alloc_page();
12508c2ecf20Sopenharmony_ci	if (unlikely(!page))
12518c2ecf20Sopenharmony_ci		return false;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	addr = dma_map_page(rxq->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
12548c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(rxq->dev, addr))) {
12558c2ecf20Sopenharmony_ci		__free_page(page);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci		return false;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	rxb->dma = addr;
12618c2ecf20Sopenharmony_ci	rxb->page = page;
12628c2ecf20Sopenharmony_ci	rxb->page_offset = 0;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	return true;
12658c2ecf20Sopenharmony_ci}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistatic void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(rx_queue->ndev);
12708c2ecf20Sopenharmony_ci	struct gfar_extra_stats *estats = &priv->extra_stats;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	netdev_err(rx_queue->ndev, "Can't alloc RX buffers\n");
12738c2ecf20Sopenharmony_ci	atomic64_inc(&estats->rx_alloc_err);
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue,
12778c2ecf20Sopenharmony_ci				int alloc_cnt)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct rxbd8 *bdp;
12808c2ecf20Sopenharmony_ci	struct gfar_rx_buff *rxb;
12818c2ecf20Sopenharmony_ci	int i;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	i = rx_queue->next_to_use;
12848c2ecf20Sopenharmony_ci	bdp = &rx_queue->rx_bd_base[i];
12858c2ecf20Sopenharmony_ci	rxb = &rx_queue->rx_buff[i];
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	while (alloc_cnt--) {
12888c2ecf20Sopenharmony_ci		/* try reuse page */
12898c2ecf20Sopenharmony_ci		if (unlikely(!rxb->page)) {
12908c2ecf20Sopenharmony_ci			if (unlikely(!gfar_new_page(rx_queue, rxb))) {
12918c2ecf20Sopenharmony_ci				gfar_rx_alloc_err(rx_queue);
12928c2ecf20Sopenharmony_ci				break;
12938c2ecf20Sopenharmony_ci			}
12948c2ecf20Sopenharmony_ci		}
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		/* Setup the new RxBD */
12978c2ecf20Sopenharmony_ci		gfar_init_rxbdp(rx_queue, bdp,
12988c2ecf20Sopenharmony_ci				rxb->dma + rxb->page_offset + RXBUF_ALIGNMENT);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci		/* Update to the next pointer */
13018c2ecf20Sopenharmony_ci		bdp++;
13028c2ecf20Sopenharmony_ci		rxb++;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci		if (unlikely(++i == rx_queue->rx_ring_size)) {
13058c2ecf20Sopenharmony_ci			i = 0;
13068c2ecf20Sopenharmony_ci			bdp = rx_queue->rx_bd_base;
13078c2ecf20Sopenharmony_ci			rxb = rx_queue->rx_buff;
13088c2ecf20Sopenharmony_ci		}
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	rx_queue->next_to_use = i;
13128c2ecf20Sopenharmony_ci	rx_queue->next_to_alloc = i;
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_cistatic void gfar_init_bds(struct net_device *ndev)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
13188c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
13198c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = NULL;
13208c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = NULL;
13218c2ecf20Sopenharmony_ci	struct txbd8 *txbdp;
13228c2ecf20Sopenharmony_ci	u32 __iomem *rfbptr;
13238c2ecf20Sopenharmony_ci	int i, j;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
13268c2ecf20Sopenharmony_ci		tx_queue = priv->tx_queue[i];
13278c2ecf20Sopenharmony_ci		/* Initialize some variables in our dev structure */
13288c2ecf20Sopenharmony_ci		tx_queue->num_txbdfree = tx_queue->tx_ring_size;
13298c2ecf20Sopenharmony_ci		tx_queue->dirty_tx = tx_queue->tx_bd_base;
13308c2ecf20Sopenharmony_ci		tx_queue->cur_tx = tx_queue->tx_bd_base;
13318c2ecf20Sopenharmony_ci		tx_queue->skb_curtx = 0;
13328c2ecf20Sopenharmony_ci		tx_queue->skb_dirtytx = 0;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		/* Initialize Transmit Descriptor Ring */
13358c2ecf20Sopenharmony_ci		txbdp = tx_queue->tx_bd_base;
13368c2ecf20Sopenharmony_ci		for (j = 0; j < tx_queue->tx_ring_size; j++) {
13378c2ecf20Sopenharmony_ci			txbdp->lstatus = 0;
13388c2ecf20Sopenharmony_ci			txbdp->bufPtr = 0;
13398c2ecf20Sopenharmony_ci			txbdp++;
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		/* Set the last descriptor in the ring to indicate wrap */
13438c2ecf20Sopenharmony_ci		txbdp--;
13448c2ecf20Sopenharmony_ci		txbdp->status = cpu_to_be16(be16_to_cpu(txbdp->status) |
13458c2ecf20Sopenharmony_ci					    TXBD_WRAP);
13468c2ecf20Sopenharmony_ci	}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	rfbptr = &regs->rfbptr0;
13498c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
13508c2ecf20Sopenharmony_ci		rx_queue = priv->rx_queue[i];
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci		rx_queue->next_to_clean = 0;
13538c2ecf20Sopenharmony_ci		rx_queue->next_to_use = 0;
13548c2ecf20Sopenharmony_ci		rx_queue->next_to_alloc = 0;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci		/* make sure next_to_clean != next_to_use after this
13578c2ecf20Sopenharmony_ci		 * by leaving at least 1 unused descriptor
13588c2ecf20Sopenharmony_ci		 */
13598c2ecf20Sopenharmony_ci		gfar_alloc_rx_buffs(rx_queue, gfar_rxbd_unused(rx_queue));
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci		rx_queue->rfbptr = rfbptr;
13628c2ecf20Sopenharmony_ci		rfbptr += 2;
13638c2ecf20Sopenharmony_ci	}
13648c2ecf20Sopenharmony_ci}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic int gfar_alloc_skb_resources(struct net_device *ndev)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	void *vaddr;
13698c2ecf20Sopenharmony_ci	dma_addr_t addr;
13708c2ecf20Sopenharmony_ci	int i, j;
13718c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
13728c2ecf20Sopenharmony_ci	struct device *dev = priv->dev;
13738c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = NULL;
13748c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = NULL;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	priv->total_tx_ring_size = 0;
13778c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++)
13788c2ecf20Sopenharmony_ci		priv->total_tx_ring_size += priv->tx_queue[i]->tx_ring_size;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	priv->total_rx_ring_size = 0;
13818c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++)
13828c2ecf20Sopenharmony_ci		priv->total_rx_ring_size += priv->rx_queue[i]->rx_ring_size;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci	/* Allocate memory for the buffer descriptors */
13858c2ecf20Sopenharmony_ci	vaddr = dma_alloc_coherent(dev,
13868c2ecf20Sopenharmony_ci				   (priv->total_tx_ring_size *
13878c2ecf20Sopenharmony_ci				    sizeof(struct txbd8)) +
13888c2ecf20Sopenharmony_ci				   (priv->total_rx_ring_size *
13898c2ecf20Sopenharmony_ci				    sizeof(struct rxbd8)),
13908c2ecf20Sopenharmony_ci				   &addr, GFP_KERNEL);
13918c2ecf20Sopenharmony_ci	if (!vaddr)
13928c2ecf20Sopenharmony_ci		return -ENOMEM;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
13958c2ecf20Sopenharmony_ci		tx_queue = priv->tx_queue[i];
13968c2ecf20Sopenharmony_ci		tx_queue->tx_bd_base = vaddr;
13978c2ecf20Sopenharmony_ci		tx_queue->tx_bd_dma_base = addr;
13988c2ecf20Sopenharmony_ci		tx_queue->dev = ndev;
13998c2ecf20Sopenharmony_ci		/* enet DMA only understands physical addresses */
14008c2ecf20Sopenharmony_ci		addr  += sizeof(struct txbd8) * tx_queue->tx_ring_size;
14018c2ecf20Sopenharmony_ci		vaddr += sizeof(struct txbd8) * tx_queue->tx_ring_size;
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	/* Start the rx descriptor ring where the tx ring leaves off */
14058c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
14068c2ecf20Sopenharmony_ci		rx_queue = priv->rx_queue[i];
14078c2ecf20Sopenharmony_ci		rx_queue->rx_bd_base = vaddr;
14088c2ecf20Sopenharmony_ci		rx_queue->rx_bd_dma_base = addr;
14098c2ecf20Sopenharmony_ci		rx_queue->ndev = ndev;
14108c2ecf20Sopenharmony_ci		rx_queue->dev = dev;
14118c2ecf20Sopenharmony_ci		addr  += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
14128c2ecf20Sopenharmony_ci		vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size;
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	/* Setup the skbuff rings */
14168c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
14178c2ecf20Sopenharmony_ci		tx_queue = priv->tx_queue[i];
14188c2ecf20Sopenharmony_ci		tx_queue->tx_skbuff =
14198c2ecf20Sopenharmony_ci			kmalloc_array(tx_queue->tx_ring_size,
14208c2ecf20Sopenharmony_ci				      sizeof(*tx_queue->tx_skbuff),
14218c2ecf20Sopenharmony_ci				      GFP_KERNEL);
14228c2ecf20Sopenharmony_ci		if (!tx_queue->tx_skbuff)
14238c2ecf20Sopenharmony_ci			goto cleanup;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci		for (j = 0; j < tx_queue->tx_ring_size; j++)
14268c2ecf20Sopenharmony_ci			tx_queue->tx_skbuff[j] = NULL;
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
14308c2ecf20Sopenharmony_ci		rx_queue = priv->rx_queue[i];
14318c2ecf20Sopenharmony_ci		rx_queue->rx_buff = kcalloc(rx_queue->rx_ring_size,
14328c2ecf20Sopenharmony_ci					    sizeof(*rx_queue->rx_buff),
14338c2ecf20Sopenharmony_ci					    GFP_KERNEL);
14348c2ecf20Sopenharmony_ci		if (!rx_queue->rx_buff)
14358c2ecf20Sopenharmony_ci			goto cleanup;
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	gfar_init_bds(ndev);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	return 0;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cicleanup:
14438c2ecf20Sopenharmony_ci	free_skb_resources(priv);
14448c2ecf20Sopenharmony_ci	return -ENOMEM;
14458c2ecf20Sopenharmony_ci}
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci/* Bring the controller up and running */
14488c2ecf20Sopenharmony_ciint startup_gfar(struct net_device *ndev)
14498c2ecf20Sopenharmony_ci{
14508c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
14518c2ecf20Sopenharmony_ci	int err;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	gfar_mac_reset(priv);
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	err = gfar_alloc_skb_resources(ndev);
14568c2ecf20Sopenharmony_ci	if (err)
14578c2ecf20Sopenharmony_ci		return err;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	gfar_init_tx_rx_base(priv);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
14628c2ecf20Sopenharmony_ci	clear_bit(GFAR_DOWN, &priv->state);
14638c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	/* Start Rx/Tx DMA and enable the interrupts */
14668c2ecf20Sopenharmony_ci	gfar_start(priv);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	/* force link state update after mac reset */
14698c2ecf20Sopenharmony_ci	priv->oldlink = 0;
14708c2ecf20Sopenharmony_ci	priv->oldspeed = 0;
14718c2ecf20Sopenharmony_ci	priv->oldduplex = -1;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	phy_start(ndev->phydev);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	enable_napi(priv);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	netif_tx_wake_all_queues(ndev);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	return 0;
14808c2ecf20Sopenharmony_ci}
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_cistatic u32 gfar_get_flowctrl_cfg(struct gfar_private *priv)
14838c2ecf20Sopenharmony_ci{
14848c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
14858c2ecf20Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
14868c2ecf20Sopenharmony_ci	u32 val = 0;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	if (!phydev->duplex)
14898c2ecf20Sopenharmony_ci		return val;
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	if (!priv->pause_aneg_en) {
14928c2ecf20Sopenharmony_ci		if (priv->tx_pause_en)
14938c2ecf20Sopenharmony_ci			val |= MACCFG1_TX_FLOW;
14948c2ecf20Sopenharmony_ci		if (priv->rx_pause_en)
14958c2ecf20Sopenharmony_ci			val |= MACCFG1_RX_FLOW;
14968c2ecf20Sopenharmony_ci	} else {
14978c2ecf20Sopenharmony_ci		u16 lcl_adv, rmt_adv;
14988c2ecf20Sopenharmony_ci		u8 flowctrl;
14998c2ecf20Sopenharmony_ci		/* get link partner capabilities */
15008c2ecf20Sopenharmony_ci		rmt_adv = 0;
15018c2ecf20Sopenharmony_ci		if (phydev->pause)
15028c2ecf20Sopenharmony_ci			rmt_adv = LPA_PAUSE_CAP;
15038c2ecf20Sopenharmony_ci		if (phydev->asym_pause)
15048c2ecf20Sopenharmony_ci			rmt_adv |= LPA_PAUSE_ASYM;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci		lcl_adv = linkmode_adv_to_lcl_adv_t(phydev->advertising);
15078c2ecf20Sopenharmony_ci		flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
15088c2ecf20Sopenharmony_ci		if (flowctrl & FLOW_CTRL_TX)
15098c2ecf20Sopenharmony_ci			val |= MACCFG1_TX_FLOW;
15108c2ecf20Sopenharmony_ci		if (flowctrl & FLOW_CTRL_RX)
15118c2ecf20Sopenharmony_ci			val |= MACCFG1_RX_FLOW;
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	return val;
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_cistatic noinline void gfar_update_link_state(struct gfar_private *priv)
15188c2ecf20Sopenharmony_ci{
15198c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
15208c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
15218c2ecf20Sopenharmony_ci	struct phy_device *phydev = ndev->phydev;
15228c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = NULL;
15238c2ecf20Sopenharmony_ci	int i;
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	if (unlikely(test_bit(GFAR_RESETTING, &priv->state)))
15268c2ecf20Sopenharmony_ci		return;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	if (phydev->link) {
15298c2ecf20Sopenharmony_ci		u32 tempval1 = gfar_read(&regs->maccfg1);
15308c2ecf20Sopenharmony_ci		u32 tempval = gfar_read(&regs->maccfg2);
15318c2ecf20Sopenharmony_ci		u32 ecntrl = gfar_read(&regs->ecntrl);
15328c2ecf20Sopenharmony_ci		u32 tx_flow_oldval = (tempval1 & MACCFG1_TX_FLOW);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci		if (phydev->duplex != priv->oldduplex) {
15358c2ecf20Sopenharmony_ci			if (!(phydev->duplex))
15368c2ecf20Sopenharmony_ci				tempval &= ~(MACCFG2_FULL_DUPLEX);
15378c2ecf20Sopenharmony_ci			else
15388c2ecf20Sopenharmony_ci				tempval |= MACCFG2_FULL_DUPLEX;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci			priv->oldduplex = phydev->duplex;
15418c2ecf20Sopenharmony_ci		}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		if (phydev->speed != priv->oldspeed) {
15448c2ecf20Sopenharmony_ci			switch (phydev->speed) {
15458c2ecf20Sopenharmony_ci			case 1000:
15468c2ecf20Sopenharmony_ci				tempval =
15478c2ecf20Sopenharmony_ci				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci				ecntrl &= ~(ECNTRL_R100);
15508c2ecf20Sopenharmony_ci				break;
15518c2ecf20Sopenharmony_ci			case 100:
15528c2ecf20Sopenharmony_ci			case 10:
15538c2ecf20Sopenharmony_ci				tempval =
15548c2ecf20Sopenharmony_ci				    ((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci				/* Reduced mode distinguishes
15578c2ecf20Sopenharmony_ci				 * between 10 and 100
15588c2ecf20Sopenharmony_ci				 */
15598c2ecf20Sopenharmony_ci				if (phydev->speed == SPEED_100)
15608c2ecf20Sopenharmony_ci					ecntrl |= ECNTRL_R100;
15618c2ecf20Sopenharmony_ci				else
15628c2ecf20Sopenharmony_ci					ecntrl &= ~(ECNTRL_R100);
15638c2ecf20Sopenharmony_ci				break;
15648c2ecf20Sopenharmony_ci			default:
15658c2ecf20Sopenharmony_ci				netif_warn(priv, link, priv->ndev,
15668c2ecf20Sopenharmony_ci					   "Ack!  Speed (%d) is not 10/100/1000!\n",
15678c2ecf20Sopenharmony_ci					   phydev->speed);
15688c2ecf20Sopenharmony_ci				break;
15698c2ecf20Sopenharmony_ci			}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci			priv->oldspeed = phydev->speed;
15728c2ecf20Sopenharmony_ci		}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		tempval1 &= ~(MACCFG1_TX_FLOW | MACCFG1_RX_FLOW);
15758c2ecf20Sopenharmony_ci		tempval1 |= gfar_get_flowctrl_cfg(priv);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci		/* Turn last free buffer recording on */
15788c2ecf20Sopenharmony_ci		if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) {
15798c2ecf20Sopenharmony_ci			for (i = 0; i < priv->num_rx_queues; i++) {
15808c2ecf20Sopenharmony_ci				u32 bdp_dma;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci				rx_queue = priv->rx_queue[i];
15838c2ecf20Sopenharmony_ci				bdp_dma = gfar_rxbd_dma_lastfree(rx_queue);
15848c2ecf20Sopenharmony_ci				gfar_write(rx_queue->rfbptr, bdp_dma);
15858c2ecf20Sopenharmony_ci			}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci			priv->tx_actual_en = 1;
15888c2ecf20Sopenharmony_ci		}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci		if (unlikely(!(tempval1 & MACCFG1_TX_FLOW) && tx_flow_oldval))
15918c2ecf20Sopenharmony_ci			priv->tx_actual_en = 0;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		gfar_write(&regs->maccfg1, tempval1);
15948c2ecf20Sopenharmony_ci		gfar_write(&regs->maccfg2, tempval);
15958c2ecf20Sopenharmony_ci		gfar_write(&regs->ecntrl, ecntrl);
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		if (!priv->oldlink)
15988c2ecf20Sopenharmony_ci			priv->oldlink = 1;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	} else if (priv->oldlink) {
16018c2ecf20Sopenharmony_ci		priv->oldlink = 0;
16028c2ecf20Sopenharmony_ci		priv->oldspeed = 0;
16038c2ecf20Sopenharmony_ci		priv->oldduplex = -1;
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	if (netif_msg_link(priv))
16078c2ecf20Sopenharmony_ci		phy_print_status(phydev);
16088c2ecf20Sopenharmony_ci}
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci/* Called every time the controller might need to be made
16118c2ecf20Sopenharmony_ci * aware of new link state.  The PHY code conveys this
16128c2ecf20Sopenharmony_ci * information through variables in the phydev structure, and this
16138c2ecf20Sopenharmony_ci * function converts those variables into the appropriate
16148c2ecf20Sopenharmony_ci * register values, and can bring down the device if needed.
16158c2ecf20Sopenharmony_ci */
16168c2ecf20Sopenharmony_cistatic void adjust_link(struct net_device *dev)
16178c2ecf20Sopenharmony_ci{
16188c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
16198c2ecf20Sopenharmony_ci	struct phy_device *phydev = dev->phydev;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	if (unlikely(phydev->link != priv->oldlink ||
16228c2ecf20Sopenharmony_ci		     (phydev->link && (phydev->duplex != priv->oldduplex ||
16238c2ecf20Sopenharmony_ci				       phydev->speed != priv->oldspeed))))
16248c2ecf20Sopenharmony_ci		gfar_update_link_state(priv);
16258c2ecf20Sopenharmony_ci}
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci/* Initialize TBI PHY interface for communicating with the
16288c2ecf20Sopenharmony_ci * SERDES lynx PHY on the chip.  We communicate with this PHY
16298c2ecf20Sopenharmony_ci * through the MDIO bus on each controller, treating it as a
16308c2ecf20Sopenharmony_ci * "normal" PHY at the address found in the TBIPA register.  We assume
16318c2ecf20Sopenharmony_ci * that the TBIPA register is valid.  Either the MDIO bus code will set
16328c2ecf20Sopenharmony_ci * it to a value that doesn't conflict with other PHYs on the bus, or the
16338c2ecf20Sopenharmony_ci * value doesn't matter, as there are no other PHYs on the bus.
16348c2ecf20Sopenharmony_ci */
16358c2ecf20Sopenharmony_cistatic void gfar_configure_serdes(struct net_device *dev)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
16388c2ecf20Sopenharmony_ci	struct phy_device *tbiphy;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	if (!priv->tbi_node) {
16418c2ecf20Sopenharmony_ci		dev_warn(&dev->dev, "error: SGMII mode requires that the "
16428c2ecf20Sopenharmony_ci				    "device tree specify a tbi-handle\n");
16438c2ecf20Sopenharmony_ci		return;
16448c2ecf20Sopenharmony_ci	}
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	tbiphy = of_phy_find_device(priv->tbi_node);
16478c2ecf20Sopenharmony_ci	if (!tbiphy) {
16488c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "error: Could not get TBI device\n");
16498c2ecf20Sopenharmony_ci		return;
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	/* If the link is already up, we must already be ok, and don't need to
16538c2ecf20Sopenharmony_ci	 * configure and reset the TBI<->SerDes link.  Maybe U-Boot configured
16548c2ecf20Sopenharmony_ci	 * everything for us?  Resetting it takes the link down and requires
16558c2ecf20Sopenharmony_ci	 * several seconds for it to come back.
16568c2ecf20Sopenharmony_ci	 */
16578c2ecf20Sopenharmony_ci	if (phy_read(tbiphy, MII_BMSR) & BMSR_LSTATUS) {
16588c2ecf20Sopenharmony_ci		put_device(&tbiphy->mdio.dev);
16598c2ecf20Sopenharmony_ci		return;
16608c2ecf20Sopenharmony_ci	}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/* Single clk mode, mii mode off(for serdes communication) */
16638c2ecf20Sopenharmony_ci	phy_write(tbiphy, MII_TBICON, TBICON_CLK_SELECT);
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci	phy_write(tbiphy, MII_ADVERTISE,
16668c2ecf20Sopenharmony_ci		  ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
16678c2ecf20Sopenharmony_ci		  ADVERTISE_1000XPSE_ASYM);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	phy_write(tbiphy, MII_BMCR,
16708c2ecf20Sopenharmony_ci		  BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX |
16718c2ecf20Sopenharmony_ci		  BMCR_SPEED1000);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	put_device(&tbiphy->mdio.dev);
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci/* Initializes driver's PHY state, and attaches to the PHY.
16778c2ecf20Sopenharmony_ci * Returns 0 on success.
16788c2ecf20Sopenharmony_ci */
16798c2ecf20Sopenharmony_cistatic int init_phy(struct net_device *dev)
16808c2ecf20Sopenharmony_ci{
16818c2ecf20Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
16828c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
16838c2ecf20Sopenharmony_ci	phy_interface_t interface = priv->interface;
16848c2ecf20Sopenharmony_ci	struct phy_device *phydev;
16858c2ecf20Sopenharmony_ci	struct ethtool_eee edata;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	linkmode_set_bit_array(phy_10_100_features_array,
16888c2ecf20Sopenharmony_ci			       ARRAY_SIZE(phy_10_100_features_array),
16898c2ecf20Sopenharmony_ci			       mask);
16908c2ecf20Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mask);
16918c2ecf20Sopenharmony_ci	linkmode_set_bit(ETHTOOL_LINK_MODE_MII_BIT, mask);
16928c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
16938c2ecf20Sopenharmony_ci		linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, mask);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	priv->oldlink = 0;
16968c2ecf20Sopenharmony_ci	priv->oldspeed = 0;
16978c2ecf20Sopenharmony_ci	priv->oldduplex = -1;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	phydev = of_phy_connect(dev, priv->phy_node, &adjust_link, 0,
17008c2ecf20Sopenharmony_ci				interface);
17018c2ecf20Sopenharmony_ci	if (!phydev) {
17028c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "could not attach to PHY\n");
17038c2ecf20Sopenharmony_ci		return -ENODEV;
17048c2ecf20Sopenharmony_ci	}
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	if (interface == PHY_INTERFACE_MODE_SGMII)
17078c2ecf20Sopenharmony_ci		gfar_configure_serdes(dev);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	/* Remove any features not supported by the controller */
17108c2ecf20Sopenharmony_ci	linkmode_and(phydev->supported, phydev->supported, mask);
17118c2ecf20Sopenharmony_ci	linkmode_copy(phydev->advertising, phydev->supported);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	/* Add support for flow control */
17148c2ecf20Sopenharmony_ci	phy_support_asym_pause(phydev);
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	/* disable EEE autoneg, EEE not supported by eTSEC */
17178c2ecf20Sopenharmony_ci	memset(&edata, 0, sizeof(struct ethtool_eee));
17188c2ecf20Sopenharmony_ci	phy_ethtool_set_eee(phydev, &edata);
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	return 0;
17218c2ecf20Sopenharmony_ci}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_cistatic inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
17248c2ecf20Sopenharmony_ci{
17258c2ecf20Sopenharmony_ci	struct txfcb *fcb = skb_push(skb, GMAC_FCB_LEN);
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	memset(fcb, 0, GMAC_FCB_LEN);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	return fcb;
17308c2ecf20Sopenharmony_ci}
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_cistatic inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
17338c2ecf20Sopenharmony_ci				    int fcb_length)
17348c2ecf20Sopenharmony_ci{
17358c2ecf20Sopenharmony_ci	/* If we're here, it's a IP packet with a TCP or UDP
17368c2ecf20Sopenharmony_ci	 * payload.  We set it to checksum, using a pseudo-header
17378c2ecf20Sopenharmony_ci	 * we provide
17388c2ecf20Sopenharmony_ci	 */
17398c2ecf20Sopenharmony_ci	u8 flags = TXFCB_DEFAULT;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	/* Tell the controller what the protocol is
17428c2ecf20Sopenharmony_ci	 * And provide the already calculated phcs
17438c2ecf20Sopenharmony_ci	 */
17448c2ecf20Sopenharmony_ci	if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
17458c2ecf20Sopenharmony_ci		flags |= TXFCB_UDP;
17468c2ecf20Sopenharmony_ci		fcb->phcs = (__force __be16)(udp_hdr(skb)->check);
17478c2ecf20Sopenharmony_ci	} else
17488c2ecf20Sopenharmony_ci		fcb->phcs = (__force __be16)(tcp_hdr(skb)->check);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	/* l3os is the distance between the start of the
17518c2ecf20Sopenharmony_ci	 * frame (skb->data) and the start of the IP hdr.
17528c2ecf20Sopenharmony_ci	 * l4os is the distance between the start of the
17538c2ecf20Sopenharmony_ci	 * l3 hdr and the l4 hdr
17548c2ecf20Sopenharmony_ci	 */
17558c2ecf20Sopenharmony_ci	fcb->l3os = (u8)(skb_network_offset(skb) - fcb_length);
17568c2ecf20Sopenharmony_ci	fcb->l4os = skb_network_header_len(skb);
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	fcb->flags = flags;
17598c2ecf20Sopenharmony_ci}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_cistatic inline void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
17628c2ecf20Sopenharmony_ci{
17638c2ecf20Sopenharmony_ci	fcb->flags |= TXFCB_VLN;
17648c2ecf20Sopenharmony_ci	fcb->vlctl = cpu_to_be16(skb_vlan_tag_get(skb));
17658c2ecf20Sopenharmony_ci}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_cistatic inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride,
17688c2ecf20Sopenharmony_ci				      struct txbd8 *base, int ring_size)
17698c2ecf20Sopenharmony_ci{
17708c2ecf20Sopenharmony_ci	struct txbd8 *new_bd = bdp + stride;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd;
17738c2ecf20Sopenharmony_ci}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_cistatic inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base,
17768c2ecf20Sopenharmony_ci				      int ring_size)
17778c2ecf20Sopenharmony_ci{
17788c2ecf20Sopenharmony_ci	return skip_txbd(bdp, 1, base, ring_size);
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci/* eTSEC12: csum generation not supported for some fcb offsets */
17828c2ecf20Sopenharmony_cistatic inline bool gfar_csum_errata_12(struct gfar_private *priv,
17838c2ecf20Sopenharmony_ci				       unsigned long fcb_addr)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	return (gfar_has_errata(priv, GFAR_ERRATA_12) &&
17868c2ecf20Sopenharmony_ci	       (fcb_addr % 0x20) > 0x18);
17878c2ecf20Sopenharmony_ci}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci/* eTSEC76: csum generation for frames larger than 2500 may
17908c2ecf20Sopenharmony_ci * cause excess delays before start of transmission
17918c2ecf20Sopenharmony_ci */
17928c2ecf20Sopenharmony_cistatic inline bool gfar_csum_errata_76(struct gfar_private *priv,
17938c2ecf20Sopenharmony_ci				       unsigned int len)
17948c2ecf20Sopenharmony_ci{
17958c2ecf20Sopenharmony_ci	return (gfar_has_errata(priv, GFAR_ERRATA_76) &&
17968c2ecf20Sopenharmony_ci	       (len > 2500));
17978c2ecf20Sopenharmony_ci}
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci/* This is called by the kernel when a frame is ready for transmission.
18008c2ecf20Sopenharmony_ci * It is pointed to by the dev->hard_start_xmit function pointer
18018c2ecf20Sopenharmony_ci */
18028c2ecf20Sopenharmony_cistatic netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
18038c2ecf20Sopenharmony_ci{
18048c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
18058c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = NULL;
18068c2ecf20Sopenharmony_ci	struct netdev_queue *txq;
18078c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = NULL;
18088c2ecf20Sopenharmony_ci	struct txfcb *fcb = NULL;
18098c2ecf20Sopenharmony_ci	struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL;
18108c2ecf20Sopenharmony_ci	u32 lstatus;
18118c2ecf20Sopenharmony_ci	skb_frag_t *frag;
18128c2ecf20Sopenharmony_ci	int i, rq = 0;
18138c2ecf20Sopenharmony_ci	int do_tstamp, do_csum, do_vlan;
18148c2ecf20Sopenharmony_ci	u32 bufaddr;
18158c2ecf20Sopenharmony_ci	unsigned int nr_frags, nr_txbds, bytes_sent, fcb_len = 0;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	rq = skb->queue_mapping;
18188c2ecf20Sopenharmony_ci	tx_queue = priv->tx_queue[rq];
18198c2ecf20Sopenharmony_ci	txq = netdev_get_tx_queue(dev, rq);
18208c2ecf20Sopenharmony_ci	base = tx_queue->tx_bd_base;
18218c2ecf20Sopenharmony_ci	regs = tx_queue->grp->regs;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	do_csum = (CHECKSUM_PARTIAL == skb->ip_summed);
18248c2ecf20Sopenharmony_ci	do_vlan = skb_vlan_tag_present(skb);
18258c2ecf20Sopenharmony_ci	do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
18268c2ecf20Sopenharmony_ci		    priv->hwts_tx_en;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	if (do_csum || do_vlan)
18298c2ecf20Sopenharmony_ci		fcb_len = GMAC_FCB_LEN;
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	/* check if time stamp should be generated */
18328c2ecf20Sopenharmony_ci	if (unlikely(do_tstamp))
18338c2ecf20Sopenharmony_ci		fcb_len = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	/* make space for additional header when fcb is needed */
18368c2ecf20Sopenharmony_ci	if (fcb_len) {
18378c2ecf20Sopenharmony_ci		if (unlikely(skb_cow_head(skb, fcb_len))) {
18388c2ecf20Sopenharmony_ci			dev->stats.tx_errors++;
18398c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
18408c2ecf20Sopenharmony_ci			return NETDEV_TX_OK;
18418c2ecf20Sopenharmony_ci		}
18428c2ecf20Sopenharmony_ci	}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	/* total number of fragments in the SKB */
18458c2ecf20Sopenharmony_ci	nr_frags = skb_shinfo(skb)->nr_frags;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* calculate the required number of TxBDs for this skb */
18488c2ecf20Sopenharmony_ci	if (unlikely(do_tstamp))
18498c2ecf20Sopenharmony_ci		nr_txbds = nr_frags + 2;
18508c2ecf20Sopenharmony_ci	else
18518c2ecf20Sopenharmony_ci		nr_txbds = nr_frags + 1;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	/* check if there is space to queue this packet */
18548c2ecf20Sopenharmony_ci	if (nr_txbds > tx_queue->num_txbdfree) {
18558c2ecf20Sopenharmony_ci		/* no space, stop the queue */
18568c2ecf20Sopenharmony_ci		netif_tx_stop_queue(txq);
18578c2ecf20Sopenharmony_ci		dev->stats.tx_fifo_errors++;
18588c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	/* Update transmit stats */
18628c2ecf20Sopenharmony_ci	bytes_sent = skb->len;
18638c2ecf20Sopenharmony_ci	tx_queue->stats.tx_bytes += bytes_sent;
18648c2ecf20Sopenharmony_ci	/* keep Tx bytes on wire for BQL accounting */
18658c2ecf20Sopenharmony_ci	GFAR_CB(skb)->bytes_sent = bytes_sent;
18668c2ecf20Sopenharmony_ci	tx_queue->stats.tx_packets++;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	txbdp = txbdp_start = tx_queue->cur_tx;
18698c2ecf20Sopenharmony_ci	lstatus = be32_to_cpu(txbdp->lstatus);
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	/* Add TxPAL between FCB and frame if required */
18728c2ecf20Sopenharmony_ci	if (unlikely(do_tstamp)) {
18738c2ecf20Sopenharmony_ci		skb_push(skb, GMAC_TXPAL_LEN);
18748c2ecf20Sopenharmony_ci		memset(skb->data, 0, GMAC_TXPAL_LEN);
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	/* Add TxFCB if required */
18788c2ecf20Sopenharmony_ci	if (fcb_len) {
18798c2ecf20Sopenharmony_ci		fcb = gfar_add_fcb(skb);
18808c2ecf20Sopenharmony_ci		lstatus |= BD_LFLAG(TXBD_TOE);
18818c2ecf20Sopenharmony_ci	}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	/* Set up checksumming */
18848c2ecf20Sopenharmony_ci	if (do_csum) {
18858c2ecf20Sopenharmony_ci		gfar_tx_checksum(skb, fcb, fcb_len);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci		if (unlikely(gfar_csum_errata_12(priv, (unsigned long)fcb)) ||
18888c2ecf20Sopenharmony_ci		    unlikely(gfar_csum_errata_76(priv, skb->len))) {
18898c2ecf20Sopenharmony_ci			__skb_pull(skb, GMAC_FCB_LEN);
18908c2ecf20Sopenharmony_ci			skb_checksum_help(skb);
18918c2ecf20Sopenharmony_ci			if (do_vlan || do_tstamp) {
18928c2ecf20Sopenharmony_ci				/* put back a new fcb for vlan/tstamp TOE */
18938c2ecf20Sopenharmony_ci				fcb = gfar_add_fcb(skb);
18948c2ecf20Sopenharmony_ci			} else {
18958c2ecf20Sopenharmony_ci				/* Tx TOE not used */
18968c2ecf20Sopenharmony_ci				lstatus &= ~(BD_LFLAG(TXBD_TOE));
18978c2ecf20Sopenharmony_ci				fcb = NULL;
18988c2ecf20Sopenharmony_ci			}
18998c2ecf20Sopenharmony_ci		}
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	if (do_vlan)
19038c2ecf20Sopenharmony_ci		gfar_tx_vlan(skb, fcb);
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	bufaddr = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
19068c2ecf20Sopenharmony_ci				 DMA_TO_DEVICE);
19078c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
19088c2ecf20Sopenharmony_ci		goto dma_map_err;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	txbdp_start->bufPtr = cpu_to_be32(bufaddr);
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	/* Time stamp insertion requires one additional TxBD */
19138c2ecf20Sopenharmony_ci	if (unlikely(do_tstamp))
19148c2ecf20Sopenharmony_ci		txbdp_tstamp = txbdp = next_txbd(txbdp, base,
19158c2ecf20Sopenharmony_ci						 tx_queue->tx_ring_size);
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	if (likely(!nr_frags)) {
19188c2ecf20Sopenharmony_ci		if (likely(!do_tstamp))
19198c2ecf20Sopenharmony_ci			lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
19208c2ecf20Sopenharmony_ci	} else {
19218c2ecf20Sopenharmony_ci		u32 lstatus_start = lstatus;
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_ci		/* Place the fragment addresses and lengths into the TxBDs */
19248c2ecf20Sopenharmony_ci		frag = &skb_shinfo(skb)->frags[0];
19258c2ecf20Sopenharmony_ci		for (i = 0; i < nr_frags; i++, frag++) {
19268c2ecf20Sopenharmony_ci			unsigned int size;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci			/* Point at the next BD, wrapping as needed */
19298c2ecf20Sopenharmony_ci			txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci			size = skb_frag_size(frag);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci			lstatus = be32_to_cpu(txbdp->lstatus) | size |
19348c2ecf20Sopenharmony_ci				  BD_LFLAG(TXBD_READY);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci			/* Handle the last BD specially */
19378c2ecf20Sopenharmony_ci			if (i == nr_frags - 1)
19388c2ecf20Sopenharmony_ci				lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci			bufaddr = skb_frag_dma_map(priv->dev, frag, 0,
19418c2ecf20Sopenharmony_ci						   size, DMA_TO_DEVICE);
19428c2ecf20Sopenharmony_ci			if (unlikely(dma_mapping_error(priv->dev, bufaddr)))
19438c2ecf20Sopenharmony_ci				goto dma_map_err;
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci			/* set the TxBD length and buffer pointer */
19468c2ecf20Sopenharmony_ci			txbdp->bufPtr = cpu_to_be32(bufaddr);
19478c2ecf20Sopenharmony_ci			txbdp->lstatus = cpu_to_be32(lstatus);
19488c2ecf20Sopenharmony_ci		}
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci		lstatus = lstatus_start;
19518c2ecf20Sopenharmony_ci	}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	/* If time stamping is requested one additional TxBD must be set up. The
19548c2ecf20Sopenharmony_ci	 * first TxBD points to the FCB and must have a data length of
19558c2ecf20Sopenharmony_ci	 * GMAC_FCB_LEN. The second TxBD points to the actual frame data with
19568c2ecf20Sopenharmony_ci	 * the full frame length.
19578c2ecf20Sopenharmony_ci	 */
19588c2ecf20Sopenharmony_ci	if (unlikely(do_tstamp)) {
19598c2ecf20Sopenharmony_ci		u32 lstatus_ts = be32_to_cpu(txbdp_tstamp->lstatus);
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci		bufaddr = be32_to_cpu(txbdp_start->bufPtr);
19628c2ecf20Sopenharmony_ci		bufaddr += fcb_len;
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci		lstatus_ts |= BD_LFLAG(TXBD_READY) |
19658c2ecf20Sopenharmony_ci			      (skb_headlen(skb) - fcb_len);
19668c2ecf20Sopenharmony_ci		if (!nr_frags)
19678c2ecf20Sopenharmony_ci			lstatus_ts |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci		txbdp_tstamp->bufPtr = cpu_to_be32(bufaddr);
19708c2ecf20Sopenharmony_ci		txbdp_tstamp->lstatus = cpu_to_be32(lstatus_ts);
19718c2ecf20Sopenharmony_ci		lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci		/* Setup tx hardware time stamping */
19748c2ecf20Sopenharmony_ci		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
19758c2ecf20Sopenharmony_ci		fcb->ptp = 1;
19768c2ecf20Sopenharmony_ci	} else {
19778c2ecf20Sopenharmony_ci		lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
19788c2ecf20Sopenharmony_ci	}
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	netdev_tx_sent_queue(txq, bytes_sent);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	gfar_wmb();
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	txbdp_start->lstatus = cpu_to_be32(lstatus);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	gfar_wmb(); /* force lstatus write before tx_skbuff */
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	tx_queue->tx_skbuff[tx_queue->skb_curtx] = skb;
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci	/* Update the current skb pointer to the next entry we will use
19918c2ecf20Sopenharmony_ci	 * (wrapping if necessary)
19928c2ecf20Sopenharmony_ci	 */
19938c2ecf20Sopenharmony_ci	tx_queue->skb_curtx = (tx_queue->skb_curtx + 1) &
19948c2ecf20Sopenharmony_ci			      TX_RING_MOD_MASK(tx_queue->tx_ring_size);
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	/* We can work in parallel with gfar_clean_tx_ring(), except
19998c2ecf20Sopenharmony_ci	 * when modifying num_txbdfree. Note that we didn't grab the lock
20008c2ecf20Sopenharmony_ci	 * when we were reading the num_txbdfree and checking for available
20018c2ecf20Sopenharmony_ci	 * space, that's because outside of this function it can only grow.
20028c2ecf20Sopenharmony_ci	 */
20038c2ecf20Sopenharmony_ci	spin_lock_bh(&tx_queue->txlock);
20048c2ecf20Sopenharmony_ci	/* reduce TxBD free count */
20058c2ecf20Sopenharmony_ci	tx_queue->num_txbdfree -= (nr_txbds);
20068c2ecf20Sopenharmony_ci	spin_unlock_bh(&tx_queue->txlock);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	/* If the next BD still needs to be cleaned up, then the bds
20098c2ecf20Sopenharmony_ci	 * are full.  We need to tell the kernel to stop sending us stuff.
20108c2ecf20Sopenharmony_ci	 */
20118c2ecf20Sopenharmony_ci	if (!tx_queue->num_txbdfree) {
20128c2ecf20Sopenharmony_ci		netif_tx_stop_queue(txq);
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci		dev->stats.tx_fifo_errors++;
20158c2ecf20Sopenharmony_ci	}
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	/* Tell the DMA to go go go */
20188c2ecf20Sopenharmony_ci	gfar_write(&regs->tstat, TSTAT_CLEAR_THALT >> tx_queue->qindex);
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cidma_map_err:
20238c2ecf20Sopenharmony_ci	txbdp = next_txbd(txbdp_start, base, tx_queue->tx_ring_size);
20248c2ecf20Sopenharmony_ci	if (do_tstamp)
20258c2ecf20Sopenharmony_ci		txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
20268c2ecf20Sopenharmony_ci	for (i = 0; i < nr_frags; i++) {
20278c2ecf20Sopenharmony_ci		lstatus = be32_to_cpu(txbdp->lstatus);
20288c2ecf20Sopenharmony_ci		if (!(lstatus & BD_LFLAG(TXBD_READY)))
20298c2ecf20Sopenharmony_ci			break;
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci		lstatus &= ~BD_LFLAG(TXBD_READY);
20328c2ecf20Sopenharmony_ci		txbdp->lstatus = cpu_to_be32(lstatus);
20338c2ecf20Sopenharmony_ci		bufaddr = be32_to_cpu(txbdp->bufPtr);
20348c2ecf20Sopenharmony_ci		dma_unmap_page(priv->dev, bufaddr, be16_to_cpu(txbdp->length),
20358c2ecf20Sopenharmony_ci			       DMA_TO_DEVICE);
20368c2ecf20Sopenharmony_ci		txbdp = next_txbd(txbdp, base, tx_queue->tx_ring_size);
20378c2ecf20Sopenharmony_ci	}
20388c2ecf20Sopenharmony_ci	gfar_wmb();
20398c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
20408c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
20418c2ecf20Sopenharmony_ci}
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci/* Changes the mac address if the controller is not running. */
20448c2ecf20Sopenharmony_cistatic int gfar_set_mac_address(struct net_device *dev)
20458c2ecf20Sopenharmony_ci{
20468c2ecf20Sopenharmony_ci	gfar_set_mac_for_addr(dev, 0, dev->dev_addr);
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	return 0;
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic int gfar_change_mtu(struct net_device *dev, int new_mtu)
20528c2ecf20Sopenharmony_ci{
20538c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
20568c2ecf20Sopenharmony_ci		cpu_relax();
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	if (dev->flags & IFF_UP)
20598c2ecf20Sopenharmony_ci		stop_gfar(dev);
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	dev->mtu = new_mtu;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	if (dev->flags & IFF_UP)
20648c2ecf20Sopenharmony_ci		startup_gfar(dev);
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	clear_bit_unlock(GFAR_RESETTING, &priv->state);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	return 0;
20698c2ecf20Sopenharmony_ci}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_cistatic void reset_gfar(struct net_device *ndev)
20728c2ecf20Sopenharmony_ci{
20738c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
20768c2ecf20Sopenharmony_ci		cpu_relax();
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci	stop_gfar(ndev);
20798c2ecf20Sopenharmony_ci	startup_gfar(ndev);
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	clear_bit_unlock(GFAR_RESETTING, &priv->state);
20828c2ecf20Sopenharmony_ci}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci/* gfar_reset_task gets scheduled when a packet has not been
20858c2ecf20Sopenharmony_ci * transmitted after a set amount of time.
20868c2ecf20Sopenharmony_ci * For now, assume that clearing out all the structures, and
20878c2ecf20Sopenharmony_ci * starting over will fix the problem.
20888c2ecf20Sopenharmony_ci */
20898c2ecf20Sopenharmony_cistatic void gfar_reset_task(struct work_struct *work)
20908c2ecf20Sopenharmony_ci{
20918c2ecf20Sopenharmony_ci	struct gfar_private *priv = container_of(work, struct gfar_private,
20928c2ecf20Sopenharmony_ci						 reset_task);
20938c2ecf20Sopenharmony_ci	reset_gfar(priv->ndev);
20948c2ecf20Sopenharmony_ci}
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_cistatic void gfar_timeout(struct net_device *dev, unsigned int txqueue)
20978c2ecf20Sopenharmony_ci{
20988c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	dev->stats.tx_errors++;
21018c2ecf20Sopenharmony_ci	schedule_work(&priv->reset_task);
21028c2ecf20Sopenharmony_ci}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_cistatic int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
21058c2ecf20Sopenharmony_ci{
21068c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
21078c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(netdev);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
21108c2ecf20Sopenharmony_ci		return -EFAULT;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	/* reserved for future extensions */
21138c2ecf20Sopenharmony_ci	if (config.flags)
21148c2ecf20Sopenharmony_ci		return -EINVAL;
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_ci	switch (config.tx_type) {
21178c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_OFF:
21188c2ecf20Sopenharmony_ci		priv->hwts_tx_en = 0;
21198c2ecf20Sopenharmony_ci		break;
21208c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_ON:
21218c2ecf20Sopenharmony_ci		if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
21228c2ecf20Sopenharmony_ci			return -ERANGE;
21238c2ecf20Sopenharmony_ci		priv->hwts_tx_en = 1;
21248c2ecf20Sopenharmony_ci		break;
21258c2ecf20Sopenharmony_ci	default:
21268c2ecf20Sopenharmony_ci		return -ERANGE;
21278c2ecf20Sopenharmony_ci	}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	switch (config.rx_filter) {
21308c2ecf20Sopenharmony_ci	case HWTSTAMP_FILTER_NONE:
21318c2ecf20Sopenharmony_ci		if (priv->hwts_rx_en) {
21328c2ecf20Sopenharmony_ci			priv->hwts_rx_en = 0;
21338c2ecf20Sopenharmony_ci			reset_gfar(netdev);
21348c2ecf20Sopenharmony_ci		}
21358c2ecf20Sopenharmony_ci		break;
21368c2ecf20Sopenharmony_ci	default:
21378c2ecf20Sopenharmony_ci		if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
21388c2ecf20Sopenharmony_ci			return -ERANGE;
21398c2ecf20Sopenharmony_ci		if (!priv->hwts_rx_en) {
21408c2ecf20Sopenharmony_ci			priv->hwts_rx_en = 1;
21418c2ecf20Sopenharmony_ci			reset_gfar(netdev);
21428c2ecf20Sopenharmony_ci		}
21438c2ecf20Sopenharmony_ci		config.rx_filter = HWTSTAMP_FILTER_ALL;
21448c2ecf20Sopenharmony_ci		break;
21458c2ecf20Sopenharmony_ci	}
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
21488c2ecf20Sopenharmony_ci		-EFAULT : 0;
21498c2ecf20Sopenharmony_ci}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_cistatic int gfar_hwtstamp_get(struct net_device *netdev, struct ifreq *ifr)
21528c2ecf20Sopenharmony_ci{
21538c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
21548c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(netdev);
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	config.flags = 0;
21578c2ecf20Sopenharmony_ci	config.tx_type = priv->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
21588c2ecf20Sopenharmony_ci	config.rx_filter = (priv->hwts_rx_en ?
21598c2ecf20Sopenharmony_ci			    HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
21628c2ecf20Sopenharmony_ci		-EFAULT : 0;
21638c2ecf20Sopenharmony_ci}
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_cistatic int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
21668c2ecf20Sopenharmony_ci{
21678c2ecf20Sopenharmony_ci	struct phy_device *phydev = dev->phydev;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	if (!netif_running(dev))
21708c2ecf20Sopenharmony_ci		return -EINVAL;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	if (cmd == SIOCSHWTSTAMP)
21738c2ecf20Sopenharmony_ci		return gfar_hwtstamp_set(dev, rq);
21748c2ecf20Sopenharmony_ci	if (cmd == SIOCGHWTSTAMP)
21758c2ecf20Sopenharmony_ci		return gfar_hwtstamp_get(dev, rq);
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	if (!phydev)
21788c2ecf20Sopenharmony_ci		return -ENODEV;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	return phy_mii_ioctl(phydev, rq, cmd);
21818c2ecf20Sopenharmony_ci}
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci/* Interrupt Handler for Transmit complete */
21848c2ecf20Sopenharmony_cistatic void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
21858c2ecf20Sopenharmony_ci{
21868c2ecf20Sopenharmony_ci	struct net_device *dev = tx_queue->dev;
21878c2ecf20Sopenharmony_ci	struct netdev_queue *txq;
21888c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
21898c2ecf20Sopenharmony_ci	struct txbd8 *bdp, *next = NULL;
21908c2ecf20Sopenharmony_ci	struct txbd8 *lbdp = NULL;
21918c2ecf20Sopenharmony_ci	struct txbd8 *base = tx_queue->tx_bd_base;
21928c2ecf20Sopenharmony_ci	struct sk_buff *skb;
21938c2ecf20Sopenharmony_ci	int skb_dirtytx;
21948c2ecf20Sopenharmony_ci	int tx_ring_size = tx_queue->tx_ring_size;
21958c2ecf20Sopenharmony_ci	int frags = 0, nr_txbds = 0;
21968c2ecf20Sopenharmony_ci	int i;
21978c2ecf20Sopenharmony_ci	int howmany = 0;
21988c2ecf20Sopenharmony_ci	int tqi = tx_queue->qindex;
21998c2ecf20Sopenharmony_ci	unsigned int bytes_sent = 0;
22008c2ecf20Sopenharmony_ci	u32 lstatus;
22018c2ecf20Sopenharmony_ci	size_t buflen;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	txq = netdev_get_tx_queue(dev, tqi);
22048c2ecf20Sopenharmony_ci	bdp = tx_queue->dirty_tx;
22058c2ecf20Sopenharmony_ci	skb_dirtytx = tx_queue->skb_dirtytx;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	while ((skb = tx_queue->tx_skbuff[skb_dirtytx])) {
22088c2ecf20Sopenharmony_ci		bool do_tstamp;
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci		do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
22118c2ecf20Sopenharmony_ci			    priv->hwts_tx_en;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		frags = skb_shinfo(skb)->nr_frags;
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		/* When time stamping, one additional TxBD must be freed.
22168c2ecf20Sopenharmony_ci		 * Also, we need to dma_unmap_single() the TxPAL.
22178c2ecf20Sopenharmony_ci		 */
22188c2ecf20Sopenharmony_ci		if (unlikely(do_tstamp))
22198c2ecf20Sopenharmony_ci			nr_txbds = frags + 2;
22208c2ecf20Sopenharmony_ci		else
22218c2ecf20Sopenharmony_ci			nr_txbds = frags + 1;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci		lbdp = skip_txbd(bdp, nr_txbds - 1, base, tx_ring_size);
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci		lstatus = be32_to_cpu(lbdp->lstatus);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci		/* Only clean completed frames */
22288c2ecf20Sopenharmony_ci		if ((lstatus & BD_LFLAG(TXBD_READY)) &&
22298c2ecf20Sopenharmony_ci		    (lstatus & BD_LENGTH_MASK))
22308c2ecf20Sopenharmony_ci			break;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci		if (unlikely(do_tstamp)) {
22338c2ecf20Sopenharmony_ci			next = next_txbd(bdp, base, tx_ring_size);
22348c2ecf20Sopenharmony_ci			buflen = be16_to_cpu(next->length) +
22358c2ecf20Sopenharmony_ci				 GMAC_FCB_LEN + GMAC_TXPAL_LEN;
22368c2ecf20Sopenharmony_ci		} else
22378c2ecf20Sopenharmony_ci			buflen = be16_to_cpu(bdp->length);
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci		dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr),
22408c2ecf20Sopenharmony_ci				 buflen, DMA_TO_DEVICE);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci		if (unlikely(do_tstamp)) {
22438c2ecf20Sopenharmony_ci			struct skb_shared_hwtstamps shhwtstamps;
22448c2ecf20Sopenharmony_ci			u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) &
22458c2ecf20Sopenharmony_ci					  ~0x7UL);
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
22488c2ecf20Sopenharmony_ci			shhwtstamps.hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
22498c2ecf20Sopenharmony_ci			skb_pull(skb, GMAC_FCB_LEN + GMAC_TXPAL_LEN);
22508c2ecf20Sopenharmony_ci			skb_tstamp_tx(skb, &shhwtstamps);
22518c2ecf20Sopenharmony_ci			gfar_clear_txbd_status(bdp);
22528c2ecf20Sopenharmony_ci			bdp = next;
22538c2ecf20Sopenharmony_ci		}
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci		gfar_clear_txbd_status(bdp);
22568c2ecf20Sopenharmony_ci		bdp = next_txbd(bdp, base, tx_ring_size);
22578c2ecf20Sopenharmony_ci
22588c2ecf20Sopenharmony_ci		for (i = 0; i < frags; i++) {
22598c2ecf20Sopenharmony_ci			dma_unmap_page(priv->dev, be32_to_cpu(bdp->bufPtr),
22608c2ecf20Sopenharmony_ci				       be16_to_cpu(bdp->length),
22618c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
22628c2ecf20Sopenharmony_ci			gfar_clear_txbd_status(bdp);
22638c2ecf20Sopenharmony_ci			bdp = next_txbd(bdp, base, tx_ring_size);
22648c2ecf20Sopenharmony_ci		}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci		bytes_sent += GFAR_CB(skb)->bytes_sent;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci		tx_queue->tx_skbuff[skb_dirtytx] = NULL;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci		skb_dirtytx = (skb_dirtytx + 1) &
22738c2ecf20Sopenharmony_ci			      TX_RING_MOD_MASK(tx_ring_size);
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci		howmany++;
22768c2ecf20Sopenharmony_ci		spin_lock(&tx_queue->txlock);
22778c2ecf20Sopenharmony_ci		tx_queue->num_txbdfree += nr_txbds;
22788c2ecf20Sopenharmony_ci		spin_unlock(&tx_queue->txlock);
22798c2ecf20Sopenharmony_ci	}
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	/* If we freed a buffer, we can restart transmission, if necessary */
22828c2ecf20Sopenharmony_ci	if (tx_queue->num_txbdfree &&
22838c2ecf20Sopenharmony_ci	    netif_tx_queue_stopped(txq) &&
22848c2ecf20Sopenharmony_ci	    !(test_bit(GFAR_DOWN, &priv->state)))
22858c2ecf20Sopenharmony_ci		netif_wake_subqueue(priv->ndev, tqi);
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	/* Update dirty indicators */
22888c2ecf20Sopenharmony_ci	tx_queue->skb_dirtytx = skb_dirtytx;
22898c2ecf20Sopenharmony_ci	tx_queue->dirty_tx = bdp;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci	netdev_tx_completed_queue(txq, howmany, bytes_sent);
22928c2ecf20Sopenharmony_ci}
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_cistatic void count_errors(u32 lstatus, struct net_device *ndev)
22958c2ecf20Sopenharmony_ci{
22968c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
22978c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
22988c2ecf20Sopenharmony_ci	struct gfar_extra_stats *estats = &priv->extra_stats;
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	/* If the packet was truncated, none of the other errors matter */
23018c2ecf20Sopenharmony_ci	if (lstatus & BD_LFLAG(RXBD_TRUNCATED)) {
23028c2ecf20Sopenharmony_ci		stats->rx_length_errors++;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci		atomic64_inc(&estats->rx_trunc);
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci		return;
23078c2ecf20Sopenharmony_ci	}
23088c2ecf20Sopenharmony_ci	/* Count the errors, if there were any */
23098c2ecf20Sopenharmony_ci	if (lstatus & BD_LFLAG(RXBD_LARGE | RXBD_SHORT)) {
23108c2ecf20Sopenharmony_ci		stats->rx_length_errors++;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci		if (lstatus & BD_LFLAG(RXBD_LARGE))
23138c2ecf20Sopenharmony_ci			atomic64_inc(&estats->rx_large);
23148c2ecf20Sopenharmony_ci		else
23158c2ecf20Sopenharmony_ci			atomic64_inc(&estats->rx_short);
23168c2ecf20Sopenharmony_ci	}
23178c2ecf20Sopenharmony_ci	if (lstatus & BD_LFLAG(RXBD_NONOCTET)) {
23188c2ecf20Sopenharmony_ci		stats->rx_frame_errors++;
23198c2ecf20Sopenharmony_ci		atomic64_inc(&estats->rx_nonoctet);
23208c2ecf20Sopenharmony_ci	}
23218c2ecf20Sopenharmony_ci	if (lstatus & BD_LFLAG(RXBD_CRCERR)) {
23228c2ecf20Sopenharmony_ci		atomic64_inc(&estats->rx_crcerr);
23238c2ecf20Sopenharmony_ci		stats->rx_crc_errors++;
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci	if (lstatus & BD_LFLAG(RXBD_OVERRUN)) {
23268c2ecf20Sopenharmony_ci		atomic64_inc(&estats->rx_overrun);
23278c2ecf20Sopenharmony_ci		stats->rx_over_errors++;
23288c2ecf20Sopenharmony_ci	}
23298c2ecf20Sopenharmony_ci}
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_cistatic irqreturn_t gfar_receive(int irq, void *grp_id)
23328c2ecf20Sopenharmony_ci{
23338c2ecf20Sopenharmony_ci	struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
23348c2ecf20Sopenharmony_ci	unsigned long flags;
23358c2ecf20Sopenharmony_ci	u32 imask, ievent;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	ievent = gfar_read(&grp->regs->ievent);
23388c2ecf20Sopenharmony_ci
23398c2ecf20Sopenharmony_ci	if (unlikely(ievent & IEVENT_FGPI)) {
23408c2ecf20Sopenharmony_ci		gfar_write(&grp->regs->ievent, IEVENT_FGPI);
23418c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	if (likely(napi_schedule_prep(&grp->napi_rx))) {
23458c2ecf20Sopenharmony_ci		spin_lock_irqsave(&grp->grplock, flags);
23468c2ecf20Sopenharmony_ci		imask = gfar_read(&grp->regs->imask);
23478c2ecf20Sopenharmony_ci		imask &= IMASK_RX_DISABLED;
23488c2ecf20Sopenharmony_ci		gfar_write(&grp->regs->imask, imask);
23498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&grp->grplock, flags);
23508c2ecf20Sopenharmony_ci		__napi_schedule(&grp->napi_rx);
23518c2ecf20Sopenharmony_ci	} else {
23528c2ecf20Sopenharmony_ci		/* Clear IEVENT, so interrupts aren't called again
23538c2ecf20Sopenharmony_ci		 * because of the packets that have already arrived.
23548c2ecf20Sopenharmony_ci		 */
23558c2ecf20Sopenharmony_ci		gfar_write(&grp->regs->ievent, IEVENT_RX_MASK);
23568c2ecf20Sopenharmony_ci	}
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci/* Interrupt Handler for Transmit complete */
23628c2ecf20Sopenharmony_cistatic irqreturn_t gfar_transmit(int irq, void *grp_id)
23638c2ecf20Sopenharmony_ci{
23648c2ecf20Sopenharmony_ci	struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
23658c2ecf20Sopenharmony_ci	unsigned long flags;
23668c2ecf20Sopenharmony_ci	u32 imask;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	if (likely(napi_schedule_prep(&grp->napi_tx))) {
23698c2ecf20Sopenharmony_ci		spin_lock_irqsave(&grp->grplock, flags);
23708c2ecf20Sopenharmony_ci		imask = gfar_read(&grp->regs->imask);
23718c2ecf20Sopenharmony_ci		imask &= IMASK_TX_DISABLED;
23728c2ecf20Sopenharmony_ci		gfar_write(&grp->regs->imask, imask);
23738c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&grp->grplock, flags);
23748c2ecf20Sopenharmony_ci		__napi_schedule(&grp->napi_tx);
23758c2ecf20Sopenharmony_ci	} else {
23768c2ecf20Sopenharmony_ci		/* Clear IEVENT, so interrupts aren't called again
23778c2ecf20Sopenharmony_ci		 * because of the packets that have already arrived.
23788c2ecf20Sopenharmony_ci		 */
23798c2ecf20Sopenharmony_ci		gfar_write(&grp->regs->ievent, IEVENT_TX_MASK);
23808c2ecf20Sopenharmony_ci	}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
23838c2ecf20Sopenharmony_ci}
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_cistatic bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
23868c2ecf20Sopenharmony_ci			     struct sk_buff *skb, bool first)
23878c2ecf20Sopenharmony_ci{
23888c2ecf20Sopenharmony_ci	int size = lstatus & BD_LENGTH_MASK;
23898c2ecf20Sopenharmony_ci	struct page *page = rxb->page;
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	if (likely(first)) {
23928c2ecf20Sopenharmony_ci		skb_put(skb, size);
23938c2ecf20Sopenharmony_ci	} else {
23948c2ecf20Sopenharmony_ci		/* the last fragments' length contains the full frame length */
23958c2ecf20Sopenharmony_ci		if (lstatus & BD_LFLAG(RXBD_LAST))
23968c2ecf20Sopenharmony_ci			size -= skb->len;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci		WARN(size < 0, "gianfar: rx fragment size underflow");
23998c2ecf20Sopenharmony_ci		if (size < 0)
24008c2ecf20Sopenharmony_ci			return false;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci		skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
24038c2ecf20Sopenharmony_ci				rxb->page_offset + RXBUF_ALIGNMENT,
24048c2ecf20Sopenharmony_ci				size, GFAR_RXB_TRUESIZE);
24058c2ecf20Sopenharmony_ci	}
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	/* try reuse page */
24088c2ecf20Sopenharmony_ci	if (unlikely(page_count(page) != 1 || page_is_pfmemalloc(page)))
24098c2ecf20Sopenharmony_ci		return false;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	/* change offset to the other half */
24128c2ecf20Sopenharmony_ci	rxb->page_offset ^= GFAR_RXB_TRUESIZE;
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci	page_ref_inc(page);
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	return true;
24178c2ecf20Sopenharmony_ci}
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_cistatic void gfar_reuse_rx_page(struct gfar_priv_rx_q *rxq,
24208c2ecf20Sopenharmony_ci			       struct gfar_rx_buff *old_rxb)
24218c2ecf20Sopenharmony_ci{
24228c2ecf20Sopenharmony_ci	struct gfar_rx_buff *new_rxb;
24238c2ecf20Sopenharmony_ci	u16 nta = rxq->next_to_alloc;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	new_rxb = &rxq->rx_buff[nta];
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	/* find next buf that can reuse a page */
24288c2ecf20Sopenharmony_ci	nta++;
24298c2ecf20Sopenharmony_ci	rxq->next_to_alloc = (nta < rxq->rx_ring_size) ? nta : 0;
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	/* copy page reference */
24328c2ecf20Sopenharmony_ci	*new_rxb = *old_rxb;
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	/* sync for use by the device */
24358c2ecf20Sopenharmony_ci	dma_sync_single_range_for_device(rxq->dev, old_rxb->dma,
24368c2ecf20Sopenharmony_ci					 old_rxb->page_offset,
24378c2ecf20Sopenharmony_ci					 GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE);
24388c2ecf20Sopenharmony_ci}
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_cistatic struct sk_buff *gfar_get_next_rxbuff(struct gfar_priv_rx_q *rx_queue,
24418c2ecf20Sopenharmony_ci					    u32 lstatus, struct sk_buff *skb)
24428c2ecf20Sopenharmony_ci{
24438c2ecf20Sopenharmony_ci	struct gfar_rx_buff *rxb = &rx_queue->rx_buff[rx_queue->next_to_clean];
24448c2ecf20Sopenharmony_ci	struct page *page = rxb->page;
24458c2ecf20Sopenharmony_ci	bool first = false;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	if (likely(!skb)) {
24488c2ecf20Sopenharmony_ci		void *buff_addr = page_address(page) + rxb->page_offset;
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci		skb = build_skb(buff_addr, GFAR_SKBFRAG_SIZE);
24518c2ecf20Sopenharmony_ci		if (unlikely(!skb)) {
24528c2ecf20Sopenharmony_ci			gfar_rx_alloc_err(rx_queue);
24538c2ecf20Sopenharmony_ci			return NULL;
24548c2ecf20Sopenharmony_ci		}
24558c2ecf20Sopenharmony_ci		skb_reserve(skb, RXBUF_ALIGNMENT);
24568c2ecf20Sopenharmony_ci		first = true;
24578c2ecf20Sopenharmony_ci	}
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	dma_sync_single_range_for_cpu(rx_queue->dev, rxb->dma, rxb->page_offset,
24608c2ecf20Sopenharmony_ci				      GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE);
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	if (gfar_add_rx_frag(rxb, lstatus, skb, first)) {
24638c2ecf20Sopenharmony_ci		/* reuse the free half of the page */
24648c2ecf20Sopenharmony_ci		gfar_reuse_rx_page(rx_queue, rxb);
24658c2ecf20Sopenharmony_ci	} else {
24668c2ecf20Sopenharmony_ci		/* page cannot be reused, unmap it */
24678c2ecf20Sopenharmony_ci		dma_unmap_page(rx_queue->dev, rxb->dma,
24688c2ecf20Sopenharmony_ci			       PAGE_SIZE, DMA_FROM_DEVICE);
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	/* clear rxb content */
24728c2ecf20Sopenharmony_ci	rxb->page = NULL;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	return skb;
24758c2ecf20Sopenharmony_ci}
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_cistatic inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
24788c2ecf20Sopenharmony_ci{
24798c2ecf20Sopenharmony_ci	/* If valid headers were found, and valid sums
24808c2ecf20Sopenharmony_ci	 * were verified, then we tell the kernel that no
24818c2ecf20Sopenharmony_ci	 * checksumming is necessary.  Otherwise, it is [FIXME]
24828c2ecf20Sopenharmony_ci	 */
24838c2ecf20Sopenharmony_ci	if ((be16_to_cpu(fcb->flags) & RXFCB_CSUM_MASK) ==
24848c2ecf20Sopenharmony_ci	    (RXFCB_CIP | RXFCB_CTU))
24858c2ecf20Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
24868c2ecf20Sopenharmony_ci	else
24878c2ecf20Sopenharmony_ci		skb_checksum_none_assert(skb);
24888c2ecf20Sopenharmony_ci}
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci/* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */
24918c2ecf20Sopenharmony_cistatic void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
24928c2ecf20Sopenharmony_ci{
24938c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
24948c2ecf20Sopenharmony_ci	struct rxfcb *fcb = NULL;
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	/* fcb is at the beginning if exists */
24978c2ecf20Sopenharmony_ci	fcb = (struct rxfcb *)skb->data;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	/* Remove the FCB from the skb
25008c2ecf20Sopenharmony_ci	 * Remove the padded bytes, if there are any
25018c2ecf20Sopenharmony_ci	 */
25028c2ecf20Sopenharmony_ci	if (priv->uses_rxfcb)
25038c2ecf20Sopenharmony_ci		skb_pull(skb, GMAC_FCB_LEN);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	/* Get receive timestamp from the skb */
25068c2ecf20Sopenharmony_ci	if (priv->hwts_rx_en) {
25078c2ecf20Sopenharmony_ci		struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
25088c2ecf20Sopenharmony_ci		u64 *ns = (u64 *) skb->data;
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
25118c2ecf20Sopenharmony_ci		shhwtstamps->hwtstamp = ns_to_ktime(be64_to_cpu(*ns));
25128c2ecf20Sopenharmony_ci	}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci	if (priv->padding)
25158c2ecf20Sopenharmony_ci		skb_pull(skb, priv->padding);
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci	/* Trim off the FCS */
25188c2ecf20Sopenharmony_ci	pskb_trim(skb, skb->len - ETH_FCS_LEN);
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	if (ndev->features & NETIF_F_RXCSUM)
25218c2ecf20Sopenharmony_ci		gfar_rx_checksum(skb, fcb);
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	/* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here.
25248c2ecf20Sopenharmony_ci	 * Even if vlan rx accel is disabled, on some chips
25258c2ecf20Sopenharmony_ci	 * RXFCB_VLN is pseudo randomly set.
25268c2ecf20Sopenharmony_ci	 */
25278c2ecf20Sopenharmony_ci	if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX &&
25288c2ecf20Sopenharmony_ci	    be16_to_cpu(fcb->flags) & RXFCB_VLN)
25298c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
25308c2ecf20Sopenharmony_ci				       be16_to_cpu(fcb->vlctl));
25318c2ecf20Sopenharmony_ci}
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
25348c2ecf20Sopenharmony_ci * until the budget/quota has been reached. Returns the number
25358c2ecf20Sopenharmony_ci * of frames handled
25368c2ecf20Sopenharmony_ci */
25378c2ecf20Sopenharmony_cistatic int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
25388c2ecf20Sopenharmony_ci			      int rx_work_limit)
25398c2ecf20Sopenharmony_ci{
25408c2ecf20Sopenharmony_ci	struct net_device *ndev = rx_queue->ndev;
25418c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(ndev);
25428c2ecf20Sopenharmony_ci	struct rxbd8 *bdp;
25438c2ecf20Sopenharmony_ci	int i, howmany = 0;
25448c2ecf20Sopenharmony_ci	struct sk_buff *skb = rx_queue->skb;
25458c2ecf20Sopenharmony_ci	int cleaned_cnt = gfar_rxbd_unused(rx_queue);
25468c2ecf20Sopenharmony_ci	unsigned int total_bytes = 0, total_pkts = 0;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	/* Get the first full descriptor */
25498c2ecf20Sopenharmony_ci	i = rx_queue->next_to_clean;
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	while (rx_work_limit--) {
25528c2ecf20Sopenharmony_ci		u32 lstatus;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci		if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) {
25558c2ecf20Sopenharmony_ci			gfar_alloc_rx_buffs(rx_queue, cleaned_cnt);
25568c2ecf20Sopenharmony_ci			cleaned_cnt = 0;
25578c2ecf20Sopenharmony_ci		}
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci		bdp = &rx_queue->rx_bd_base[i];
25608c2ecf20Sopenharmony_ci		lstatus = be32_to_cpu(bdp->lstatus);
25618c2ecf20Sopenharmony_ci		if (lstatus & BD_LFLAG(RXBD_EMPTY))
25628c2ecf20Sopenharmony_ci			break;
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci		/* lost RXBD_LAST descriptor due to overrun */
25658c2ecf20Sopenharmony_ci		if (skb &&
25668c2ecf20Sopenharmony_ci		    (lstatus & BD_LFLAG(RXBD_FIRST))) {
25678c2ecf20Sopenharmony_ci			/* discard faulty buffer */
25688c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
25698c2ecf20Sopenharmony_ci			skb = NULL;
25708c2ecf20Sopenharmony_ci			rx_queue->stats.rx_dropped++;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci			/* can continue normally */
25738c2ecf20Sopenharmony_ci		}
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci		/* order rx buffer descriptor reads */
25768c2ecf20Sopenharmony_ci		rmb();
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci		/* fetch next to clean buffer from the ring */
25798c2ecf20Sopenharmony_ci		skb = gfar_get_next_rxbuff(rx_queue, lstatus, skb);
25808c2ecf20Sopenharmony_ci		if (unlikely(!skb))
25818c2ecf20Sopenharmony_ci			break;
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci		cleaned_cnt++;
25848c2ecf20Sopenharmony_ci		howmany++;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci		if (unlikely(++i == rx_queue->rx_ring_size))
25878c2ecf20Sopenharmony_ci			i = 0;
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci		rx_queue->next_to_clean = i;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci		/* fetch next buffer if not the last in frame */
25928c2ecf20Sopenharmony_ci		if (!(lstatus & BD_LFLAG(RXBD_LAST)))
25938c2ecf20Sopenharmony_ci			continue;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci		if (unlikely(lstatus & BD_LFLAG(RXBD_ERR))) {
25968c2ecf20Sopenharmony_ci			count_errors(lstatus, ndev);
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci			/* discard faulty buffer */
25998c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
26008c2ecf20Sopenharmony_ci			skb = NULL;
26018c2ecf20Sopenharmony_ci			rx_queue->stats.rx_dropped++;
26028c2ecf20Sopenharmony_ci			continue;
26038c2ecf20Sopenharmony_ci		}
26048c2ecf20Sopenharmony_ci
26058c2ecf20Sopenharmony_ci		gfar_process_frame(ndev, skb);
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci		/* Increment the number of packets */
26088c2ecf20Sopenharmony_ci		total_pkts++;
26098c2ecf20Sopenharmony_ci		total_bytes += skb->len;
26108c2ecf20Sopenharmony_ci
26118c2ecf20Sopenharmony_ci		skb_record_rx_queue(skb, rx_queue->qindex);
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, ndev);
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci		/* Send the packet up the stack */
26168c2ecf20Sopenharmony_ci		napi_gro_receive(&rx_queue->grp->napi_rx, skb);
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_ci		skb = NULL;
26198c2ecf20Sopenharmony_ci	}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	/* Store incomplete frames for completion */
26228c2ecf20Sopenharmony_ci	rx_queue->skb = skb;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	rx_queue->stats.rx_packets += total_pkts;
26258c2ecf20Sopenharmony_ci	rx_queue->stats.rx_bytes += total_bytes;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	if (cleaned_cnt)
26288c2ecf20Sopenharmony_ci		gfar_alloc_rx_buffs(rx_queue, cleaned_cnt);
26298c2ecf20Sopenharmony_ci
26308c2ecf20Sopenharmony_ci	/* Update Last Free RxBD pointer for LFC */
26318c2ecf20Sopenharmony_ci	if (unlikely(priv->tx_actual_en)) {
26328c2ecf20Sopenharmony_ci		u32 bdp_dma = gfar_rxbd_dma_lastfree(rx_queue);
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci		gfar_write(rx_queue->rfbptr, bdp_dma);
26358c2ecf20Sopenharmony_ci	}
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	return howmany;
26388c2ecf20Sopenharmony_ci}
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_cistatic int gfar_poll_rx_sq(struct napi_struct *napi, int budget)
26418c2ecf20Sopenharmony_ci{
26428c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp =
26438c2ecf20Sopenharmony_ci		container_of(napi, struct gfar_priv_grp, napi_rx);
26448c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = gfargrp->regs;
26458c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue;
26468c2ecf20Sopenharmony_ci	int work_done = 0;
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	/* Clear IEVENT, so interrupts aren't called again
26498c2ecf20Sopenharmony_ci	 * because of the packets that have already arrived
26508c2ecf20Sopenharmony_ci	 */
26518c2ecf20Sopenharmony_ci	gfar_write(&regs->ievent, IEVENT_RX_MASK);
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci	work_done = gfar_clean_rx_ring(rx_queue, budget);
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	if (work_done < budget) {
26568c2ecf20Sopenharmony_ci		u32 imask;
26578c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
26588c2ecf20Sopenharmony_ci		/* Clear the halt bit in RSTAT */
26598c2ecf20Sopenharmony_ci		gfar_write(&regs->rstat, gfargrp->rstat);
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci		spin_lock_irq(&gfargrp->grplock);
26628c2ecf20Sopenharmony_ci		imask = gfar_read(&regs->imask);
26638c2ecf20Sopenharmony_ci		imask |= IMASK_RX_DEFAULT;
26648c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, imask);
26658c2ecf20Sopenharmony_ci		spin_unlock_irq(&gfargrp->grplock);
26668c2ecf20Sopenharmony_ci	}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	return work_done;
26698c2ecf20Sopenharmony_ci}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_cistatic int gfar_poll_tx_sq(struct napi_struct *napi, int budget)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp =
26748c2ecf20Sopenharmony_ci		container_of(napi, struct gfar_priv_grp, napi_tx);
26758c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = gfargrp->regs;
26768c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue;
26778c2ecf20Sopenharmony_ci	u32 imask;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	/* Clear IEVENT, so interrupts aren't called again
26808c2ecf20Sopenharmony_ci	 * because of the packets that have already arrived
26818c2ecf20Sopenharmony_ci	 */
26828c2ecf20Sopenharmony_ci	gfar_write(&regs->ievent, IEVENT_TX_MASK);
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci	/* run Tx cleanup to completion */
26858c2ecf20Sopenharmony_ci	if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
26868c2ecf20Sopenharmony_ci		gfar_clean_tx_ring(tx_queue);
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci	napi_complete(napi);
26898c2ecf20Sopenharmony_ci
26908c2ecf20Sopenharmony_ci	spin_lock_irq(&gfargrp->grplock);
26918c2ecf20Sopenharmony_ci	imask = gfar_read(&regs->imask);
26928c2ecf20Sopenharmony_ci	imask |= IMASK_TX_DEFAULT;
26938c2ecf20Sopenharmony_ci	gfar_write(&regs->imask, imask);
26948c2ecf20Sopenharmony_ci	spin_unlock_irq(&gfargrp->grplock);
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	return 0;
26978c2ecf20Sopenharmony_ci}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_cistatic int gfar_poll_rx(struct napi_struct *napi, int budget)
27008c2ecf20Sopenharmony_ci{
27018c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp =
27028c2ecf20Sopenharmony_ci		container_of(napi, struct gfar_priv_grp, napi_rx);
27038c2ecf20Sopenharmony_ci	struct gfar_private *priv = gfargrp->priv;
27048c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = gfargrp->regs;
27058c2ecf20Sopenharmony_ci	struct gfar_priv_rx_q *rx_queue = NULL;
27068c2ecf20Sopenharmony_ci	int work_done = 0, work_done_per_q = 0;
27078c2ecf20Sopenharmony_ci	int i, budget_per_q = 0;
27088c2ecf20Sopenharmony_ci	unsigned long rstat_rxf;
27098c2ecf20Sopenharmony_ci	int num_act_queues;
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_ci	/* Clear IEVENT, so interrupts aren't called again
27128c2ecf20Sopenharmony_ci	 * because of the packets that have already arrived
27138c2ecf20Sopenharmony_ci	 */
27148c2ecf20Sopenharmony_ci	gfar_write(&regs->ievent, IEVENT_RX_MASK);
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	num_act_queues = bitmap_weight(&rstat_rxf, MAX_RX_QS);
27198c2ecf20Sopenharmony_ci	if (num_act_queues)
27208c2ecf20Sopenharmony_ci		budget_per_q = budget/num_act_queues;
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
27238c2ecf20Sopenharmony_ci		/* skip queue if not active */
27248c2ecf20Sopenharmony_ci		if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
27258c2ecf20Sopenharmony_ci			continue;
27268c2ecf20Sopenharmony_ci
27278c2ecf20Sopenharmony_ci		rx_queue = priv->rx_queue[i];
27288c2ecf20Sopenharmony_ci		work_done_per_q =
27298c2ecf20Sopenharmony_ci			gfar_clean_rx_ring(rx_queue, budget_per_q);
27308c2ecf20Sopenharmony_ci		work_done += work_done_per_q;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci		/* finished processing this queue */
27338c2ecf20Sopenharmony_ci		if (work_done_per_q < budget_per_q) {
27348c2ecf20Sopenharmony_ci			/* clear active queue hw indication */
27358c2ecf20Sopenharmony_ci			gfar_write(&regs->rstat,
27368c2ecf20Sopenharmony_ci				   RSTAT_CLEAR_RXF0 >> i);
27378c2ecf20Sopenharmony_ci			num_act_queues--;
27388c2ecf20Sopenharmony_ci
27398c2ecf20Sopenharmony_ci			if (!num_act_queues)
27408c2ecf20Sopenharmony_ci				break;
27418c2ecf20Sopenharmony_ci		}
27428c2ecf20Sopenharmony_ci	}
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_ci	if (!num_act_queues) {
27458c2ecf20Sopenharmony_ci		u32 imask;
27468c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci		/* Clear the halt bit in RSTAT */
27498c2ecf20Sopenharmony_ci		gfar_write(&regs->rstat, gfargrp->rstat);
27508c2ecf20Sopenharmony_ci
27518c2ecf20Sopenharmony_ci		spin_lock_irq(&gfargrp->grplock);
27528c2ecf20Sopenharmony_ci		imask = gfar_read(&regs->imask);
27538c2ecf20Sopenharmony_ci		imask |= IMASK_RX_DEFAULT;
27548c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, imask);
27558c2ecf20Sopenharmony_ci		spin_unlock_irq(&gfargrp->grplock);
27568c2ecf20Sopenharmony_ci	}
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	return work_done;
27598c2ecf20Sopenharmony_ci}
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_cistatic int gfar_poll_tx(struct napi_struct *napi, int budget)
27628c2ecf20Sopenharmony_ci{
27638c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp =
27648c2ecf20Sopenharmony_ci		container_of(napi, struct gfar_priv_grp, napi_tx);
27658c2ecf20Sopenharmony_ci	struct gfar_private *priv = gfargrp->priv;
27668c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = gfargrp->regs;
27678c2ecf20Sopenharmony_ci	struct gfar_priv_tx_q *tx_queue = NULL;
27688c2ecf20Sopenharmony_ci	int has_tx_work = 0;
27698c2ecf20Sopenharmony_ci	int i;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	/* Clear IEVENT, so interrupts aren't called again
27728c2ecf20Sopenharmony_ci	 * because of the packets that have already arrived
27738c2ecf20Sopenharmony_ci	 */
27748c2ecf20Sopenharmony_ci	gfar_write(&regs->ievent, IEVENT_TX_MASK);
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
27778c2ecf20Sopenharmony_ci		tx_queue = priv->tx_queue[i];
27788c2ecf20Sopenharmony_ci		/* run Tx cleanup to completion */
27798c2ecf20Sopenharmony_ci		if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
27808c2ecf20Sopenharmony_ci			gfar_clean_tx_ring(tx_queue);
27818c2ecf20Sopenharmony_ci			has_tx_work = 1;
27828c2ecf20Sopenharmony_ci		}
27838c2ecf20Sopenharmony_ci	}
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	if (!has_tx_work) {
27868c2ecf20Sopenharmony_ci		u32 imask;
27878c2ecf20Sopenharmony_ci		napi_complete(napi);
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci		spin_lock_irq(&gfargrp->grplock);
27908c2ecf20Sopenharmony_ci		imask = gfar_read(&regs->imask);
27918c2ecf20Sopenharmony_ci		imask |= IMASK_TX_DEFAULT;
27928c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, imask);
27938c2ecf20Sopenharmony_ci		spin_unlock_irq(&gfargrp->grplock);
27948c2ecf20Sopenharmony_ci	}
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	return 0;
27978c2ecf20Sopenharmony_ci}
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci/* GFAR error interrupt handler */
28008c2ecf20Sopenharmony_cistatic irqreturn_t gfar_error(int irq, void *grp_id)
28018c2ecf20Sopenharmony_ci{
28028c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp = grp_id;
28038c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = gfargrp->regs;
28048c2ecf20Sopenharmony_ci	struct gfar_private *priv= gfargrp->priv;
28058c2ecf20Sopenharmony_ci	struct net_device *dev = priv->ndev;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	/* Save ievent for future reference */
28088c2ecf20Sopenharmony_ci	u32 events = gfar_read(&regs->ievent);
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_ci	/* Clear IEVENT */
28118c2ecf20Sopenharmony_ci	gfar_write(&regs->ievent, events & IEVENT_ERR_MASK);
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	/* Magic Packet is not an error. */
28148c2ecf20Sopenharmony_ci	if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) &&
28158c2ecf20Sopenharmony_ci	    (events & IEVENT_MAG))
28168c2ecf20Sopenharmony_ci		events &= ~IEVENT_MAG;
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	/* Hmm... */
28198c2ecf20Sopenharmony_ci	if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
28208c2ecf20Sopenharmony_ci		netdev_dbg(dev,
28218c2ecf20Sopenharmony_ci			   "error interrupt (ievent=0x%08x imask=0x%08x)\n",
28228c2ecf20Sopenharmony_ci			   events, gfar_read(&regs->imask));
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	/* Update the error counters */
28258c2ecf20Sopenharmony_ci	if (events & IEVENT_TXE) {
28268c2ecf20Sopenharmony_ci		dev->stats.tx_errors++;
28278c2ecf20Sopenharmony_ci
28288c2ecf20Sopenharmony_ci		if (events & IEVENT_LC)
28298c2ecf20Sopenharmony_ci			dev->stats.tx_window_errors++;
28308c2ecf20Sopenharmony_ci		if (events & IEVENT_CRL)
28318c2ecf20Sopenharmony_ci			dev->stats.tx_aborted_errors++;
28328c2ecf20Sopenharmony_ci		if (events & IEVENT_XFUN) {
28338c2ecf20Sopenharmony_ci			netif_dbg(priv, tx_err, dev,
28348c2ecf20Sopenharmony_ci				  "TX FIFO underrun, packet dropped\n");
28358c2ecf20Sopenharmony_ci			dev->stats.tx_dropped++;
28368c2ecf20Sopenharmony_ci			atomic64_inc(&priv->extra_stats.tx_underrun);
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci			schedule_work(&priv->reset_task);
28398c2ecf20Sopenharmony_ci		}
28408c2ecf20Sopenharmony_ci		netif_dbg(priv, tx_err, dev, "Transmit Error\n");
28418c2ecf20Sopenharmony_ci	}
28428c2ecf20Sopenharmony_ci	if (events & IEVENT_BSY) {
28438c2ecf20Sopenharmony_ci		dev->stats.rx_over_errors++;
28448c2ecf20Sopenharmony_ci		atomic64_inc(&priv->extra_stats.rx_bsy);
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci		netif_dbg(priv, rx_err, dev, "busy error (rstat: %x)\n",
28478c2ecf20Sopenharmony_ci			  gfar_read(&regs->rstat));
28488c2ecf20Sopenharmony_ci	}
28498c2ecf20Sopenharmony_ci	if (events & IEVENT_BABR) {
28508c2ecf20Sopenharmony_ci		dev->stats.rx_errors++;
28518c2ecf20Sopenharmony_ci		atomic64_inc(&priv->extra_stats.rx_babr);
28528c2ecf20Sopenharmony_ci
28538c2ecf20Sopenharmony_ci		netif_dbg(priv, rx_err, dev, "babbling RX error\n");
28548c2ecf20Sopenharmony_ci	}
28558c2ecf20Sopenharmony_ci	if (events & IEVENT_EBERR) {
28568c2ecf20Sopenharmony_ci		atomic64_inc(&priv->extra_stats.eberr);
28578c2ecf20Sopenharmony_ci		netif_dbg(priv, rx_err, dev, "bus error\n");
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci	if (events & IEVENT_RXC)
28608c2ecf20Sopenharmony_ci		netif_dbg(priv, rx_status, dev, "control frame\n");
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	if (events & IEVENT_BABT) {
28638c2ecf20Sopenharmony_ci		atomic64_inc(&priv->extra_stats.tx_babt);
28648c2ecf20Sopenharmony_ci		netif_dbg(priv, tx_err, dev, "babbling TX error\n");
28658c2ecf20Sopenharmony_ci	}
28668c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
28678c2ecf20Sopenharmony_ci}
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci/* The interrupt handler for devices with one interrupt */
28708c2ecf20Sopenharmony_cistatic irqreturn_t gfar_interrupt(int irq, void *grp_id)
28718c2ecf20Sopenharmony_ci{
28728c2ecf20Sopenharmony_ci	struct gfar_priv_grp *gfargrp = grp_id;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci	/* Save ievent for future reference */
28758c2ecf20Sopenharmony_ci	u32 events = gfar_read(&gfargrp->regs->ievent);
28768c2ecf20Sopenharmony_ci
28778c2ecf20Sopenharmony_ci	/* Check for reception */
28788c2ecf20Sopenharmony_ci	if (events & IEVENT_RX_MASK)
28798c2ecf20Sopenharmony_ci		gfar_receive(irq, grp_id);
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	/* Check for transmit completion */
28828c2ecf20Sopenharmony_ci	if (events & IEVENT_TX_MASK)
28838c2ecf20Sopenharmony_ci		gfar_transmit(irq, grp_id);
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	/* Check for errors */
28868c2ecf20Sopenharmony_ci	if (events & IEVENT_ERR_MASK)
28878c2ecf20Sopenharmony_ci		gfar_error(irq, grp_id);
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
28908c2ecf20Sopenharmony_ci}
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
28938c2ecf20Sopenharmony_ci/* Polling 'interrupt' - used by things like netconsole to send skbs
28948c2ecf20Sopenharmony_ci * without having to re-enable interrupts. It's not called while
28958c2ecf20Sopenharmony_ci * the interrupt routine is executing.
28968c2ecf20Sopenharmony_ci */
28978c2ecf20Sopenharmony_cistatic void gfar_netpoll(struct net_device *dev)
28988c2ecf20Sopenharmony_ci{
28998c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
29008c2ecf20Sopenharmony_ci	int i;
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_ci	/* If the device has multiple interrupts, run tx/rx */
29038c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
29048c2ecf20Sopenharmony_ci		for (i = 0; i < priv->num_grps; i++) {
29058c2ecf20Sopenharmony_ci			struct gfar_priv_grp *grp = &priv->gfargrp[i];
29068c2ecf20Sopenharmony_ci
29078c2ecf20Sopenharmony_ci			disable_irq(gfar_irq(grp, TX)->irq);
29088c2ecf20Sopenharmony_ci			disable_irq(gfar_irq(grp, RX)->irq);
29098c2ecf20Sopenharmony_ci			disable_irq(gfar_irq(grp, ER)->irq);
29108c2ecf20Sopenharmony_ci			gfar_interrupt(gfar_irq(grp, TX)->irq, grp);
29118c2ecf20Sopenharmony_ci			enable_irq(gfar_irq(grp, ER)->irq);
29128c2ecf20Sopenharmony_ci			enable_irq(gfar_irq(grp, RX)->irq);
29138c2ecf20Sopenharmony_ci			enable_irq(gfar_irq(grp, TX)->irq);
29148c2ecf20Sopenharmony_ci		}
29158c2ecf20Sopenharmony_ci	} else {
29168c2ecf20Sopenharmony_ci		for (i = 0; i < priv->num_grps; i++) {
29178c2ecf20Sopenharmony_ci			struct gfar_priv_grp *grp = &priv->gfargrp[i];
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci			disable_irq(gfar_irq(grp, TX)->irq);
29208c2ecf20Sopenharmony_ci			gfar_interrupt(gfar_irq(grp, TX)->irq, grp);
29218c2ecf20Sopenharmony_ci			enable_irq(gfar_irq(grp, TX)->irq);
29228c2ecf20Sopenharmony_ci		}
29238c2ecf20Sopenharmony_ci	}
29248c2ecf20Sopenharmony_ci}
29258c2ecf20Sopenharmony_ci#endif
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_cistatic void free_grp_irqs(struct gfar_priv_grp *grp)
29288c2ecf20Sopenharmony_ci{
29298c2ecf20Sopenharmony_ci	free_irq(gfar_irq(grp, TX)->irq, grp);
29308c2ecf20Sopenharmony_ci	free_irq(gfar_irq(grp, RX)->irq, grp);
29318c2ecf20Sopenharmony_ci	free_irq(gfar_irq(grp, ER)->irq, grp);
29328c2ecf20Sopenharmony_ci}
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_cistatic int register_grp_irqs(struct gfar_priv_grp *grp)
29358c2ecf20Sopenharmony_ci{
29368c2ecf20Sopenharmony_ci	struct gfar_private *priv = grp->priv;
29378c2ecf20Sopenharmony_ci	struct net_device *dev = priv->ndev;
29388c2ecf20Sopenharmony_ci	int err;
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	/* If the device has multiple interrupts, register for
29418c2ecf20Sopenharmony_ci	 * them.  Otherwise, only register for the one
29428c2ecf20Sopenharmony_ci	 */
29438c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
29448c2ecf20Sopenharmony_ci		/* Install our interrupt handlers for Error,
29458c2ecf20Sopenharmony_ci		 * Transmit, and Receive
29468c2ecf20Sopenharmony_ci		 */
29478c2ecf20Sopenharmony_ci		err = request_irq(gfar_irq(grp, ER)->irq, gfar_error, 0,
29488c2ecf20Sopenharmony_ci				  gfar_irq(grp, ER)->name, grp);
29498c2ecf20Sopenharmony_ci		if (err < 0) {
29508c2ecf20Sopenharmony_ci			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
29518c2ecf20Sopenharmony_ci				  gfar_irq(grp, ER)->irq);
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci			goto err_irq_fail;
29548c2ecf20Sopenharmony_ci		}
29558c2ecf20Sopenharmony_ci		enable_irq_wake(gfar_irq(grp, ER)->irq);
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci		err = request_irq(gfar_irq(grp, TX)->irq, gfar_transmit, 0,
29588c2ecf20Sopenharmony_ci				  gfar_irq(grp, TX)->name, grp);
29598c2ecf20Sopenharmony_ci		if (err < 0) {
29608c2ecf20Sopenharmony_ci			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
29618c2ecf20Sopenharmony_ci				  gfar_irq(grp, TX)->irq);
29628c2ecf20Sopenharmony_ci			goto tx_irq_fail;
29638c2ecf20Sopenharmony_ci		}
29648c2ecf20Sopenharmony_ci		err = request_irq(gfar_irq(grp, RX)->irq, gfar_receive, 0,
29658c2ecf20Sopenharmony_ci				  gfar_irq(grp, RX)->name, grp);
29668c2ecf20Sopenharmony_ci		if (err < 0) {
29678c2ecf20Sopenharmony_ci			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
29688c2ecf20Sopenharmony_ci				  gfar_irq(grp, RX)->irq);
29698c2ecf20Sopenharmony_ci			goto rx_irq_fail;
29708c2ecf20Sopenharmony_ci		}
29718c2ecf20Sopenharmony_ci		enable_irq_wake(gfar_irq(grp, RX)->irq);
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci	} else {
29748c2ecf20Sopenharmony_ci		err = request_irq(gfar_irq(grp, TX)->irq, gfar_interrupt, 0,
29758c2ecf20Sopenharmony_ci				  gfar_irq(grp, TX)->name, grp);
29768c2ecf20Sopenharmony_ci		if (err < 0) {
29778c2ecf20Sopenharmony_ci			netif_err(priv, intr, dev, "Can't get IRQ %d\n",
29788c2ecf20Sopenharmony_ci				  gfar_irq(grp, TX)->irq);
29798c2ecf20Sopenharmony_ci			goto err_irq_fail;
29808c2ecf20Sopenharmony_ci		}
29818c2ecf20Sopenharmony_ci		enable_irq_wake(gfar_irq(grp, TX)->irq);
29828c2ecf20Sopenharmony_ci	}
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	return 0;
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_cirx_irq_fail:
29878c2ecf20Sopenharmony_ci	free_irq(gfar_irq(grp, TX)->irq, grp);
29888c2ecf20Sopenharmony_citx_irq_fail:
29898c2ecf20Sopenharmony_ci	free_irq(gfar_irq(grp, ER)->irq, grp);
29908c2ecf20Sopenharmony_cierr_irq_fail:
29918c2ecf20Sopenharmony_ci	return err;
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci}
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_cistatic void gfar_free_irq(struct gfar_private *priv)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	int i;
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	/* Free the IRQs */
30008c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
30018c2ecf20Sopenharmony_ci		for (i = 0; i < priv->num_grps; i++)
30028c2ecf20Sopenharmony_ci			free_grp_irqs(&priv->gfargrp[i]);
30038c2ecf20Sopenharmony_ci	} else {
30048c2ecf20Sopenharmony_ci		for (i = 0; i < priv->num_grps; i++)
30058c2ecf20Sopenharmony_ci			free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
30068c2ecf20Sopenharmony_ci				 &priv->gfargrp[i]);
30078c2ecf20Sopenharmony_ci	}
30088c2ecf20Sopenharmony_ci}
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_cistatic int gfar_request_irq(struct gfar_private *priv)
30118c2ecf20Sopenharmony_ci{
30128c2ecf20Sopenharmony_ci	int err, i, j;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
30158c2ecf20Sopenharmony_ci		err = register_grp_irqs(&priv->gfargrp[i]);
30168c2ecf20Sopenharmony_ci		if (err) {
30178c2ecf20Sopenharmony_ci			for (j = 0; j < i; j++)
30188c2ecf20Sopenharmony_ci				free_grp_irqs(&priv->gfargrp[j]);
30198c2ecf20Sopenharmony_ci			return err;
30208c2ecf20Sopenharmony_ci		}
30218c2ecf20Sopenharmony_ci	}
30228c2ecf20Sopenharmony_ci
30238c2ecf20Sopenharmony_ci	return 0;
30248c2ecf20Sopenharmony_ci}
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_ci/* Called when something needs to use the ethernet device
30278c2ecf20Sopenharmony_ci * Returns 0 for success.
30288c2ecf20Sopenharmony_ci */
30298c2ecf20Sopenharmony_cistatic int gfar_enet_open(struct net_device *dev)
30308c2ecf20Sopenharmony_ci{
30318c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
30328c2ecf20Sopenharmony_ci	int err;
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci	err = init_phy(dev);
30358c2ecf20Sopenharmony_ci	if (err)
30368c2ecf20Sopenharmony_ci		return err;
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	err = gfar_request_irq(priv);
30398c2ecf20Sopenharmony_ci	if (err)
30408c2ecf20Sopenharmony_ci		return err;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci	err = startup_gfar(dev);
30438c2ecf20Sopenharmony_ci	if (err)
30448c2ecf20Sopenharmony_ci		return err;
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci	return err;
30478c2ecf20Sopenharmony_ci}
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_ci/* Stops the kernel queue, and halts the controller */
30508c2ecf20Sopenharmony_cistatic int gfar_close(struct net_device *dev)
30518c2ecf20Sopenharmony_ci{
30528c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	cancel_work_sync(&priv->reset_task);
30558c2ecf20Sopenharmony_ci	stop_gfar(dev);
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci	/* Disconnect from the PHY */
30588c2ecf20Sopenharmony_ci	phy_disconnect(dev->phydev);
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	gfar_free_irq(priv);
30618c2ecf20Sopenharmony_ci
30628c2ecf20Sopenharmony_ci	return 0;
30638c2ecf20Sopenharmony_ci}
30648c2ecf20Sopenharmony_ci
30658c2ecf20Sopenharmony_ci/* Clears each of the exact match registers to zero, so they
30668c2ecf20Sopenharmony_ci * don't interfere with normal reception
30678c2ecf20Sopenharmony_ci */
30688c2ecf20Sopenharmony_cistatic void gfar_clear_exact_match(struct net_device *dev)
30698c2ecf20Sopenharmony_ci{
30708c2ecf20Sopenharmony_ci	int idx;
30718c2ecf20Sopenharmony_ci	static const u8 zero_arr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	for (idx = 1; idx < GFAR_EM_NUM + 1; idx++)
30748c2ecf20Sopenharmony_ci		gfar_set_mac_for_addr(dev, idx, zero_arr);
30758c2ecf20Sopenharmony_ci}
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci/* Update the hash table based on the current list of multicast
30788c2ecf20Sopenharmony_ci * addresses we subscribe to.  Also, change the promiscuity of
30798c2ecf20Sopenharmony_ci * the device based on the flags (this function is called
30808c2ecf20Sopenharmony_ci * whenever dev->flags is changed
30818c2ecf20Sopenharmony_ci */
30828c2ecf20Sopenharmony_cistatic void gfar_set_multi(struct net_device *dev)
30838c2ecf20Sopenharmony_ci{
30848c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
30858c2ecf20Sopenharmony_ci	struct gfar_private *priv = netdev_priv(dev);
30868c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
30878c2ecf20Sopenharmony_ci	u32 tempval;
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
30908c2ecf20Sopenharmony_ci		/* Set RCTRL to PROM */
30918c2ecf20Sopenharmony_ci		tempval = gfar_read(&regs->rctrl);
30928c2ecf20Sopenharmony_ci		tempval |= RCTRL_PROM;
30938c2ecf20Sopenharmony_ci		gfar_write(&regs->rctrl, tempval);
30948c2ecf20Sopenharmony_ci	} else {
30958c2ecf20Sopenharmony_ci		/* Set RCTRL to not PROM */
30968c2ecf20Sopenharmony_ci		tempval = gfar_read(&regs->rctrl);
30978c2ecf20Sopenharmony_ci		tempval &= ~(RCTRL_PROM);
30988c2ecf20Sopenharmony_ci		gfar_write(&regs->rctrl, tempval);
30998c2ecf20Sopenharmony_ci	}
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI) {
31028c2ecf20Sopenharmony_ci		/* Set the hash to rx all multicast frames */
31038c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr0, 0xffffffff);
31048c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr1, 0xffffffff);
31058c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr2, 0xffffffff);
31068c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr3, 0xffffffff);
31078c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr4, 0xffffffff);
31088c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr5, 0xffffffff);
31098c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr6, 0xffffffff);
31108c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr7, 0xffffffff);
31118c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr0, 0xffffffff);
31128c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr1, 0xffffffff);
31138c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr2, 0xffffffff);
31148c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr3, 0xffffffff);
31158c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr4, 0xffffffff);
31168c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr5, 0xffffffff);
31178c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr6, 0xffffffff);
31188c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr7, 0xffffffff);
31198c2ecf20Sopenharmony_ci	} else {
31208c2ecf20Sopenharmony_ci		int em_num;
31218c2ecf20Sopenharmony_ci		int idx;
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci		/* zero out the hash */
31248c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr0, 0x0);
31258c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr1, 0x0);
31268c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr2, 0x0);
31278c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr3, 0x0);
31288c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr4, 0x0);
31298c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr5, 0x0);
31308c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr6, 0x0);
31318c2ecf20Sopenharmony_ci		gfar_write(&regs->igaddr7, 0x0);
31328c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr0, 0x0);
31338c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr1, 0x0);
31348c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr2, 0x0);
31358c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr3, 0x0);
31368c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr4, 0x0);
31378c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr5, 0x0);
31388c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr6, 0x0);
31398c2ecf20Sopenharmony_ci		gfar_write(&regs->gaddr7, 0x0);
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci		/* If we have extended hash tables, we need to
31428c2ecf20Sopenharmony_ci		 * clear the exact match registers to prepare for
31438c2ecf20Sopenharmony_ci		 * setting them
31448c2ecf20Sopenharmony_ci		 */
31458c2ecf20Sopenharmony_ci		if (priv->extended_hash) {
31468c2ecf20Sopenharmony_ci			em_num = GFAR_EM_NUM + 1;
31478c2ecf20Sopenharmony_ci			gfar_clear_exact_match(dev);
31488c2ecf20Sopenharmony_ci			idx = 1;
31498c2ecf20Sopenharmony_ci		} else {
31508c2ecf20Sopenharmony_ci			idx = 0;
31518c2ecf20Sopenharmony_ci			em_num = 0;
31528c2ecf20Sopenharmony_ci		}
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci		if (netdev_mc_empty(dev))
31558c2ecf20Sopenharmony_ci			return;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci		/* Parse the list, and set the appropriate bits */
31588c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
31598c2ecf20Sopenharmony_ci			if (idx < em_num) {
31608c2ecf20Sopenharmony_ci				gfar_set_mac_for_addr(dev, idx, ha->addr);
31618c2ecf20Sopenharmony_ci				idx++;
31628c2ecf20Sopenharmony_ci			} else
31638c2ecf20Sopenharmony_ci				gfar_set_hash_for_addr(dev, ha->addr);
31648c2ecf20Sopenharmony_ci		}
31658c2ecf20Sopenharmony_ci	}
31668c2ecf20Sopenharmony_ci}
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_civoid gfar_mac_reset(struct gfar_private *priv)
31698c2ecf20Sopenharmony_ci{
31708c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
31718c2ecf20Sopenharmony_ci	u32 tempval;
31728c2ecf20Sopenharmony_ci
31738c2ecf20Sopenharmony_ci	/* Reset MAC layer */
31748c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg1, MACCFG1_SOFT_RESET);
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	/* We need to delay at least 3 TX clocks */
31778c2ecf20Sopenharmony_ci	udelay(3);
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci	/* the soft reset bit is not self-resetting, so we need to
31808c2ecf20Sopenharmony_ci	 * clear it before resuming normal operation
31818c2ecf20Sopenharmony_ci	 */
31828c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg1, 0);
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	udelay(3);
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci	gfar_rx_offload_en(priv);
31878c2ecf20Sopenharmony_ci
31888c2ecf20Sopenharmony_ci	/* Initialize the max receive frame/buffer lengths */
31898c2ecf20Sopenharmony_ci	gfar_write(&regs->maxfrm, GFAR_JUMBO_FRAME_SIZE);
31908c2ecf20Sopenharmony_ci	gfar_write(&regs->mrblr, GFAR_RXB_SIZE);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	/* Initialize the Minimum Frame Length Register */
31938c2ecf20Sopenharmony_ci	gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	/* Initialize MACCFG2. */
31968c2ecf20Sopenharmony_ci	tempval = MACCFG2_INIT_SETTINGS;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	/* eTSEC74 erratum: Rx frames of length MAXFRM or MAXFRM-1
31998c2ecf20Sopenharmony_ci	 * are marked as truncated.  Avoid this by MACCFG2[Huge Frame]=1,
32008c2ecf20Sopenharmony_ci	 * and by checking RxBD[LG] and discarding larger than MAXFRM.
32018c2ecf20Sopenharmony_ci	 */
32028c2ecf20Sopenharmony_ci	if (gfar_has_errata(priv, GFAR_ERRATA_74))
32038c2ecf20Sopenharmony_ci		tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg2, tempval);
32068c2ecf20Sopenharmony_ci
32078c2ecf20Sopenharmony_ci	/* Clear mac addr hash registers */
32088c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr0, 0);
32098c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr1, 0);
32108c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr2, 0);
32118c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr3, 0);
32128c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr4, 0);
32138c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr5, 0);
32148c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr6, 0);
32158c2ecf20Sopenharmony_ci	gfar_write(&regs->igaddr7, 0);
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr0, 0);
32188c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr1, 0);
32198c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr2, 0);
32208c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr3, 0);
32218c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr4, 0);
32228c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr5, 0);
32238c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr6, 0);
32248c2ecf20Sopenharmony_ci	gfar_write(&regs->gaddr7, 0);
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	if (priv->extended_hash)
32278c2ecf20Sopenharmony_ci		gfar_clear_exact_match(priv->ndev);
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci	gfar_mac_rx_config(priv);
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci	gfar_mac_tx_config(priv);
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	gfar_set_mac_address(priv->ndev);
32348c2ecf20Sopenharmony_ci
32358c2ecf20Sopenharmony_ci	gfar_set_multi(priv->ndev);
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	/* clear ievent and imask before configuring coalescing */
32388c2ecf20Sopenharmony_ci	gfar_ints_disable(priv);
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	/* Configure the coalescing support */
32418c2ecf20Sopenharmony_ci	gfar_configure_coalescing_all(priv);
32428c2ecf20Sopenharmony_ci}
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_cistatic void gfar_hw_init(struct gfar_private *priv)
32458c2ecf20Sopenharmony_ci{
32468c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
32478c2ecf20Sopenharmony_ci	u32 attrs;
32488c2ecf20Sopenharmony_ci
32498c2ecf20Sopenharmony_ci	/* Stop the DMA engine now, in case it was running before
32508c2ecf20Sopenharmony_ci	 * (The firmware could have used it, and left it running).
32518c2ecf20Sopenharmony_ci	 */
32528c2ecf20Sopenharmony_ci	gfar_halt(priv);
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci	gfar_mac_reset(priv);
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci	/* Zero out the rmon mib registers if it has them */
32578c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
32588c2ecf20Sopenharmony_ci		memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib));
32598c2ecf20Sopenharmony_ci
32608c2ecf20Sopenharmony_ci		/* Mask off the CAM interrupts */
32618c2ecf20Sopenharmony_ci		gfar_write(&regs->rmon.cam1, 0xffffffff);
32628c2ecf20Sopenharmony_ci		gfar_write(&regs->rmon.cam2, 0xffffffff);
32638c2ecf20Sopenharmony_ci	}
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	/* Initialize ECNTRL */
32668c2ecf20Sopenharmony_ci	gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	/* Set the extraction length and index */
32698c2ecf20Sopenharmony_ci	attrs = ATTRELI_EL(priv->rx_stash_size) |
32708c2ecf20Sopenharmony_ci		ATTRELI_EI(priv->rx_stash_index);
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci	gfar_write(&regs->attreli, attrs);
32738c2ecf20Sopenharmony_ci
32748c2ecf20Sopenharmony_ci	/* Start with defaults, and add stashing
32758c2ecf20Sopenharmony_ci	 * depending on driver parameters
32768c2ecf20Sopenharmony_ci	 */
32778c2ecf20Sopenharmony_ci	attrs = ATTR_INIT_SETTINGS;
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	if (priv->bd_stash_en)
32808c2ecf20Sopenharmony_ci		attrs |= ATTR_BDSTASH;
32818c2ecf20Sopenharmony_ci
32828c2ecf20Sopenharmony_ci	if (priv->rx_stash_size != 0)
32838c2ecf20Sopenharmony_ci		attrs |= ATTR_BUFSTASH;
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ci	gfar_write(&regs->attr, attrs);
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	/* FIFO configs */
32888c2ecf20Sopenharmony_ci	gfar_write(&regs->fifo_tx_thr, DEFAULT_FIFO_TX_THR);
32898c2ecf20Sopenharmony_ci	gfar_write(&regs->fifo_tx_starve, DEFAULT_FIFO_TX_STARVE);
32908c2ecf20Sopenharmony_ci	gfar_write(&regs->fifo_tx_starve_shutoff, DEFAULT_FIFO_TX_STARVE_OFF);
32918c2ecf20Sopenharmony_ci
32928c2ecf20Sopenharmony_ci	/* Program the interrupt steering regs, only for MG devices */
32938c2ecf20Sopenharmony_ci	if (priv->num_grps > 1)
32948c2ecf20Sopenharmony_ci		gfar_write_isrg(priv);
32958c2ecf20Sopenharmony_ci}
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_cistatic const struct net_device_ops gfar_netdev_ops = {
32988c2ecf20Sopenharmony_ci	.ndo_open = gfar_enet_open,
32998c2ecf20Sopenharmony_ci	.ndo_start_xmit = gfar_start_xmit,
33008c2ecf20Sopenharmony_ci	.ndo_stop = gfar_close,
33018c2ecf20Sopenharmony_ci	.ndo_change_mtu = gfar_change_mtu,
33028c2ecf20Sopenharmony_ci	.ndo_set_features = gfar_set_features,
33038c2ecf20Sopenharmony_ci	.ndo_set_rx_mode = gfar_set_multi,
33048c2ecf20Sopenharmony_ci	.ndo_tx_timeout = gfar_timeout,
33058c2ecf20Sopenharmony_ci	.ndo_do_ioctl = gfar_ioctl,
33068c2ecf20Sopenharmony_ci	.ndo_get_stats = gfar_get_stats,
33078c2ecf20Sopenharmony_ci	.ndo_change_carrier = fixed_phy_change_carrier,
33088c2ecf20Sopenharmony_ci	.ndo_set_mac_address = gfar_set_mac_addr,
33098c2ecf20Sopenharmony_ci	.ndo_validate_addr = eth_validate_addr,
33108c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
33118c2ecf20Sopenharmony_ci	.ndo_poll_controller = gfar_netpoll,
33128c2ecf20Sopenharmony_ci#endif
33138c2ecf20Sopenharmony_ci};
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci/* Set up the ethernet device structure, private data,
33168c2ecf20Sopenharmony_ci * and anything else we need before we start
33178c2ecf20Sopenharmony_ci */
33188c2ecf20Sopenharmony_cistatic int gfar_probe(struct platform_device *ofdev)
33198c2ecf20Sopenharmony_ci{
33208c2ecf20Sopenharmony_ci	struct device_node *np = ofdev->dev.of_node;
33218c2ecf20Sopenharmony_ci	struct net_device *dev = NULL;
33228c2ecf20Sopenharmony_ci	struct gfar_private *priv = NULL;
33238c2ecf20Sopenharmony_ci	int err = 0, i;
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci	err = gfar_of_init(ofdev, &dev);
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	if (err)
33288c2ecf20Sopenharmony_ci		return err;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	priv = netdev_priv(dev);
33318c2ecf20Sopenharmony_ci	priv->ndev = dev;
33328c2ecf20Sopenharmony_ci	priv->ofdev = ofdev;
33338c2ecf20Sopenharmony_ci	priv->dev = &ofdev->dev;
33348c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &ofdev->dev);
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci	INIT_WORK(&priv->reset_task, gfar_reset_task);
33378c2ecf20Sopenharmony_ci
33388c2ecf20Sopenharmony_ci	platform_set_drvdata(ofdev, priv);
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	gfar_detect_errata(priv);
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci	/* Set the dev->base_addr to the gfar reg region */
33438c2ecf20Sopenharmony_ci	dev->base_addr = (unsigned long) priv->gfargrp[0].regs;
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci	/* Fill in the dev structure */
33468c2ecf20Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
33478c2ecf20Sopenharmony_ci	/* MTU range: 50 - 9586 */
33488c2ecf20Sopenharmony_ci	dev->mtu = 1500;
33498c2ecf20Sopenharmony_ci	dev->min_mtu = 50;
33508c2ecf20Sopenharmony_ci	dev->max_mtu = GFAR_JUMBO_FRAME_SIZE - ETH_HLEN;
33518c2ecf20Sopenharmony_ci	dev->netdev_ops = &gfar_netdev_ops;
33528c2ecf20Sopenharmony_ci	dev->ethtool_ops = &gfar_ethtool_ops;
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci	/* Register for napi ...We are registering NAPI for each grp */
33558c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
33568c2ecf20Sopenharmony_ci		if (priv->poll_mode == GFAR_SQ_POLLING) {
33578c2ecf20Sopenharmony_ci			netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
33588c2ecf20Sopenharmony_ci				       gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
33598c2ecf20Sopenharmony_ci			netif_tx_napi_add(dev, &priv->gfargrp[i].napi_tx,
33608c2ecf20Sopenharmony_ci				       gfar_poll_tx_sq, 2);
33618c2ecf20Sopenharmony_ci		} else {
33628c2ecf20Sopenharmony_ci			netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
33638c2ecf20Sopenharmony_ci				       gfar_poll_rx, GFAR_DEV_WEIGHT);
33648c2ecf20Sopenharmony_ci			netif_tx_napi_add(dev, &priv->gfargrp[i].napi_tx,
33658c2ecf20Sopenharmony_ci				       gfar_poll_tx, 2);
33668c2ecf20Sopenharmony_ci		}
33678c2ecf20Sopenharmony_ci	}
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
33708c2ecf20Sopenharmony_ci		dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
33718c2ecf20Sopenharmony_ci				   NETIF_F_RXCSUM;
33728c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG |
33738c2ecf20Sopenharmony_ci				 NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
33748c2ecf20Sopenharmony_ci	}
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
33778c2ecf20Sopenharmony_ci		dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
33788c2ecf20Sopenharmony_ci				    NETIF_F_HW_VLAN_CTAG_RX;
33798c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
33808c2ecf20Sopenharmony_ci	}
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_ci	gfar_init_addr_hash_table(priv);
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	/* Insert receive time stamps into padding alignment bytes, and
33878c2ecf20Sopenharmony_ci	 * plus 2 bytes padding to ensure the cpu alignment.
33888c2ecf20Sopenharmony_ci	 */
33898c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
33908c2ecf20Sopenharmony_ci		priv->padding = 8 + DEFAULT_PADDING;
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci	if (dev->features & NETIF_F_IP_CSUM ||
33938c2ecf20Sopenharmony_ci	    priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
33948c2ecf20Sopenharmony_ci		dev->needed_headroom = GMAC_FCB_LEN + GMAC_TXPAL_LEN;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci	/* Initializing some of the rx/tx queue level parameters */
33978c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++) {
33988c2ecf20Sopenharmony_ci		priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE;
33998c2ecf20Sopenharmony_ci		priv->tx_queue[i]->num_txbdfree = DEFAULT_TX_RING_SIZE;
34008c2ecf20Sopenharmony_ci		priv->tx_queue[i]->txcoalescing = DEFAULT_TX_COALESCE;
34018c2ecf20Sopenharmony_ci		priv->tx_queue[i]->txic = DEFAULT_TXIC;
34028c2ecf20Sopenharmony_ci	}
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++) {
34058c2ecf20Sopenharmony_ci		priv->rx_queue[i]->rx_ring_size = DEFAULT_RX_RING_SIZE;
34068c2ecf20Sopenharmony_ci		priv->rx_queue[i]->rxcoalescing = DEFAULT_RX_COALESCE;
34078c2ecf20Sopenharmony_ci		priv->rx_queue[i]->rxic = DEFAULT_RXIC;
34088c2ecf20Sopenharmony_ci	}
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	/* Always enable rx filer if available */
34118c2ecf20Sopenharmony_ci	priv->rx_filer_enable =
34128c2ecf20Sopenharmony_ci	    (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0;
34138c2ecf20Sopenharmony_ci	/* Enable most messages by default */
34148c2ecf20Sopenharmony_ci	priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
34158c2ecf20Sopenharmony_ci	/* use pritority h/w tx queue scheduling for single queue devices */
34168c2ecf20Sopenharmony_ci	if (priv->num_tx_queues == 1)
34178c2ecf20Sopenharmony_ci		priv->prio_sched_en = 1;
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	set_bit(GFAR_DOWN, &priv->state);
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci	gfar_hw_init(priv);
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	/* Carrier starts down, phylib will bring it up */
34248c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_ci	err = register_netdev(dev);
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci	if (err) {
34298c2ecf20Sopenharmony_ci		pr_err("%s: Cannot register net device, aborting\n", dev->name);
34308c2ecf20Sopenharmony_ci		goto register_fail;
34318c2ecf20Sopenharmony_ci	}
34328c2ecf20Sopenharmony_ci
34338c2ecf20Sopenharmony_ci	if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET)
34348c2ecf20Sopenharmony_ci		priv->wol_supported |= GFAR_WOL_MAGIC;
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_ci	if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER) &&
34378c2ecf20Sopenharmony_ci	    priv->rx_filer_enable)
34388c2ecf20Sopenharmony_ci		priv->wol_supported |= GFAR_WOL_FILER_UCAST;
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_ci	device_set_wakeup_capable(&ofdev->dev, priv->wol_supported);
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	/* fill out IRQ number and name fields */
34438c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
34448c2ecf20Sopenharmony_ci		struct gfar_priv_grp *grp = &priv->gfargrp[i];
34458c2ecf20Sopenharmony_ci		if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
34468c2ecf20Sopenharmony_ci			sprintf(gfar_irq(grp, TX)->name, "%s%s%c%s",
34478c2ecf20Sopenharmony_ci				dev->name, "_g", '0' + i, "_tx");
34488c2ecf20Sopenharmony_ci			sprintf(gfar_irq(grp, RX)->name, "%s%s%c%s",
34498c2ecf20Sopenharmony_ci				dev->name, "_g", '0' + i, "_rx");
34508c2ecf20Sopenharmony_ci			sprintf(gfar_irq(grp, ER)->name, "%s%s%c%s",
34518c2ecf20Sopenharmony_ci				dev->name, "_g", '0' + i, "_er");
34528c2ecf20Sopenharmony_ci		} else
34538c2ecf20Sopenharmony_ci			strcpy(gfar_irq(grp, TX)->name, dev->name);
34548c2ecf20Sopenharmony_ci	}
34558c2ecf20Sopenharmony_ci
34568c2ecf20Sopenharmony_ci	/* Initialize the filer table */
34578c2ecf20Sopenharmony_ci	gfar_init_filer_table(priv);
34588c2ecf20Sopenharmony_ci
34598c2ecf20Sopenharmony_ci	/* Print out the device info */
34608c2ecf20Sopenharmony_ci	netdev_info(dev, "mac: %pM\n", dev->dev_addr);
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_ci	/* Even more device info helps when determining which kernel
34638c2ecf20Sopenharmony_ci	 * provided which set of benchmarks.
34648c2ecf20Sopenharmony_ci	 */
34658c2ecf20Sopenharmony_ci	netdev_info(dev, "Running with NAPI enabled\n");
34668c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_queues; i++)
34678c2ecf20Sopenharmony_ci		netdev_info(dev, "RX BD ring size for Q[%d]: %d\n",
34688c2ecf20Sopenharmony_ci			    i, priv->rx_queue[i]->rx_ring_size);
34698c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_queues; i++)
34708c2ecf20Sopenharmony_ci		netdev_info(dev, "TX BD ring size for Q[%d]: %d\n",
34718c2ecf20Sopenharmony_ci			    i, priv->tx_queue[i]->tx_ring_size);
34728c2ecf20Sopenharmony_ci
34738c2ecf20Sopenharmony_ci	return 0;
34748c2ecf20Sopenharmony_ci
34758c2ecf20Sopenharmony_ciregister_fail:
34768c2ecf20Sopenharmony_ci	if (of_phy_is_fixed_link(np))
34778c2ecf20Sopenharmony_ci		of_phy_deregister_fixed_link(np);
34788c2ecf20Sopenharmony_ci	unmap_group_regs(priv);
34798c2ecf20Sopenharmony_ci	gfar_free_rx_queues(priv);
34808c2ecf20Sopenharmony_ci	gfar_free_tx_queues(priv);
34818c2ecf20Sopenharmony_ci	of_node_put(priv->phy_node);
34828c2ecf20Sopenharmony_ci	of_node_put(priv->tbi_node);
34838c2ecf20Sopenharmony_ci	free_gfar_dev(priv);
34848c2ecf20Sopenharmony_ci	return err;
34858c2ecf20Sopenharmony_ci}
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_cistatic int gfar_remove(struct platform_device *ofdev)
34888c2ecf20Sopenharmony_ci{
34898c2ecf20Sopenharmony_ci	struct gfar_private *priv = platform_get_drvdata(ofdev);
34908c2ecf20Sopenharmony_ci	struct device_node *np = ofdev->dev.of_node;
34918c2ecf20Sopenharmony_ci
34928c2ecf20Sopenharmony_ci	of_node_put(priv->phy_node);
34938c2ecf20Sopenharmony_ci	of_node_put(priv->tbi_node);
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_ci	unregister_netdev(priv->ndev);
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_ci	if (of_phy_is_fixed_link(np))
34988c2ecf20Sopenharmony_ci		of_phy_deregister_fixed_link(np);
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci	unmap_group_regs(priv);
35018c2ecf20Sopenharmony_ci	gfar_free_rx_queues(priv);
35028c2ecf20Sopenharmony_ci	gfar_free_tx_queues(priv);
35038c2ecf20Sopenharmony_ci	free_gfar_dev(priv);
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	return 0;
35068c2ecf20Sopenharmony_ci}
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_cistatic void __gfar_filer_disable(struct gfar_private *priv)
35118c2ecf20Sopenharmony_ci{
35128c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
35138c2ecf20Sopenharmony_ci	u32 temp;
35148c2ecf20Sopenharmony_ci
35158c2ecf20Sopenharmony_ci	temp = gfar_read(&regs->rctrl);
35168c2ecf20Sopenharmony_ci	temp &= ~(RCTRL_FILREN | RCTRL_PRSDEP_INIT);
35178c2ecf20Sopenharmony_ci	gfar_write(&regs->rctrl, temp);
35188c2ecf20Sopenharmony_ci}
35198c2ecf20Sopenharmony_ci
35208c2ecf20Sopenharmony_cistatic void __gfar_filer_enable(struct gfar_private *priv)
35218c2ecf20Sopenharmony_ci{
35228c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
35238c2ecf20Sopenharmony_ci	u32 temp;
35248c2ecf20Sopenharmony_ci
35258c2ecf20Sopenharmony_ci	temp = gfar_read(&regs->rctrl);
35268c2ecf20Sopenharmony_ci	temp |= RCTRL_FILREN | RCTRL_PRSDEP_INIT;
35278c2ecf20Sopenharmony_ci	gfar_write(&regs->rctrl, temp);
35288c2ecf20Sopenharmony_ci}
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci/* Filer rules implementing wol capabilities */
35318c2ecf20Sopenharmony_cistatic void gfar_filer_config_wol(struct gfar_private *priv)
35328c2ecf20Sopenharmony_ci{
35338c2ecf20Sopenharmony_ci	unsigned int i;
35348c2ecf20Sopenharmony_ci	u32 rqfcr;
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	__gfar_filer_disable(priv);
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci	/* clear the filer table, reject any packet by default */
35398c2ecf20Sopenharmony_ci	rqfcr = RQFCR_RJE | RQFCR_CMP_MATCH;
35408c2ecf20Sopenharmony_ci	for (i = 0; i <= MAX_FILER_IDX; i++)
35418c2ecf20Sopenharmony_ci		gfar_write_filer(priv, i, rqfcr, 0);
35428c2ecf20Sopenharmony_ci
35438c2ecf20Sopenharmony_ci	i = 0;
35448c2ecf20Sopenharmony_ci	if (priv->wol_opts & GFAR_WOL_FILER_UCAST) {
35458c2ecf20Sopenharmony_ci		/* unicast packet, accept it */
35468c2ecf20Sopenharmony_ci		struct net_device *ndev = priv->ndev;
35478c2ecf20Sopenharmony_ci		/* get the default rx queue index */
35488c2ecf20Sopenharmony_ci		u8 qindex = (u8)priv->gfargrp[0].rx_queue->qindex;
35498c2ecf20Sopenharmony_ci		u32 dest_mac_addr = (ndev->dev_addr[0] << 16) |
35508c2ecf20Sopenharmony_ci				    (ndev->dev_addr[1] << 8) |
35518c2ecf20Sopenharmony_ci				     ndev->dev_addr[2];
35528c2ecf20Sopenharmony_ci
35538c2ecf20Sopenharmony_ci		rqfcr = (qindex << 10) | RQFCR_AND |
35548c2ecf20Sopenharmony_ci			RQFCR_CMP_EXACT | RQFCR_PID_DAH;
35558c2ecf20Sopenharmony_ci
35568c2ecf20Sopenharmony_ci		gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci		dest_mac_addr = (ndev->dev_addr[3] << 16) |
35598c2ecf20Sopenharmony_ci				(ndev->dev_addr[4] << 8) |
35608c2ecf20Sopenharmony_ci				 ndev->dev_addr[5];
35618c2ecf20Sopenharmony_ci		rqfcr = (qindex << 10) | RQFCR_GPI |
35628c2ecf20Sopenharmony_ci			RQFCR_CMP_EXACT | RQFCR_PID_DAL;
35638c2ecf20Sopenharmony_ci		gfar_write_filer(priv, i++, rqfcr, dest_mac_addr);
35648c2ecf20Sopenharmony_ci	}
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	__gfar_filer_enable(priv);
35678c2ecf20Sopenharmony_ci}
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_cistatic void gfar_filer_restore_table(struct gfar_private *priv)
35708c2ecf20Sopenharmony_ci{
35718c2ecf20Sopenharmony_ci	u32 rqfcr, rqfpr;
35728c2ecf20Sopenharmony_ci	unsigned int i;
35738c2ecf20Sopenharmony_ci
35748c2ecf20Sopenharmony_ci	__gfar_filer_disable(priv);
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci	for (i = 0; i <= MAX_FILER_IDX; i++) {
35778c2ecf20Sopenharmony_ci		rqfcr = priv->ftp_rqfcr[i];
35788c2ecf20Sopenharmony_ci		rqfpr = priv->ftp_rqfpr[i];
35798c2ecf20Sopenharmony_ci		gfar_write_filer(priv, i, rqfcr, rqfpr);
35808c2ecf20Sopenharmony_ci	}
35818c2ecf20Sopenharmony_ci
35828c2ecf20Sopenharmony_ci	__gfar_filer_enable(priv);
35838c2ecf20Sopenharmony_ci}
35848c2ecf20Sopenharmony_ci
35858c2ecf20Sopenharmony_ci/* gfar_start() for Rx only and with the FGPI filer interrupt enabled */
35868c2ecf20Sopenharmony_cistatic void gfar_start_wol_filer(struct gfar_private *priv)
35878c2ecf20Sopenharmony_ci{
35888c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
35898c2ecf20Sopenharmony_ci	u32 tempval;
35908c2ecf20Sopenharmony_ci	int i = 0;
35918c2ecf20Sopenharmony_ci
35928c2ecf20Sopenharmony_ci	/* Enable Rx hw queues */
35938c2ecf20Sopenharmony_ci	gfar_write(&regs->rqueue, priv->rqueue);
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	/* Initialize DMACTRL to have WWR and WOP */
35968c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->dmactrl);
35978c2ecf20Sopenharmony_ci	tempval |= DMACTRL_INIT_SETTINGS;
35988c2ecf20Sopenharmony_ci	gfar_write(&regs->dmactrl, tempval);
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ci	/* Make sure we aren't stopped */
36018c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->dmactrl);
36028c2ecf20Sopenharmony_ci	tempval &= ~DMACTRL_GRS;
36038c2ecf20Sopenharmony_ci	gfar_write(&regs->dmactrl, tempval);
36048c2ecf20Sopenharmony_ci
36058c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_grps; i++) {
36068c2ecf20Sopenharmony_ci		regs = priv->gfargrp[i].regs;
36078c2ecf20Sopenharmony_ci		/* Clear RHLT, so that the DMA starts polling now */
36088c2ecf20Sopenharmony_ci		gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
36098c2ecf20Sopenharmony_ci		/* enable the Filer General Purpose Interrupt */
36108c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, IMASK_FGPI);
36118c2ecf20Sopenharmony_ci	}
36128c2ecf20Sopenharmony_ci
36138c2ecf20Sopenharmony_ci	/* Enable Rx DMA */
36148c2ecf20Sopenharmony_ci	tempval = gfar_read(&regs->maccfg1);
36158c2ecf20Sopenharmony_ci	tempval |= MACCFG1_RX_EN;
36168c2ecf20Sopenharmony_ci	gfar_write(&regs->maccfg1, tempval);
36178c2ecf20Sopenharmony_ci}
36188c2ecf20Sopenharmony_ci
36198c2ecf20Sopenharmony_cistatic int gfar_suspend(struct device *dev)
36208c2ecf20Sopenharmony_ci{
36218c2ecf20Sopenharmony_ci	struct gfar_private *priv = dev_get_drvdata(dev);
36228c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
36238c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
36248c2ecf20Sopenharmony_ci	u32 tempval;
36258c2ecf20Sopenharmony_ci	u16 wol = priv->wol_opts;
36268c2ecf20Sopenharmony_ci
36278c2ecf20Sopenharmony_ci	if (!netif_running(ndev))
36288c2ecf20Sopenharmony_ci		return 0;
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_ci	disable_napi(priv);
36318c2ecf20Sopenharmony_ci	netif_tx_lock(ndev);
36328c2ecf20Sopenharmony_ci	netif_device_detach(ndev);
36338c2ecf20Sopenharmony_ci	netif_tx_unlock(ndev);
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ci	gfar_halt(priv);
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_ci	if (wol & GFAR_WOL_MAGIC) {
36388c2ecf20Sopenharmony_ci		/* Enable interrupt on Magic Packet */
36398c2ecf20Sopenharmony_ci		gfar_write(&regs->imask, IMASK_MAG);
36408c2ecf20Sopenharmony_ci
36418c2ecf20Sopenharmony_ci		/* Enable Magic Packet mode */
36428c2ecf20Sopenharmony_ci		tempval = gfar_read(&regs->maccfg2);
36438c2ecf20Sopenharmony_ci		tempval |= MACCFG2_MPEN;
36448c2ecf20Sopenharmony_ci		gfar_write(&regs->maccfg2, tempval);
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci		/* re-enable the Rx block */
36478c2ecf20Sopenharmony_ci		tempval = gfar_read(&regs->maccfg1);
36488c2ecf20Sopenharmony_ci		tempval |= MACCFG1_RX_EN;
36498c2ecf20Sopenharmony_ci		gfar_write(&regs->maccfg1, tempval);
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	} else if (wol & GFAR_WOL_FILER_UCAST) {
36528c2ecf20Sopenharmony_ci		gfar_filer_config_wol(priv);
36538c2ecf20Sopenharmony_ci		gfar_start_wol_filer(priv);
36548c2ecf20Sopenharmony_ci
36558c2ecf20Sopenharmony_ci	} else {
36568c2ecf20Sopenharmony_ci		phy_stop(ndev->phydev);
36578c2ecf20Sopenharmony_ci	}
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci	return 0;
36608c2ecf20Sopenharmony_ci}
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_cistatic int gfar_resume(struct device *dev)
36638c2ecf20Sopenharmony_ci{
36648c2ecf20Sopenharmony_ci	struct gfar_private *priv = dev_get_drvdata(dev);
36658c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
36668c2ecf20Sopenharmony_ci	struct gfar __iomem *regs = priv->gfargrp[0].regs;
36678c2ecf20Sopenharmony_ci	u32 tempval;
36688c2ecf20Sopenharmony_ci	u16 wol = priv->wol_opts;
36698c2ecf20Sopenharmony_ci
36708c2ecf20Sopenharmony_ci	if (!netif_running(ndev))
36718c2ecf20Sopenharmony_ci		return 0;
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci	if (wol & GFAR_WOL_MAGIC) {
36748c2ecf20Sopenharmony_ci		/* Disable Magic Packet mode */
36758c2ecf20Sopenharmony_ci		tempval = gfar_read(&regs->maccfg2);
36768c2ecf20Sopenharmony_ci		tempval &= ~MACCFG2_MPEN;
36778c2ecf20Sopenharmony_ci		gfar_write(&regs->maccfg2, tempval);
36788c2ecf20Sopenharmony_ci
36798c2ecf20Sopenharmony_ci	} else if (wol & GFAR_WOL_FILER_UCAST) {
36808c2ecf20Sopenharmony_ci		/* need to stop rx only, tx is already down */
36818c2ecf20Sopenharmony_ci		gfar_halt(priv);
36828c2ecf20Sopenharmony_ci		gfar_filer_restore_table(priv);
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ci	} else {
36858c2ecf20Sopenharmony_ci		phy_start(ndev->phydev);
36868c2ecf20Sopenharmony_ci	}
36878c2ecf20Sopenharmony_ci
36888c2ecf20Sopenharmony_ci	gfar_start(priv);
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	netif_device_attach(ndev);
36918c2ecf20Sopenharmony_ci	enable_napi(priv);
36928c2ecf20Sopenharmony_ci
36938c2ecf20Sopenharmony_ci	return 0;
36948c2ecf20Sopenharmony_ci}
36958c2ecf20Sopenharmony_ci
36968c2ecf20Sopenharmony_cistatic int gfar_restore(struct device *dev)
36978c2ecf20Sopenharmony_ci{
36988c2ecf20Sopenharmony_ci	struct gfar_private *priv = dev_get_drvdata(dev);
36998c2ecf20Sopenharmony_ci	struct net_device *ndev = priv->ndev;
37008c2ecf20Sopenharmony_ci
37018c2ecf20Sopenharmony_ci	if (!netif_running(ndev)) {
37028c2ecf20Sopenharmony_ci		netif_device_attach(ndev);
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci		return 0;
37058c2ecf20Sopenharmony_ci	}
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci	gfar_init_bds(ndev);
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_ci	gfar_mac_reset(priv);
37108c2ecf20Sopenharmony_ci
37118c2ecf20Sopenharmony_ci	gfar_init_tx_rx_base(priv);
37128c2ecf20Sopenharmony_ci
37138c2ecf20Sopenharmony_ci	gfar_start(priv);
37148c2ecf20Sopenharmony_ci
37158c2ecf20Sopenharmony_ci	priv->oldlink = 0;
37168c2ecf20Sopenharmony_ci	priv->oldspeed = 0;
37178c2ecf20Sopenharmony_ci	priv->oldduplex = -1;
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_ci	if (ndev->phydev)
37208c2ecf20Sopenharmony_ci		phy_start(ndev->phydev);
37218c2ecf20Sopenharmony_ci
37228c2ecf20Sopenharmony_ci	netif_device_attach(ndev);
37238c2ecf20Sopenharmony_ci	enable_napi(priv);
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	return 0;
37268c2ecf20Sopenharmony_ci}
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_cistatic const struct dev_pm_ops gfar_pm_ops = {
37298c2ecf20Sopenharmony_ci	.suspend = gfar_suspend,
37308c2ecf20Sopenharmony_ci	.resume = gfar_resume,
37318c2ecf20Sopenharmony_ci	.freeze = gfar_suspend,
37328c2ecf20Sopenharmony_ci	.thaw = gfar_resume,
37338c2ecf20Sopenharmony_ci	.restore = gfar_restore,
37348c2ecf20Sopenharmony_ci};
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_ci#define GFAR_PM_OPS (&gfar_pm_ops)
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ci#else
37398c2ecf20Sopenharmony_ci
37408c2ecf20Sopenharmony_ci#define GFAR_PM_OPS NULL
37418c2ecf20Sopenharmony_ci
37428c2ecf20Sopenharmony_ci#endif
37438c2ecf20Sopenharmony_ci
37448c2ecf20Sopenharmony_cistatic const struct of_device_id gfar_match[] =
37458c2ecf20Sopenharmony_ci{
37468c2ecf20Sopenharmony_ci	{
37478c2ecf20Sopenharmony_ci		.type = "network",
37488c2ecf20Sopenharmony_ci		.compatible = "gianfar",
37498c2ecf20Sopenharmony_ci	},
37508c2ecf20Sopenharmony_ci	{
37518c2ecf20Sopenharmony_ci		.compatible = "fsl,etsec2",
37528c2ecf20Sopenharmony_ci	},
37538c2ecf20Sopenharmony_ci	{},
37548c2ecf20Sopenharmony_ci};
37558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, gfar_match);
37568c2ecf20Sopenharmony_ci
37578c2ecf20Sopenharmony_ci/* Structure for a device driver */
37588c2ecf20Sopenharmony_cistatic struct platform_driver gfar_driver = {
37598c2ecf20Sopenharmony_ci	.driver = {
37608c2ecf20Sopenharmony_ci		.name = "fsl-gianfar",
37618c2ecf20Sopenharmony_ci		.pm = GFAR_PM_OPS,
37628c2ecf20Sopenharmony_ci		.of_match_table = gfar_match,
37638c2ecf20Sopenharmony_ci	},
37648c2ecf20Sopenharmony_ci	.probe = gfar_probe,
37658c2ecf20Sopenharmony_ci	.remove = gfar_remove,
37668c2ecf20Sopenharmony_ci};
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_cimodule_platform_driver(gfar_driver);
3769