162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. (www.synopsys.com)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Driver for the ARC EMAC 10100 (hardware revision 5)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Contributors:
862306a36Sopenharmony_ci *		Amit Bhor
962306a36Sopenharmony_ci *		Sameer Dhavale
1062306a36Sopenharmony_ci *		Vineet Gupta
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/crc32.h>
1462306a36Sopenharmony_ci#include <linux/etherdevice.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/of_address.h>
2062306a36Sopenharmony_ci#include <linux/of_irq.h>
2162306a36Sopenharmony_ci#include <linux/of_mdio.h>
2262306a36Sopenharmony_ci#include <linux/of_net.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "emac.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic void arc_emac_restart(struct net_device *ndev);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/**
2962306a36Sopenharmony_ci * arc_emac_tx_avail - Return the number of available slots in the tx ring.
3062306a36Sopenharmony_ci * @priv: Pointer to ARC EMAC private data structure.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * returns: the number of slots available for transmission in tx the ring.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic inline int arc_emac_tx_avail(struct arc_emac_priv *priv)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return (priv->txbd_dirty + TX_BD_NUM - priv->txbd_curr - 1) % TX_BD_NUM;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/**
4062306a36Sopenharmony_ci * arc_emac_adjust_link - Adjust the PHY link duplex.
4162306a36Sopenharmony_ci * @ndev:	Pointer to the net_device structure.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * This function is called to change the duplex setting after auto negotiation
4462306a36Sopenharmony_ci * is done by the PHY.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistatic void arc_emac_adjust_link(struct net_device *ndev)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
4962306a36Sopenharmony_ci	struct phy_device *phy_dev = ndev->phydev;
5062306a36Sopenharmony_ci	unsigned int reg, state_changed = 0;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (priv->link != phy_dev->link) {
5362306a36Sopenharmony_ci		priv->link = phy_dev->link;
5462306a36Sopenharmony_ci		state_changed = 1;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (priv->speed != phy_dev->speed) {
5862306a36Sopenharmony_ci		priv->speed = phy_dev->speed;
5962306a36Sopenharmony_ci		state_changed = 1;
6062306a36Sopenharmony_ci		if (priv->set_mac_speed)
6162306a36Sopenharmony_ci			priv->set_mac_speed(priv, priv->speed);
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (priv->duplex != phy_dev->duplex) {
6562306a36Sopenharmony_ci		reg = arc_reg_get(priv, R_CTRL);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		if (phy_dev->duplex == DUPLEX_FULL)
6862306a36Sopenharmony_ci			reg |= ENFL_MASK;
6962306a36Sopenharmony_ci		else
7062306a36Sopenharmony_ci			reg &= ~ENFL_MASK;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		arc_reg_set(priv, R_CTRL, reg);
7362306a36Sopenharmony_ci		priv->duplex = phy_dev->duplex;
7462306a36Sopenharmony_ci		state_changed = 1;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (state_changed)
7862306a36Sopenharmony_ci		phy_print_status(phy_dev);
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/**
8262306a36Sopenharmony_ci * arc_emac_get_drvinfo - Get EMAC driver information.
8362306a36Sopenharmony_ci * @ndev:	Pointer to net_device structure.
8462306a36Sopenharmony_ci * @info:	Pointer to ethtool_drvinfo structure.
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * This implements ethtool command for getting the driver information.
8762306a36Sopenharmony_ci * Issue "ethtool -i ethX" under linux prompt to execute this function.
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_cistatic void arc_emac_get_drvinfo(struct net_device *ndev,
9062306a36Sopenharmony_ci				 struct ethtool_drvinfo *info)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	strscpy(info->driver, priv->drv_name, sizeof(info->driver));
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const struct ethtool_ops arc_emac_ethtool_ops = {
9862306a36Sopenharmony_ci	.get_drvinfo	= arc_emac_get_drvinfo,
9962306a36Sopenharmony_ci	.get_link	= ethtool_op_get_link,
10062306a36Sopenharmony_ci	.get_link_ksettings = phy_ethtool_get_link_ksettings,
10162306a36Sopenharmony_ci	.set_link_ksettings = phy_ethtool_set_link_ksettings,
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define FIRST_OR_LAST_MASK	(FIRST_MASK | LAST_MASK)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/**
10762306a36Sopenharmony_ci * arc_emac_tx_clean - clears processed by EMAC Tx BDs.
10862306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_cistatic void arc_emac_tx_clean(struct net_device *ndev)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
11362306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
11462306a36Sopenharmony_ci	unsigned int i;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i < TX_BD_NUM; i++) {
11762306a36Sopenharmony_ci		unsigned int *txbd_dirty = &priv->txbd_dirty;
11862306a36Sopenharmony_ci		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
11962306a36Sopenharmony_ci		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
12062306a36Sopenharmony_ci		struct sk_buff *skb = tx_buff->skb;
12162306a36Sopenharmony_ci		unsigned int info = le32_to_cpu(txbd->info);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		if ((info & FOR_EMAC) || !txbd->data || !skb)
12462306a36Sopenharmony_ci			break;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
12762306a36Sopenharmony_ci			stats->tx_errors++;
12862306a36Sopenharmony_ci			stats->tx_dropped++;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci			if (info & DEFR)
13162306a36Sopenharmony_ci				stats->tx_carrier_errors++;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci			if (info & LTCL)
13462306a36Sopenharmony_ci				stats->collisions++;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci			if (info & UFLO)
13762306a36Sopenharmony_ci				stats->tx_fifo_errors++;
13862306a36Sopenharmony_ci		} else if (likely(info & FIRST_OR_LAST_MASK)) {
13962306a36Sopenharmony_ci			stats->tx_packets++;
14062306a36Sopenharmony_ci			stats->tx_bytes += skb->len;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr),
14462306a36Sopenharmony_ci				 dma_unmap_len(tx_buff, len), DMA_TO_DEVICE);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		/* return the sk_buff to system */
14762306a36Sopenharmony_ci		dev_consume_skb_irq(skb);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		txbd->data = 0;
15062306a36Sopenharmony_ci		txbd->info = 0;
15162306a36Sopenharmony_ci		tx_buff->skb = NULL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Ensure that txbd_dirty is visible to tx() before checking
15762306a36Sopenharmony_ci	 * for queue stopped.
15862306a36Sopenharmony_ci	 */
15962306a36Sopenharmony_ci	smp_mb();
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (netif_queue_stopped(ndev) && arc_emac_tx_avail(priv))
16262306a36Sopenharmony_ci		netif_wake_queue(ndev);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/**
16662306a36Sopenharmony_ci * arc_emac_rx - processing of Rx packets.
16762306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
16862306a36Sopenharmony_ci * @budget:	How many BDs to process on 1 call.
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci * returns:	Number of processed BDs
17162306a36Sopenharmony_ci *
17262306a36Sopenharmony_ci * Iterate through Rx BDs and deliver received packages to upper layer.
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_cistatic int arc_emac_rx(struct net_device *ndev, int budget)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
17762306a36Sopenharmony_ci	unsigned int work_done;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	for (work_done = 0; work_done < budget; work_done++) {
18062306a36Sopenharmony_ci		unsigned int *last_rx_bd = &priv->last_rx_bd;
18162306a36Sopenharmony_ci		struct net_device_stats *stats = &ndev->stats;
18262306a36Sopenharmony_ci		struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd];
18362306a36Sopenharmony_ci		struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd];
18462306a36Sopenharmony_ci		unsigned int pktlen, info = le32_to_cpu(rxbd->info);
18562306a36Sopenharmony_ci		struct sk_buff *skb;
18662306a36Sopenharmony_ci		dma_addr_t addr;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		if (unlikely((info & OWN_MASK) == FOR_EMAC))
18962306a36Sopenharmony_ci			break;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		/* Make a note that we saw a packet at this BD.
19262306a36Sopenharmony_ci		 * So next time, driver starts from this + 1
19362306a36Sopenharmony_ci		 */
19462306a36Sopenharmony_ci		*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		if (unlikely((info & FIRST_OR_LAST_MASK) !=
19762306a36Sopenharmony_ci			     FIRST_OR_LAST_MASK)) {
19862306a36Sopenharmony_ci			/* We pre-allocate buffers of MTU size so incoming
19962306a36Sopenharmony_ci			 * packets won't be split/chained.
20062306a36Sopenharmony_ci			 */
20162306a36Sopenharmony_ci			if (net_ratelimit())
20262306a36Sopenharmony_ci				netdev_err(ndev, "incomplete packet received\n");
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			/* Return ownership to EMAC */
20562306a36Sopenharmony_ci			rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
20662306a36Sopenharmony_ci			stats->rx_errors++;
20762306a36Sopenharmony_ci			stats->rx_length_errors++;
20862306a36Sopenharmony_ci			continue;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		/* Prepare the BD for next cycle. netif_receive_skb()
21262306a36Sopenharmony_ci		 * only if new skb was allocated and mapped to avoid holes
21362306a36Sopenharmony_ci		 * in the RX fifo.
21462306a36Sopenharmony_ci		 */
21562306a36Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE);
21662306a36Sopenharmony_ci		if (unlikely(!skb)) {
21762306a36Sopenharmony_ci			if (net_ratelimit())
21862306a36Sopenharmony_ci				netdev_err(ndev, "cannot allocate skb\n");
21962306a36Sopenharmony_ci			/* Return ownership to EMAC */
22062306a36Sopenharmony_ci			rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
22162306a36Sopenharmony_ci			stats->rx_errors++;
22262306a36Sopenharmony_ci			stats->rx_dropped++;
22362306a36Sopenharmony_ci			continue;
22462306a36Sopenharmony_ci		}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		addr = dma_map_single(&ndev->dev, (void *)skb->data,
22762306a36Sopenharmony_ci				      EMAC_BUFFER_SIZE, DMA_FROM_DEVICE);
22862306a36Sopenharmony_ci		if (dma_mapping_error(&ndev->dev, addr)) {
22962306a36Sopenharmony_ci			if (net_ratelimit())
23062306a36Sopenharmony_ci				netdev_err(ndev, "cannot map dma buffer\n");
23162306a36Sopenharmony_ci			dev_kfree_skb(skb);
23262306a36Sopenharmony_ci			/* Return ownership to EMAC */
23362306a36Sopenharmony_ci			rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
23462306a36Sopenharmony_ci			stats->rx_errors++;
23562306a36Sopenharmony_ci			stats->rx_dropped++;
23662306a36Sopenharmony_ci			continue;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		/* unmap previosly mapped skb */
24062306a36Sopenharmony_ci		dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr),
24162306a36Sopenharmony_ci				 dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		pktlen = info & LEN_MASK;
24462306a36Sopenharmony_ci		stats->rx_packets++;
24562306a36Sopenharmony_ci		stats->rx_bytes += pktlen;
24662306a36Sopenharmony_ci		skb_put(rx_buff->skb, pktlen);
24762306a36Sopenharmony_ci		rx_buff->skb->dev = ndev;
24862306a36Sopenharmony_ci		rx_buff->skb->protocol = eth_type_trans(rx_buff->skb, ndev);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		netif_receive_skb(rx_buff->skb);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		rx_buff->skb = skb;
25362306a36Sopenharmony_ci		dma_unmap_addr_set(rx_buff, addr, addr);
25462306a36Sopenharmony_ci		dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		rxbd->data = cpu_to_le32(addr);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/* Make sure pointer to data buffer is set */
25962306a36Sopenharmony_ci		wmb();
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		/* Return ownership to EMAC */
26262306a36Sopenharmony_ci		rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return work_done;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/**
26962306a36Sopenharmony_ci * arc_emac_rx_miss_handle - handle R_MISS register
27062306a36Sopenharmony_ci * @ndev:	Pointer to the net_device structure.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistatic void arc_emac_rx_miss_handle(struct net_device *ndev)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
27562306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
27662306a36Sopenharmony_ci	unsigned int miss;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	miss = arc_reg_get(priv, R_MISS);
27962306a36Sopenharmony_ci	if (miss) {
28062306a36Sopenharmony_ci		stats->rx_errors += miss;
28162306a36Sopenharmony_ci		stats->rx_missed_errors += miss;
28262306a36Sopenharmony_ci		priv->rx_missed_errors += miss;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/**
28762306a36Sopenharmony_ci * arc_emac_rx_stall_check - check RX stall
28862306a36Sopenharmony_ci * @ndev:	Pointer to the net_device structure.
28962306a36Sopenharmony_ci * @budget:	How many BDs requested to process on 1 call.
29062306a36Sopenharmony_ci * @work_done:	How many BDs processed
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * Under certain conditions EMAC stop reception of incoming packets and
29362306a36Sopenharmony_ci * continuously increment R_MISS register instead of saving data into
29462306a36Sopenharmony_ci * provided buffer. This function detect that condition and restart
29562306a36Sopenharmony_ci * EMAC.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic void arc_emac_rx_stall_check(struct net_device *ndev,
29862306a36Sopenharmony_ci				    int budget, unsigned int work_done)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
30162306a36Sopenharmony_ci	struct arc_emac_bd *rxbd;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (work_done)
30462306a36Sopenharmony_ci		priv->rx_missed_errors = 0;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	if (priv->rx_missed_errors && budget) {
30762306a36Sopenharmony_ci		rxbd = &priv->rxbd[priv->last_rx_bd];
30862306a36Sopenharmony_ci		if (le32_to_cpu(rxbd->info) & FOR_EMAC) {
30962306a36Sopenharmony_ci			arc_emac_restart(ndev);
31062306a36Sopenharmony_ci			priv->rx_missed_errors = 0;
31162306a36Sopenharmony_ci		}
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/**
31662306a36Sopenharmony_ci * arc_emac_poll - NAPI poll handler.
31762306a36Sopenharmony_ci * @napi:	Pointer to napi_struct structure.
31862306a36Sopenharmony_ci * @budget:	How many BDs to process on 1 call.
31962306a36Sopenharmony_ci *
32062306a36Sopenharmony_ci * returns:	Number of processed BDs
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic int arc_emac_poll(struct napi_struct *napi, int budget)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct net_device *ndev = napi->dev;
32562306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
32662306a36Sopenharmony_ci	unsigned int work_done;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	arc_emac_tx_clean(ndev);
32962306a36Sopenharmony_ci	arc_emac_rx_miss_handle(ndev);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	work_done = arc_emac_rx(ndev, budget);
33262306a36Sopenharmony_ci	if (work_done < budget) {
33362306a36Sopenharmony_ci		napi_complete_done(napi, work_done);
33462306a36Sopenharmony_ci		arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	arc_emac_rx_stall_check(ndev, budget, work_done);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return work_done;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci/**
34362306a36Sopenharmony_ci * arc_emac_intr - Global interrupt handler for EMAC.
34462306a36Sopenharmony_ci * @irq:		irq number.
34562306a36Sopenharmony_ci * @dev_instance:	device instance.
34662306a36Sopenharmony_ci *
34762306a36Sopenharmony_ci * returns: IRQ_HANDLED for all cases.
34862306a36Sopenharmony_ci *
34962306a36Sopenharmony_ci * ARC EMAC has only 1 interrupt line, and depending on bits raised in
35062306a36Sopenharmony_ci * STATUS register we may tell what is a reason for interrupt to fire.
35162306a36Sopenharmony_ci */
35262306a36Sopenharmony_cistatic irqreturn_t arc_emac_intr(int irq, void *dev_instance)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct net_device *ndev = dev_instance;
35562306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
35662306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
35762306a36Sopenharmony_ci	unsigned int status;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	status = arc_reg_get(priv, R_STATUS);
36062306a36Sopenharmony_ci	status &= ~MDIO_MASK;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Reset all flags except "MDIO complete" */
36362306a36Sopenharmony_ci	arc_reg_set(priv, R_STATUS, status);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (status & (RXINT_MASK | TXINT_MASK)) {
36662306a36Sopenharmony_ci		if (likely(napi_schedule_prep(&priv->napi))) {
36762306a36Sopenharmony_ci			arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
36862306a36Sopenharmony_ci			__napi_schedule(&priv->napi);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (status & ERR_MASK) {
37362306a36Sopenharmony_ci		/* MSER/RXCR/RXFR/RXFL interrupt fires on corresponding
37462306a36Sopenharmony_ci		 * 8-bit error counter overrun.
37562306a36Sopenharmony_ci		 */
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if (status & MSER_MASK) {
37862306a36Sopenharmony_ci			stats->rx_missed_errors += 0x100;
37962306a36Sopenharmony_ci			stats->rx_errors += 0x100;
38062306a36Sopenharmony_ci			priv->rx_missed_errors += 0x100;
38162306a36Sopenharmony_ci			napi_schedule(&priv->napi);
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		if (status & RXCR_MASK) {
38562306a36Sopenharmony_ci			stats->rx_crc_errors += 0x100;
38662306a36Sopenharmony_ci			stats->rx_errors += 0x100;
38762306a36Sopenharmony_ci		}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		if (status & RXFR_MASK) {
39062306a36Sopenharmony_ci			stats->rx_frame_errors += 0x100;
39162306a36Sopenharmony_ci			stats->rx_errors += 0x100;
39262306a36Sopenharmony_ci		}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		if (status & RXFL_MASK) {
39562306a36Sopenharmony_ci			stats->rx_over_errors += 0x100;
39662306a36Sopenharmony_ci			stats->rx_errors += 0x100;
39762306a36Sopenharmony_ci		}
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	return IRQ_HANDLED;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
40462306a36Sopenharmony_cistatic void arc_emac_poll_controller(struct net_device *dev)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	disable_irq(dev->irq);
40762306a36Sopenharmony_ci	arc_emac_intr(dev->irq, dev);
40862306a36Sopenharmony_ci	enable_irq(dev->irq);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci#endif
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci/**
41362306a36Sopenharmony_ci * arc_emac_open - Open the network device.
41462306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * returns: 0, on success or non-zero error value on failure.
41762306a36Sopenharmony_ci *
41862306a36Sopenharmony_ci * This function sets the MAC address, requests and enables an IRQ
41962306a36Sopenharmony_ci * for the EMAC device and starts the Tx queue.
42062306a36Sopenharmony_ci * It also connects to the phy device.
42162306a36Sopenharmony_ci */
42262306a36Sopenharmony_cistatic int arc_emac_open(struct net_device *ndev)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
42562306a36Sopenharmony_ci	struct phy_device *phy_dev = ndev->phydev;
42662306a36Sopenharmony_ci	int i;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	phy_dev->autoneg = AUTONEG_ENABLE;
42962306a36Sopenharmony_ci	phy_dev->speed = 0;
43062306a36Sopenharmony_ci	phy_dev->duplex = 0;
43162306a36Sopenharmony_ci	linkmode_and(phy_dev->advertising, phy_dev->advertising,
43262306a36Sopenharmony_ci		     phy_dev->supported);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	priv->last_rx_bd = 0;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* Allocate and set buffers for Rx BD's */
43762306a36Sopenharmony_ci	for (i = 0; i < RX_BD_NUM; i++) {
43862306a36Sopenharmony_ci		dma_addr_t addr;
43962306a36Sopenharmony_ci		unsigned int *last_rx_bd = &priv->last_rx_bd;
44062306a36Sopenharmony_ci		struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd];
44162306a36Sopenharmony_ci		struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd];
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		rx_buff->skb = netdev_alloc_skb_ip_align(ndev,
44462306a36Sopenharmony_ci							 EMAC_BUFFER_SIZE);
44562306a36Sopenharmony_ci		if (unlikely(!rx_buff->skb))
44662306a36Sopenharmony_ci			return -ENOMEM;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data,
44962306a36Sopenharmony_ci				      EMAC_BUFFER_SIZE, DMA_FROM_DEVICE);
45062306a36Sopenharmony_ci		if (dma_mapping_error(&ndev->dev, addr)) {
45162306a36Sopenharmony_ci			netdev_err(ndev, "cannot dma map\n");
45262306a36Sopenharmony_ci			dev_kfree_skb(rx_buff->skb);
45362306a36Sopenharmony_ci			return -ENOMEM;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci		dma_unmap_addr_set(rx_buff, addr, addr);
45662306a36Sopenharmony_ci		dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		rxbd->data = cpu_to_le32(addr);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		/* Make sure pointer to data buffer is set */
46162306a36Sopenharmony_ci		wmb();
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		/* Return ownership to EMAC */
46462306a36Sopenharmony_ci		rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	priv->txbd_curr = 0;
47062306a36Sopenharmony_ci	priv->txbd_dirty = 0;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Clean Tx BD's */
47362306a36Sopenharmony_ci	memset(priv->txbd, 0, TX_RING_SZ);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Initialize logical address filter */
47662306a36Sopenharmony_ci	arc_reg_set(priv, R_LAFL, 0);
47762306a36Sopenharmony_ci	arc_reg_set(priv, R_LAFH, 0);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Set BD ring pointers for device side */
48062306a36Sopenharmony_ci	arc_reg_set(priv, R_RX_RING, (unsigned int)priv->rxbd_dma);
48162306a36Sopenharmony_ci	arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd_dma);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Enable interrupts */
48462306a36Sopenharmony_ci	arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Set CONTROL */
48762306a36Sopenharmony_ci	arc_reg_set(priv, R_CTRL,
48862306a36Sopenharmony_ci		    (RX_BD_NUM << 24) |	/* RX BD table length */
48962306a36Sopenharmony_ci		    (TX_BD_NUM << 16) |	/* TX BD table length */
49062306a36Sopenharmony_ci		    TXRN_MASK | RXRN_MASK);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	napi_enable(&priv->napi);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	/* Enable EMAC */
49562306a36Sopenharmony_ci	arc_reg_or(priv, R_CTRL, EN_MASK);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	phy_start(ndev->phydev);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	netif_start_queue(ndev);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * arc_emac_set_rx_mode - Change the receive filtering mode.
50662306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci * This function enables/disables promiscuous or all-multicast mode
50962306a36Sopenharmony_ci * and updates the multicast filtering list of the network device.
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_cistatic void arc_emac_set_rx_mode(struct net_device *ndev)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (ndev->flags & IFF_PROMISC) {
51662306a36Sopenharmony_ci		arc_reg_or(priv, R_CTRL, PROM_MASK);
51762306a36Sopenharmony_ci	} else {
51862306a36Sopenharmony_ci		arc_reg_clr(priv, R_CTRL, PROM_MASK);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci		if (ndev->flags & IFF_ALLMULTI) {
52162306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFL, ~0);
52262306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFH, ~0);
52362306a36Sopenharmony_ci		} else if (ndev->flags & IFF_MULTICAST) {
52462306a36Sopenharmony_ci			struct netdev_hw_addr *ha;
52562306a36Sopenharmony_ci			unsigned int filter[2] = { 0, 0 };
52662306a36Sopenharmony_ci			int bit;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci			netdev_for_each_mc_addr(ha, ndev) {
52962306a36Sopenharmony_ci				bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
53062306a36Sopenharmony_ci				filter[bit >> 5] |= 1 << (bit & 31);
53162306a36Sopenharmony_ci			}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFL, filter[0]);
53462306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFH, filter[1]);
53562306a36Sopenharmony_ci		} else {
53662306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFL, 0);
53762306a36Sopenharmony_ci			arc_reg_set(priv, R_LAFH, 0);
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci/**
54362306a36Sopenharmony_ci * arc_free_tx_queue - free skb from tx queue
54462306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
54562306a36Sopenharmony_ci *
54662306a36Sopenharmony_ci * This function must be called while EMAC disable
54762306a36Sopenharmony_ci */
54862306a36Sopenharmony_cistatic void arc_free_tx_queue(struct net_device *ndev)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
55162306a36Sopenharmony_ci	unsigned int i;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	for (i = 0; i < TX_BD_NUM; i++) {
55462306a36Sopenharmony_ci		struct arc_emac_bd *txbd = &priv->txbd[i];
55562306a36Sopenharmony_ci		struct buffer_state *tx_buff = &priv->tx_buff[i];
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		if (tx_buff->skb) {
55862306a36Sopenharmony_ci			dma_unmap_single(&ndev->dev,
55962306a36Sopenharmony_ci					 dma_unmap_addr(tx_buff, addr),
56062306a36Sopenharmony_ci					 dma_unmap_len(tx_buff, len),
56162306a36Sopenharmony_ci					 DMA_TO_DEVICE);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci			/* return the sk_buff to system */
56462306a36Sopenharmony_ci			dev_kfree_skb_irq(tx_buff->skb);
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		txbd->info = 0;
56862306a36Sopenharmony_ci		txbd->data = 0;
56962306a36Sopenharmony_ci		tx_buff->skb = NULL;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/**
57462306a36Sopenharmony_ci * arc_free_rx_queue - free skb from rx queue
57562306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
57662306a36Sopenharmony_ci *
57762306a36Sopenharmony_ci * This function must be called while EMAC disable
57862306a36Sopenharmony_ci */
57962306a36Sopenharmony_cistatic void arc_free_rx_queue(struct net_device *ndev)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
58262306a36Sopenharmony_ci	unsigned int i;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	for (i = 0; i < RX_BD_NUM; i++) {
58562306a36Sopenharmony_ci		struct arc_emac_bd *rxbd = &priv->rxbd[i];
58662306a36Sopenharmony_ci		struct buffer_state *rx_buff = &priv->rx_buff[i];
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		if (rx_buff->skb) {
58962306a36Sopenharmony_ci			dma_unmap_single(&ndev->dev,
59062306a36Sopenharmony_ci					 dma_unmap_addr(rx_buff, addr),
59162306a36Sopenharmony_ci					 dma_unmap_len(rx_buff, len),
59262306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci			/* return the sk_buff to system */
59562306a36Sopenharmony_ci			dev_kfree_skb_irq(rx_buff->skb);
59662306a36Sopenharmony_ci		}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		rxbd->info = 0;
59962306a36Sopenharmony_ci		rxbd->data = 0;
60062306a36Sopenharmony_ci		rx_buff->skb = NULL;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/**
60562306a36Sopenharmony_ci * arc_emac_stop - Close the network device.
60662306a36Sopenharmony_ci * @ndev:	Pointer to the network device.
60762306a36Sopenharmony_ci *
60862306a36Sopenharmony_ci * This function stops the Tx queue, disables interrupts and frees the IRQ for
60962306a36Sopenharmony_ci * the EMAC device.
61062306a36Sopenharmony_ci * It also disconnects the PHY device associated with the EMAC device.
61162306a36Sopenharmony_ci */
61262306a36Sopenharmony_cistatic int arc_emac_stop(struct net_device *ndev)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	napi_disable(&priv->napi);
61762306a36Sopenharmony_ci	netif_stop_queue(ndev);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	phy_stop(ndev->phydev);
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Disable interrupts */
62262306a36Sopenharmony_ci	arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Disable EMAC */
62562306a36Sopenharmony_ci	arc_reg_clr(priv, R_CTRL, EN_MASK);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* Return the sk_buff to system */
62862306a36Sopenharmony_ci	arc_free_tx_queue(ndev);
62962306a36Sopenharmony_ci	arc_free_rx_queue(ndev);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return 0;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/**
63562306a36Sopenharmony_ci * arc_emac_stats - Get system network statistics.
63662306a36Sopenharmony_ci * @ndev:	Pointer to net_device structure.
63762306a36Sopenharmony_ci *
63862306a36Sopenharmony_ci * Returns the address of the device statistics structure.
63962306a36Sopenharmony_ci * Statistics are updated in interrupt handler.
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_cistatic struct net_device_stats *arc_emac_stats(struct net_device *ndev)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
64462306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
64562306a36Sopenharmony_ci	unsigned long miss, rxerr;
64662306a36Sopenharmony_ci	u8 rxcrc, rxfram, rxoflow;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	rxerr = arc_reg_get(priv, R_RXERR);
64962306a36Sopenharmony_ci	miss = arc_reg_get(priv, R_MISS);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	rxcrc = rxerr;
65262306a36Sopenharmony_ci	rxfram = rxerr >> 8;
65362306a36Sopenharmony_ci	rxoflow = rxerr >> 16;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	stats->rx_errors += miss;
65662306a36Sopenharmony_ci	stats->rx_errors += rxcrc + rxfram + rxoflow;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	stats->rx_over_errors += rxoflow;
65962306a36Sopenharmony_ci	stats->rx_frame_errors += rxfram;
66062306a36Sopenharmony_ci	stats->rx_crc_errors += rxcrc;
66162306a36Sopenharmony_ci	stats->rx_missed_errors += miss;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	return stats;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci/**
66762306a36Sopenharmony_ci * arc_emac_tx - Starts the data transmission.
66862306a36Sopenharmony_ci * @skb:	sk_buff pointer that contains data to be Transmitted.
66962306a36Sopenharmony_ci * @ndev:	Pointer to net_device structure.
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * returns: NETDEV_TX_OK, on success
67262306a36Sopenharmony_ci *		NETDEV_TX_BUSY, if any of the descriptors are not free.
67362306a36Sopenharmony_ci *
67462306a36Sopenharmony_ci * This function is invoked from upper layers to initiate transmission.
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_cistatic netdev_tx_t arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
67962306a36Sopenharmony_ci	unsigned int len, *txbd_curr = &priv->txbd_curr;
68062306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
68162306a36Sopenharmony_ci	__le32 *info = &priv->txbd[*txbd_curr].info;
68262306a36Sopenharmony_ci	dma_addr_t addr;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (skb_padto(skb, ETH_ZLEN))
68562306a36Sopenharmony_ci		return NETDEV_TX_OK;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	len = max_t(unsigned int, ETH_ZLEN, skb->len);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (unlikely(!arc_emac_tx_avail(priv))) {
69062306a36Sopenharmony_ci		netif_stop_queue(ndev);
69162306a36Sopenharmony_ci		netdev_err(ndev, "BUG! Tx Ring full when queue awake!\n");
69262306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	addr = dma_map_single(&ndev->dev, (void *)skb->data, len,
69662306a36Sopenharmony_ci			      DMA_TO_DEVICE);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(&ndev->dev, addr))) {
69962306a36Sopenharmony_ci		stats->tx_dropped++;
70062306a36Sopenharmony_ci		stats->tx_errors++;
70162306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
70262306a36Sopenharmony_ci		return NETDEV_TX_OK;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci	dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
70562306a36Sopenharmony_ci	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	/* Make sure pointer to data buffer is set */
71062306a36Sopenharmony_ci	wmb();
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	skb_tx_timestamp(skb);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* Make sure info word is set */
71762306a36Sopenharmony_ci	wmb();
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	priv->tx_buff[*txbd_curr].skb = skb;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* Increment index to point to the next BD */
72262306a36Sopenharmony_ci	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Ensure that tx_clean() sees the new txbd_curr before
72562306a36Sopenharmony_ci	 * checking the queue status. This prevents an unneeded wake
72662306a36Sopenharmony_ci	 * of the queue in tx_clean().
72762306a36Sopenharmony_ci	 */
72862306a36Sopenharmony_ci	smp_mb();
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (!arc_emac_tx_avail(priv)) {
73162306a36Sopenharmony_ci		netif_stop_queue(ndev);
73262306a36Sopenharmony_ci		/* Refresh tx_dirty */
73362306a36Sopenharmony_ci		smp_mb();
73462306a36Sopenharmony_ci		if (arc_emac_tx_avail(priv))
73562306a36Sopenharmony_ci			netif_start_queue(ndev);
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	arc_reg_set(priv, R_STATUS, TXPL_MASK);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	return NETDEV_TX_OK;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic void arc_emac_set_address_internal(struct net_device *ndev)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
74662306a36Sopenharmony_ci	unsigned int addr_low, addr_hi;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	addr_low = le32_to_cpu(*(__le32 *)&ndev->dev_addr[0]);
74962306a36Sopenharmony_ci	addr_hi = le16_to_cpu(*(__le16 *)&ndev->dev_addr[4]);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	arc_reg_set(priv, R_ADDRL, addr_low);
75262306a36Sopenharmony_ci	arc_reg_set(priv, R_ADDRH, addr_hi);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/**
75662306a36Sopenharmony_ci * arc_emac_set_address - Set the MAC address for this device.
75762306a36Sopenharmony_ci * @ndev:	Pointer to net_device structure.
75862306a36Sopenharmony_ci * @p:		6 byte Address to be written as MAC address.
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci * This function copies the HW address from the sockaddr structure to the
76162306a36Sopenharmony_ci * net_device structure and updates the address in HW.
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci * returns:	-EBUSY if the net device is busy or 0 if the address is set
76462306a36Sopenharmony_ci *		successfully.
76562306a36Sopenharmony_ci */
76662306a36Sopenharmony_cistatic int arc_emac_set_address(struct net_device *ndev, void *p)
76762306a36Sopenharmony_ci{
76862306a36Sopenharmony_ci	struct sockaddr *addr = p;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	if (netif_running(ndev))
77162306a36Sopenharmony_ci		return -EBUSY;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
77462306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	eth_hw_addr_set(ndev, addr->sa_data);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	arc_emac_set_address_internal(ndev);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return 0;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/**
78462306a36Sopenharmony_ci * arc_emac_restart - Restart EMAC
78562306a36Sopenharmony_ci * @ndev:	Pointer to net_device structure.
78662306a36Sopenharmony_ci *
78762306a36Sopenharmony_ci * This function do hardware reset of EMAC in order to restore
78862306a36Sopenharmony_ci * network packets reception.
78962306a36Sopenharmony_ci */
79062306a36Sopenharmony_cistatic void arc_emac_restart(struct net_device *ndev)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
79362306a36Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
79462306a36Sopenharmony_ci	int i;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (net_ratelimit())
79762306a36Sopenharmony_ci		netdev_warn(ndev, "restarting stalled EMAC\n");
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	netif_stop_queue(ndev);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/* Disable interrupts */
80262306a36Sopenharmony_ci	arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	/* Disable EMAC */
80562306a36Sopenharmony_ci	arc_reg_clr(priv, R_CTRL, EN_MASK);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* Return the sk_buff to system */
80862306a36Sopenharmony_ci	arc_free_tx_queue(ndev);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* Clean Tx BD's */
81162306a36Sopenharmony_ci	priv->txbd_curr = 0;
81262306a36Sopenharmony_ci	priv->txbd_dirty = 0;
81362306a36Sopenharmony_ci	memset(priv->txbd, 0, TX_RING_SZ);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	for (i = 0; i < RX_BD_NUM; i++) {
81662306a36Sopenharmony_ci		struct arc_emac_bd *rxbd = &priv->rxbd[i];
81762306a36Sopenharmony_ci		unsigned int info = le32_to_cpu(rxbd->info);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		if (!(info & FOR_EMAC)) {
82062306a36Sopenharmony_ci			stats->rx_errors++;
82162306a36Sopenharmony_ci			stats->rx_dropped++;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci		/* Return ownership to EMAC */
82462306a36Sopenharmony_ci		rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci	priv->last_rx_bd = 0;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/* Make sure info is visible to EMAC before enable */
82962306a36Sopenharmony_ci	wmb();
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Enable interrupts */
83262306a36Sopenharmony_ci	arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	/* Enable EMAC */
83562306a36Sopenharmony_ci	arc_reg_or(priv, R_CTRL, EN_MASK);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	netif_start_queue(ndev);
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_cistatic const struct net_device_ops arc_emac_netdev_ops = {
84162306a36Sopenharmony_ci	.ndo_open		= arc_emac_open,
84262306a36Sopenharmony_ci	.ndo_stop		= arc_emac_stop,
84362306a36Sopenharmony_ci	.ndo_start_xmit		= arc_emac_tx,
84462306a36Sopenharmony_ci	.ndo_set_mac_address	= arc_emac_set_address,
84562306a36Sopenharmony_ci	.ndo_get_stats		= arc_emac_stats,
84662306a36Sopenharmony_ci	.ndo_set_rx_mode	= arc_emac_set_rx_mode,
84762306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl_running,
84862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
84962306a36Sopenharmony_ci	.ndo_poll_controller	= arc_emac_poll_controller,
85062306a36Sopenharmony_ci#endif
85162306a36Sopenharmony_ci};
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ciint arc_emac_probe(struct net_device *ndev, int interface)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct device *dev = ndev->dev.parent;
85662306a36Sopenharmony_ci	struct resource res_regs;
85762306a36Sopenharmony_ci	struct device_node *phy_node;
85862306a36Sopenharmony_ci	struct phy_device *phydev = NULL;
85962306a36Sopenharmony_ci	struct arc_emac_priv *priv;
86062306a36Sopenharmony_ci	unsigned int id, clock_frequency, irq;
86162306a36Sopenharmony_ci	int err;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* Get PHY from device tree */
86462306a36Sopenharmony_ci	phy_node = of_parse_phandle(dev->of_node, "phy", 0);
86562306a36Sopenharmony_ci	if (!phy_node) {
86662306a36Sopenharmony_ci		dev_err(dev, "failed to retrieve phy description from device tree\n");
86762306a36Sopenharmony_ci		return -ENODEV;
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* Get EMAC registers base address from device tree */
87162306a36Sopenharmony_ci	err = of_address_to_resource(dev->of_node, 0, &res_regs);
87262306a36Sopenharmony_ci	if (err) {
87362306a36Sopenharmony_ci		dev_err(dev, "failed to retrieve registers base from device tree\n");
87462306a36Sopenharmony_ci		err = -ENODEV;
87562306a36Sopenharmony_ci		goto out_put_node;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Get IRQ from device tree */
87962306a36Sopenharmony_ci	irq = irq_of_parse_and_map(dev->of_node, 0);
88062306a36Sopenharmony_ci	if (!irq) {
88162306a36Sopenharmony_ci		dev_err(dev, "failed to retrieve <irq> value from device tree\n");
88262306a36Sopenharmony_ci		err = -ENODEV;
88362306a36Sopenharmony_ci		goto out_put_node;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	ndev->netdev_ops = &arc_emac_netdev_ops;
88762306a36Sopenharmony_ci	ndev->ethtool_ops = &arc_emac_ethtool_ops;
88862306a36Sopenharmony_ci	ndev->watchdog_timeo = TX_TIMEOUT;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	priv = netdev_priv(ndev);
89162306a36Sopenharmony_ci	priv->dev = dev;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	priv->regs = devm_ioremap_resource(dev, &res_regs);
89462306a36Sopenharmony_ci	if (IS_ERR(priv->regs)) {
89562306a36Sopenharmony_ci		err = PTR_ERR(priv->regs);
89662306a36Sopenharmony_ci		goto out_put_node;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (priv->clk) {
90262306a36Sopenharmony_ci		err = clk_prepare_enable(priv->clk);
90362306a36Sopenharmony_ci		if (err) {
90462306a36Sopenharmony_ci			dev_err(dev, "failed to enable clock\n");
90562306a36Sopenharmony_ci			goto out_put_node;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci		clock_frequency = clk_get_rate(priv->clk);
90962306a36Sopenharmony_ci	} else {
91062306a36Sopenharmony_ci		/* Get CPU clock frequency from device tree */
91162306a36Sopenharmony_ci		if (of_property_read_u32(dev->of_node, "clock-frequency",
91262306a36Sopenharmony_ci					 &clock_frequency)) {
91362306a36Sopenharmony_ci			dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
91462306a36Sopenharmony_ci			err = -EINVAL;
91562306a36Sopenharmony_ci			goto out_put_node;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	id = arc_reg_get(priv, R_ID);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/* Check for EMAC revision 5 or 7, magic number */
92262306a36Sopenharmony_ci	if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
92362306a36Sopenharmony_ci		dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
92462306a36Sopenharmony_ci		err = -ENODEV;
92562306a36Sopenharmony_ci		goto out_clken;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci	dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* Set poll rate so that it polls every 1 ms */
93062306a36Sopenharmony_ci	arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	ndev->irq = irq;
93362306a36Sopenharmony_ci	dev_info(dev, "IRQ is %d\n", ndev->irq);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Register interrupt handler for device */
93662306a36Sopenharmony_ci	err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
93762306a36Sopenharmony_ci			       ndev->name, ndev);
93862306a36Sopenharmony_ci	if (err) {
93962306a36Sopenharmony_ci		dev_err(dev, "could not allocate IRQ\n");
94062306a36Sopenharmony_ci		goto out_clken;
94162306a36Sopenharmony_ci	}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	/* Get MAC address from device tree */
94462306a36Sopenharmony_ci	err = of_get_ethdev_address(dev->of_node, ndev);
94562306a36Sopenharmony_ci	if (err)
94662306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	arc_emac_set_address_internal(ndev);
94962306a36Sopenharmony_ci	dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	/* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
95262306a36Sopenharmony_ci	priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
95362306a36Sopenharmony_ci					 &priv->rxbd_dma, GFP_KERNEL);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!priv->rxbd) {
95662306a36Sopenharmony_ci		dev_err(dev, "failed to allocate data buffers\n");
95762306a36Sopenharmony_ci		err = -ENOMEM;
95862306a36Sopenharmony_ci		goto out_clken;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	priv->txbd = priv->rxbd + RX_BD_NUM;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ;
96462306a36Sopenharmony_ci	dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
96562306a36Sopenharmony_ci		(unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	err = arc_mdio_probe(priv);
96862306a36Sopenharmony_ci	if (err) {
96962306a36Sopenharmony_ci		dev_err(dev, "failed to probe MII bus\n");
97062306a36Sopenharmony_ci		goto out_clken;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	phydev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
97462306a36Sopenharmony_ci				interface);
97562306a36Sopenharmony_ci	if (!phydev) {
97662306a36Sopenharmony_ci		dev_err(dev, "of_phy_connect() failed\n");
97762306a36Sopenharmony_ci		err = -ENODEV;
97862306a36Sopenharmony_ci		goto out_mdio;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	dev_info(dev, "connected to %s phy with id 0x%x\n",
98262306a36Sopenharmony_ci		 phydev->drv->name, phydev->phy_id);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	netif_napi_add_weight(ndev, &priv->napi, arc_emac_poll,
98562306a36Sopenharmony_ci			      ARC_EMAC_NAPI_WEIGHT);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	err = register_netdev(ndev);
98862306a36Sopenharmony_ci	if (err) {
98962306a36Sopenharmony_ci		dev_err(dev, "failed to register network device\n");
99062306a36Sopenharmony_ci		goto out_netif_api;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	of_node_put(phy_node);
99462306a36Sopenharmony_ci	return 0;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ciout_netif_api:
99762306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
99862306a36Sopenharmony_ci	phy_disconnect(phydev);
99962306a36Sopenharmony_ciout_mdio:
100062306a36Sopenharmony_ci	arc_mdio_remove(priv);
100162306a36Sopenharmony_ciout_clken:
100262306a36Sopenharmony_ci	if (priv->clk)
100362306a36Sopenharmony_ci		clk_disable_unprepare(priv->clk);
100462306a36Sopenharmony_ciout_put_node:
100562306a36Sopenharmony_ci	of_node_put(phy_node);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	return err;
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arc_emac_probe);
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_civoid arc_emac_remove(struct net_device *ndev)
101262306a36Sopenharmony_ci{
101362306a36Sopenharmony_ci	struct arc_emac_priv *priv = netdev_priv(ndev);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	phy_disconnect(ndev->phydev);
101662306a36Sopenharmony_ci	arc_mdio_remove(priv);
101762306a36Sopenharmony_ci	unregister_netdev(ndev);
101862306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (!IS_ERR(priv->clk))
102162306a36Sopenharmony_ci		clk_disable_unprepare(priv->clk);
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arc_emac_remove);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ciMODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
102662306a36Sopenharmony_ciMODULE_DESCRIPTION("ARC EMAC driver");
102762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1028