162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Faraday FTGMAC100 Gigabit Ethernet
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright 2009-2011 Faraday Technology
662306a36Sopenharmony_ci * Po-Yu Chuang <ratbert@faraday-tech.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1362306a36Sopenharmony_ci#include <linux/etherdevice.h>
1462306a36Sopenharmony_ci#include <linux/ethtool.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/io.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/netdevice.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/of_mdio.h>
2162306a36Sopenharmony_ci#include <linux/phy.h>
2262306a36Sopenharmony_ci#include <linux/platform_device.h>
2362306a36Sopenharmony_ci#include <linux/property.h>
2462306a36Sopenharmony_ci#include <linux/crc32.h>
2562306a36Sopenharmony_ci#include <linux/if_vlan.h>
2662306a36Sopenharmony_ci#include <linux/of_net.h>
2762306a36Sopenharmony_ci#include <net/ip.h>
2862306a36Sopenharmony_ci#include <net/ncsi.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "ftgmac100.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define DRV_NAME	"ftgmac100"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Arbitrary values, I am not sure the HW has limits */
3562306a36Sopenharmony_ci#define MAX_RX_QUEUE_ENTRIES	1024
3662306a36Sopenharmony_ci#define MAX_TX_QUEUE_ENTRIES	1024
3762306a36Sopenharmony_ci#define MIN_RX_QUEUE_ENTRIES	32
3862306a36Sopenharmony_ci#define MIN_TX_QUEUE_ENTRIES	32
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* Defaults */
4162306a36Sopenharmony_ci#define DEF_RX_QUEUE_ENTRIES	128
4262306a36Sopenharmony_ci#define DEF_TX_QUEUE_ENTRIES	128
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define MAX_PKT_SIZE		1536
4562306a36Sopenharmony_ci#define RX_BUF_SIZE		MAX_PKT_SIZE	/* must be smaller than 0x3fff */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* Min number of tx ring entries before stopping queue */
4862306a36Sopenharmony_ci#define TX_THRESHOLD		(MAX_SKB_FRAGS + 1)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define FTGMAC_100MHZ		100000000
5162306a36Sopenharmony_ci#define FTGMAC_25MHZ		25000000
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct ftgmac100 {
5462306a36Sopenharmony_ci	/* Registers */
5562306a36Sopenharmony_ci	struct resource *res;
5662306a36Sopenharmony_ci	void __iomem *base;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Rx ring */
5962306a36Sopenharmony_ci	unsigned int rx_q_entries;
6062306a36Sopenharmony_ci	struct ftgmac100_rxdes *rxdes;
6162306a36Sopenharmony_ci	dma_addr_t rxdes_dma;
6262306a36Sopenharmony_ci	struct sk_buff **rx_skbs;
6362306a36Sopenharmony_ci	unsigned int rx_pointer;
6462306a36Sopenharmony_ci	u32 rxdes0_edorr_mask;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Tx ring */
6762306a36Sopenharmony_ci	unsigned int tx_q_entries;
6862306a36Sopenharmony_ci	struct ftgmac100_txdes *txdes;
6962306a36Sopenharmony_ci	dma_addr_t txdes_dma;
7062306a36Sopenharmony_ci	struct sk_buff **tx_skbs;
7162306a36Sopenharmony_ci	unsigned int tx_clean_pointer;
7262306a36Sopenharmony_ci	unsigned int tx_pointer;
7362306a36Sopenharmony_ci	u32 txdes0_edotr_mask;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Used to signal the reset task of ring change request */
7662306a36Sopenharmony_ci	unsigned int new_rx_q_entries;
7762306a36Sopenharmony_ci	unsigned int new_tx_q_entries;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* Scratch page to use when rx skb alloc fails */
8062306a36Sopenharmony_ci	void *rx_scratch;
8162306a36Sopenharmony_ci	dma_addr_t rx_scratch_dma;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Component structures */
8462306a36Sopenharmony_ci	struct net_device *netdev;
8562306a36Sopenharmony_ci	struct device *dev;
8662306a36Sopenharmony_ci	struct ncsi_dev *ndev;
8762306a36Sopenharmony_ci	struct napi_struct napi;
8862306a36Sopenharmony_ci	struct work_struct reset_task;
8962306a36Sopenharmony_ci	struct mii_bus *mii_bus;
9062306a36Sopenharmony_ci	struct clk *clk;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* AST2500/AST2600 RMII ref clock gate */
9362306a36Sopenharmony_ci	struct clk *rclk;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Link management */
9662306a36Sopenharmony_ci	int cur_speed;
9762306a36Sopenharmony_ci	int cur_duplex;
9862306a36Sopenharmony_ci	bool use_ncsi;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* Multicast filter settings */
10162306a36Sopenharmony_ci	u32 maht0;
10262306a36Sopenharmony_ci	u32 maht1;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Flow control settings */
10562306a36Sopenharmony_ci	bool tx_pause;
10662306a36Sopenharmony_ci	bool rx_pause;
10762306a36Sopenharmony_ci	bool aneg_pause;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Misc */
11062306a36Sopenharmony_ci	bool need_mac_restart;
11162306a36Sopenharmony_ci	bool is_aspeed;
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int ftgmac100_reset_mac(struct ftgmac100 *priv, u32 maccr)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
11762306a36Sopenharmony_ci	int i;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* NOTE: reset clears all registers */
12062306a36Sopenharmony_ci	iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
12162306a36Sopenharmony_ci	iowrite32(maccr | FTGMAC100_MACCR_SW_RST,
12262306a36Sopenharmony_ci		  priv->base + FTGMAC100_OFFSET_MACCR);
12362306a36Sopenharmony_ci	for (i = 0; i < 200; i++) {
12462306a36Sopenharmony_ci		unsigned int maccr;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
12762306a36Sopenharmony_ci		if (!(maccr & FTGMAC100_MACCR_SW_RST))
12862306a36Sopenharmony_ci			return 0;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		udelay(1);
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	netdev_err(netdev, "Hardware reset failed\n");
13462306a36Sopenharmony_ci	return -EIO;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int ftgmac100_reset_and_config_mac(struct ftgmac100 *priv)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	u32 maccr = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	switch (priv->cur_speed) {
14262306a36Sopenharmony_ci	case SPEED_10:
14362306a36Sopenharmony_ci	case 0: /* no link */
14462306a36Sopenharmony_ci		break;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	case SPEED_100:
14762306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_FAST_MODE;
14862306a36Sopenharmony_ci		break;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	case SPEED_1000:
15162306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_GIGA_MODE;
15262306a36Sopenharmony_ci		break;
15362306a36Sopenharmony_ci	default:
15462306a36Sopenharmony_ci		netdev_err(priv->netdev, "Unknown speed %d !\n",
15562306a36Sopenharmony_ci			   priv->cur_speed);
15662306a36Sopenharmony_ci		break;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* (Re)initialize the queue pointers */
16062306a36Sopenharmony_ci	priv->rx_pointer = 0;
16162306a36Sopenharmony_ci	priv->tx_clean_pointer = 0;
16262306a36Sopenharmony_ci	priv->tx_pointer = 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* The doc says reset twice with 10us interval */
16562306a36Sopenharmony_ci	if (ftgmac100_reset_mac(priv, maccr))
16662306a36Sopenharmony_ci		return -EIO;
16762306a36Sopenharmony_ci	usleep_range(10, 1000);
16862306a36Sopenharmony_ci	return ftgmac100_reset_mac(priv, maccr);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void ftgmac100_write_mac_addr(struct ftgmac100 *priv, const u8 *mac)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	unsigned int maddr = mac[0] << 8 | mac[1];
17462306a36Sopenharmony_ci	unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	iowrite32(maddr, priv->base + FTGMAC100_OFFSET_MAC_MADR);
17762306a36Sopenharmony_ci	iowrite32(laddr, priv->base + FTGMAC100_OFFSET_MAC_LADR);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic int ftgmac100_initial_mac(struct ftgmac100 *priv)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
18362306a36Sopenharmony_ci	unsigned int m;
18462306a36Sopenharmony_ci	unsigned int l;
18562306a36Sopenharmony_ci	int err;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	err = of_get_ethdev_address(priv->dev->of_node, priv->netdev);
18862306a36Sopenharmony_ci	if (err == -EPROBE_DEFER)
18962306a36Sopenharmony_ci		return err;
19062306a36Sopenharmony_ci	if (!err) {
19162306a36Sopenharmony_ci		dev_info(priv->dev, "Read MAC address %pM from device tree\n",
19262306a36Sopenharmony_ci			 priv->netdev->dev_addr);
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	m = ioread32(priv->base + FTGMAC100_OFFSET_MAC_MADR);
19762306a36Sopenharmony_ci	l = ioread32(priv->base + FTGMAC100_OFFSET_MAC_LADR);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	mac[0] = (m >> 8) & 0xff;
20062306a36Sopenharmony_ci	mac[1] = m & 0xff;
20162306a36Sopenharmony_ci	mac[2] = (l >> 24) & 0xff;
20262306a36Sopenharmony_ci	mac[3] = (l >> 16) & 0xff;
20362306a36Sopenharmony_ci	mac[4] = (l >> 8) & 0xff;
20462306a36Sopenharmony_ci	mac[5] = l & 0xff;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (is_valid_ether_addr(mac)) {
20762306a36Sopenharmony_ci		eth_hw_addr_set(priv->netdev, mac);
20862306a36Sopenharmony_ci		dev_info(priv->dev, "Read MAC address %pM from chip\n", mac);
20962306a36Sopenharmony_ci	} else {
21062306a36Sopenharmony_ci		eth_hw_addr_random(priv->netdev);
21162306a36Sopenharmony_ci		dev_info(priv->dev, "Generated random MAC address %pM\n",
21262306a36Sopenharmony_ci			 priv->netdev->dev_addr);
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int ftgmac100_set_mac_addr(struct net_device *dev, void *p)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	int ret;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ret = eth_prepare_mac_addr_change(dev, p);
22362306a36Sopenharmony_ci	if (ret < 0)
22462306a36Sopenharmony_ci		return ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	eth_commit_mac_addr_change(dev, p);
22762306a36Sopenharmony_ci	ftgmac100_write_mac_addr(netdev_priv(dev), dev->dev_addr);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return 0;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void ftgmac100_config_pause(struct ftgmac100 *priv)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	u32 fcr = FTGMAC100_FCR_PAUSE_TIME(16);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* Throttle tx queue when receiving pause frames */
23762306a36Sopenharmony_ci	if (priv->rx_pause)
23862306a36Sopenharmony_ci		fcr |= FTGMAC100_FCR_FC_EN;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* Enables sending pause frames when the RX queue is past a
24162306a36Sopenharmony_ci	 * certain threshold.
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	if (priv->tx_pause)
24462306a36Sopenharmony_ci		fcr |= FTGMAC100_FCR_FCTHR_EN;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	iowrite32(fcr, priv->base + FTGMAC100_OFFSET_FCR);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void ftgmac100_init_hw(struct ftgmac100 *priv)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	u32 reg, rfifo_sz, tfifo_sz;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Clear stale interrupts */
25462306a36Sopenharmony_ci	reg = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
25562306a36Sopenharmony_ci	iowrite32(reg, priv->base + FTGMAC100_OFFSET_ISR);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/* Setup RX ring buffer base */
25862306a36Sopenharmony_ci	iowrite32(priv->rxdes_dma, priv->base + FTGMAC100_OFFSET_RXR_BADR);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/* Setup TX ring buffer base */
26162306a36Sopenharmony_ci	iowrite32(priv->txdes_dma, priv->base + FTGMAC100_OFFSET_NPTXR_BADR);
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* Configure RX buffer size */
26462306a36Sopenharmony_ci	iowrite32(FTGMAC100_RBSR_SIZE(RX_BUF_SIZE),
26562306a36Sopenharmony_ci		  priv->base + FTGMAC100_OFFSET_RBSR);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* Set RX descriptor autopoll */
26862306a36Sopenharmony_ci	iowrite32(FTGMAC100_APTC_RXPOLL_CNT(1),
26962306a36Sopenharmony_ci		  priv->base + FTGMAC100_OFFSET_APTC);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Write MAC address */
27262306a36Sopenharmony_ci	ftgmac100_write_mac_addr(priv, priv->netdev->dev_addr);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* Write multicast filter */
27562306a36Sopenharmony_ci	iowrite32(priv->maht0, priv->base + FTGMAC100_OFFSET_MAHT0);
27662306a36Sopenharmony_ci	iowrite32(priv->maht1, priv->base + FTGMAC100_OFFSET_MAHT1);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* Configure descriptor sizes and increase burst sizes according
27962306a36Sopenharmony_ci	 * to values in Aspeed SDK. The FIFO arbitration is enabled and
28062306a36Sopenharmony_ci	 * the thresholds set based on the recommended values in the
28162306a36Sopenharmony_ci	 * AST2400 specification.
28262306a36Sopenharmony_ci	 */
28362306a36Sopenharmony_ci	iowrite32(FTGMAC100_DBLAC_RXDES_SIZE(2) |   /* 2*8 bytes RX descs */
28462306a36Sopenharmony_ci		  FTGMAC100_DBLAC_TXDES_SIZE(2) |   /* 2*8 bytes TX descs */
28562306a36Sopenharmony_ci		  FTGMAC100_DBLAC_RXBURST_SIZE(3) | /* 512 bytes max RX bursts */
28662306a36Sopenharmony_ci		  FTGMAC100_DBLAC_TXBURST_SIZE(3) | /* 512 bytes max TX bursts */
28762306a36Sopenharmony_ci		  FTGMAC100_DBLAC_RX_THR_EN |       /* Enable fifo threshold arb */
28862306a36Sopenharmony_ci		  FTGMAC100_DBLAC_RXFIFO_HTHR(6) |  /* 6/8 of FIFO high threshold */
28962306a36Sopenharmony_ci		  FTGMAC100_DBLAC_RXFIFO_LTHR(2),   /* 2/8 of FIFO low threshold */
29062306a36Sopenharmony_ci		  priv->base + FTGMAC100_OFFSET_DBLAC);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* Interrupt mitigation configured for 1 interrupt/packet. HW interrupt
29362306a36Sopenharmony_ci	 * mitigation doesn't seem to provide any benefit with NAPI so leave
29462306a36Sopenharmony_ci	 * it at that.
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	iowrite32(FTGMAC100_ITC_RXINT_THR(1) |
29762306a36Sopenharmony_ci		  FTGMAC100_ITC_TXINT_THR(1),
29862306a36Sopenharmony_ci		  priv->base + FTGMAC100_OFFSET_ITC);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Configure FIFO sizes in the TPAFCR register */
30162306a36Sopenharmony_ci	reg = ioread32(priv->base + FTGMAC100_OFFSET_FEAR);
30262306a36Sopenharmony_ci	rfifo_sz = reg & 0x00000007;
30362306a36Sopenharmony_ci	tfifo_sz = (reg >> 3) & 0x00000007;
30462306a36Sopenharmony_ci	reg = ioread32(priv->base + FTGMAC100_OFFSET_TPAFCR);
30562306a36Sopenharmony_ci	reg &= ~0x3f000000;
30662306a36Sopenharmony_ci	reg |= (tfifo_sz << 27);
30762306a36Sopenharmony_ci	reg |= (rfifo_sz << 24);
30862306a36Sopenharmony_ci	iowrite32(reg, priv->base + FTGMAC100_OFFSET_TPAFCR);
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void ftgmac100_start_hw(struct ftgmac100 *priv)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	u32 maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Keep the original GMAC and FAST bits */
31662306a36Sopenharmony_ci	maccr &= (FTGMAC100_MACCR_FAST_MODE | FTGMAC100_MACCR_GIGA_MODE);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Add all the main enable bits */
31962306a36Sopenharmony_ci	maccr |= FTGMAC100_MACCR_TXDMA_EN	|
32062306a36Sopenharmony_ci		 FTGMAC100_MACCR_RXDMA_EN	|
32162306a36Sopenharmony_ci		 FTGMAC100_MACCR_TXMAC_EN	|
32262306a36Sopenharmony_ci		 FTGMAC100_MACCR_RXMAC_EN	|
32362306a36Sopenharmony_ci		 FTGMAC100_MACCR_CRC_APD	|
32462306a36Sopenharmony_ci		 FTGMAC100_MACCR_PHY_LINK_LEVEL	|
32562306a36Sopenharmony_ci		 FTGMAC100_MACCR_RX_RUNT	|
32662306a36Sopenharmony_ci		 FTGMAC100_MACCR_RX_BROADPKT;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	/* Add other bits as needed */
32962306a36Sopenharmony_ci	if (priv->cur_duplex == DUPLEX_FULL)
33062306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_FULLDUP;
33162306a36Sopenharmony_ci	if (priv->netdev->flags & IFF_PROMISC)
33262306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_RX_ALL;
33362306a36Sopenharmony_ci	if (priv->netdev->flags & IFF_ALLMULTI)
33462306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_RX_MULTIPKT;
33562306a36Sopenharmony_ci	else if (netdev_mc_count(priv->netdev))
33662306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_HT_MULTI_EN;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Vlan filtering enabled */
33962306a36Sopenharmony_ci	if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
34062306a36Sopenharmony_ci		maccr |= FTGMAC100_MACCR_RM_VLAN;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Hit the HW */
34362306a36Sopenharmony_ci	iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void ftgmac100_stop_hw(struct ftgmac100 *priv)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	iowrite32(0, priv->base + FTGMAC100_OFFSET_MACCR);
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void ftgmac100_calc_mc_hash(struct ftgmac100 *priv)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	priv->maht1 = 0;
35662306a36Sopenharmony_ci	priv->maht0 = 0;
35762306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, priv->netdev) {
35862306a36Sopenharmony_ci		u32 crc_val = ether_crc_le(ETH_ALEN, ha->addr);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci		crc_val = (~(crc_val >> 2)) & 0x3f;
36162306a36Sopenharmony_ci		if (crc_val >= 32)
36262306a36Sopenharmony_ci			priv->maht1 |= 1ul << (crc_val - 32);
36362306a36Sopenharmony_ci		else
36462306a36Sopenharmony_ci			priv->maht0 |= 1ul << (crc_val);
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic void ftgmac100_set_rx_mode(struct net_device *netdev)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* Setup the hash filter */
37362306a36Sopenharmony_ci	ftgmac100_calc_mc_hash(priv);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* Interface down ? that's all there is to do */
37662306a36Sopenharmony_ci	if (!netif_running(netdev))
37762306a36Sopenharmony_ci		return;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Update the HW */
38062306a36Sopenharmony_ci	iowrite32(priv->maht0, priv->base + FTGMAC100_OFFSET_MAHT0);
38162306a36Sopenharmony_ci	iowrite32(priv->maht1, priv->base + FTGMAC100_OFFSET_MAHT1);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* Reconfigure MACCR */
38462306a36Sopenharmony_ci	ftgmac100_start_hw(priv);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic int ftgmac100_alloc_rx_buf(struct ftgmac100 *priv, unsigned int entry,
38862306a36Sopenharmony_ci				  struct ftgmac100_rxdes *rxdes, gfp_t gfp)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
39162306a36Sopenharmony_ci	struct sk_buff *skb;
39262306a36Sopenharmony_ci	dma_addr_t map;
39362306a36Sopenharmony_ci	int err = 0;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	skb = netdev_alloc_skb_ip_align(netdev, RX_BUF_SIZE);
39662306a36Sopenharmony_ci	if (unlikely(!skb)) {
39762306a36Sopenharmony_ci		if (net_ratelimit())
39862306a36Sopenharmony_ci			netdev_warn(netdev, "failed to allocate rx skb\n");
39962306a36Sopenharmony_ci		err = -ENOMEM;
40062306a36Sopenharmony_ci		map = priv->rx_scratch_dma;
40162306a36Sopenharmony_ci	} else {
40262306a36Sopenharmony_ci		map = dma_map_single(priv->dev, skb->data, RX_BUF_SIZE,
40362306a36Sopenharmony_ci				     DMA_FROM_DEVICE);
40462306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(priv->dev, map))) {
40562306a36Sopenharmony_ci			if (net_ratelimit())
40662306a36Sopenharmony_ci				netdev_err(netdev, "failed to map rx page\n");
40762306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
40862306a36Sopenharmony_ci			map = priv->rx_scratch_dma;
40962306a36Sopenharmony_ci			skb = NULL;
41062306a36Sopenharmony_ci			err = -ENOMEM;
41162306a36Sopenharmony_ci		}
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Store skb */
41562306a36Sopenharmony_ci	priv->rx_skbs[entry] = skb;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Store DMA address into RX desc */
41862306a36Sopenharmony_ci	rxdes->rxdes3 = cpu_to_le32(map);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* Ensure the above is ordered vs clearing the OWN bit */
42162306a36Sopenharmony_ci	dma_wmb();
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Clean status (which resets own bit) */
42462306a36Sopenharmony_ci	if (entry == (priv->rx_q_entries - 1))
42562306a36Sopenharmony_ci		rxdes->rxdes0 = cpu_to_le32(priv->rxdes0_edorr_mask);
42662306a36Sopenharmony_ci	else
42762306a36Sopenharmony_ci		rxdes->rxdes0 = 0;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	return err;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic unsigned int ftgmac100_next_rx_pointer(struct ftgmac100 *priv,
43362306a36Sopenharmony_ci					      unsigned int pointer)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	return (pointer + 1) & (priv->rx_q_entries - 1);
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void ftgmac100_rx_packet_error(struct ftgmac100 *priv, u32 status)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (status & FTGMAC100_RXDES0_RX_ERR)
44362306a36Sopenharmony_ci		netdev->stats.rx_errors++;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (status & FTGMAC100_RXDES0_CRC_ERR)
44662306a36Sopenharmony_ci		netdev->stats.rx_crc_errors++;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (status & (FTGMAC100_RXDES0_FTL |
44962306a36Sopenharmony_ci		      FTGMAC100_RXDES0_RUNT |
45062306a36Sopenharmony_ci		      FTGMAC100_RXDES0_RX_ODD_NB))
45162306a36Sopenharmony_ci		netdev->stats.rx_length_errors++;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
45762306a36Sopenharmony_ci	struct ftgmac100_rxdes *rxdes;
45862306a36Sopenharmony_ci	struct sk_buff *skb;
45962306a36Sopenharmony_ci	unsigned int pointer, size;
46062306a36Sopenharmony_ci	u32 status, csum_vlan;
46162306a36Sopenharmony_ci	dma_addr_t map;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* Grab next RX descriptor */
46462306a36Sopenharmony_ci	pointer = priv->rx_pointer;
46562306a36Sopenharmony_ci	rxdes = &priv->rxdes[pointer];
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* Grab descriptor status */
46862306a36Sopenharmony_ci	status = le32_to_cpu(rxdes->rxdes0);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* Do we have a packet ? */
47162306a36Sopenharmony_ci	if (!(status & FTGMAC100_RXDES0_RXPKT_RDY))
47262306a36Sopenharmony_ci		return false;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* Order subsequent reads with the test for the ready bit */
47562306a36Sopenharmony_ci	dma_rmb();
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* We don't cope with fragmented RX packets */
47862306a36Sopenharmony_ci	if (unlikely(!(status & FTGMAC100_RXDES0_FRS) ||
47962306a36Sopenharmony_ci		     !(status & FTGMAC100_RXDES0_LRS)))
48062306a36Sopenharmony_ci		goto drop;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* Grab received size and csum vlan field in the descriptor */
48362306a36Sopenharmony_ci	size = status & FTGMAC100_RXDES0_VDBC;
48462306a36Sopenharmony_ci	csum_vlan = le32_to_cpu(rxdes->rxdes1);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Any error (other than csum offload) flagged ? */
48762306a36Sopenharmony_ci	if (unlikely(status & RXDES0_ANY_ERROR)) {
48862306a36Sopenharmony_ci		/* Correct for incorrect flagging of runt packets
48962306a36Sopenharmony_ci		 * with vlan tags... Just accept a runt packet that
49062306a36Sopenharmony_ci		 * has been flagged as vlan and whose size is at
49162306a36Sopenharmony_ci		 * least 60 bytes.
49262306a36Sopenharmony_ci		 */
49362306a36Sopenharmony_ci		if ((status & FTGMAC100_RXDES0_RUNT) &&
49462306a36Sopenharmony_ci		    (csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL) &&
49562306a36Sopenharmony_ci		    (size >= 60))
49662306a36Sopenharmony_ci			status &= ~FTGMAC100_RXDES0_RUNT;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		/* Any error still in there ? */
49962306a36Sopenharmony_ci		if (status & RXDES0_ANY_ERROR) {
50062306a36Sopenharmony_ci			ftgmac100_rx_packet_error(priv, status);
50162306a36Sopenharmony_ci			goto drop;
50262306a36Sopenharmony_ci		}
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* If the packet had no skb (failed to allocate earlier)
50662306a36Sopenharmony_ci	 * then try to allocate one and skip
50762306a36Sopenharmony_ci	 */
50862306a36Sopenharmony_ci	skb = priv->rx_skbs[pointer];
50962306a36Sopenharmony_ci	if (!unlikely(skb)) {
51062306a36Sopenharmony_ci		ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
51162306a36Sopenharmony_ci		goto drop;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (unlikely(status & FTGMAC100_RXDES0_MULTICAST))
51562306a36Sopenharmony_ci		netdev->stats.multicast++;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* If the HW found checksum errors, bounce it to software.
51862306a36Sopenharmony_ci	 *
51962306a36Sopenharmony_ci	 * If we didn't, we need to see if the packet was recognized
52062306a36Sopenharmony_ci	 * by HW as one of the supported checksummed protocols before
52162306a36Sopenharmony_ci	 * we accept the HW test results.
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	if (netdev->features & NETIF_F_RXCSUM) {
52462306a36Sopenharmony_ci		u32 err_bits = FTGMAC100_RXDES1_TCP_CHKSUM_ERR |
52562306a36Sopenharmony_ci			FTGMAC100_RXDES1_UDP_CHKSUM_ERR |
52662306a36Sopenharmony_ci			FTGMAC100_RXDES1_IP_CHKSUM_ERR;
52762306a36Sopenharmony_ci		if ((csum_vlan & err_bits) ||
52862306a36Sopenharmony_ci		    !(csum_vlan & FTGMAC100_RXDES1_PROT_MASK))
52962306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_NONE;
53062306a36Sopenharmony_ci		else
53162306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	/* Transfer received size to skb */
53562306a36Sopenharmony_ci	skb_put(skb, size);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* Extract vlan tag */
53862306a36Sopenharmony_ci	if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
53962306a36Sopenharmony_ci	    (csum_vlan & FTGMAC100_RXDES1_VLANTAG_AVAIL))
54062306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
54162306a36Sopenharmony_ci				       csum_vlan & 0xffff);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* Tear down DMA mapping, do necessary cache management */
54462306a36Sopenharmony_ci	map = le32_to_cpu(rxdes->rxdes3);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci#if defined(CONFIG_ARM) && !defined(CONFIG_ARM_DMA_USE_IOMMU)
54762306a36Sopenharmony_ci	/* When we don't have an iommu, we can save cycles by not
54862306a36Sopenharmony_ci	 * invalidating the cache for the part of the packet that
54962306a36Sopenharmony_ci	 * wasn't received.
55062306a36Sopenharmony_ci	 */
55162306a36Sopenharmony_ci	dma_unmap_single(priv->dev, map, size, DMA_FROM_DEVICE);
55262306a36Sopenharmony_ci#else
55362306a36Sopenharmony_ci	dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
55462306a36Sopenharmony_ci#endif
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* Resplenish rx ring */
55862306a36Sopenharmony_ci	ftgmac100_alloc_rx_buf(priv, pointer, rxdes, GFP_ATOMIC);
55962306a36Sopenharmony_ci	priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, netdev);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	netdev->stats.rx_packets++;
56462306a36Sopenharmony_ci	netdev->stats.rx_bytes += size;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/* push packet to protocol stack */
56762306a36Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_NONE)
56862306a36Sopenharmony_ci		netif_receive_skb(skb);
56962306a36Sopenharmony_ci	else
57062306a36Sopenharmony_ci		napi_gro_receive(&priv->napi, skb);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	(*processed)++;
57362306a36Sopenharmony_ci	return true;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci drop:
57662306a36Sopenharmony_ci	/* Clean rxdes0 (which resets own bit) */
57762306a36Sopenharmony_ci	rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);
57862306a36Sopenharmony_ci	priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer);
57962306a36Sopenharmony_ci	netdev->stats.rx_dropped++;
58062306a36Sopenharmony_ci	return true;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cistatic u32 ftgmac100_base_tx_ctlstat(struct ftgmac100 *priv,
58462306a36Sopenharmony_ci				     unsigned int index)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	if (index == (priv->tx_q_entries - 1))
58762306a36Sopenharmony_ci		return priv->txdes0_edotr_mask;
58862306a36Sopenharmony_ci	else
58962306a36Sopenharmony_ci		return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic unsigned int ftgmac100_next_tx_pointer(struct ftgmac100 *priv,
59362306a36Sopenharmony_ci					      unsigned int pointer)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	return (pointer + 1) & (priv->tx_q_entries - 1);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic u32 ftgmac100_tx_buf_avail(struct ftgmac100 *priv)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	/* Returns the number of available slots in the TX queue
60162306a36Sopenharmony_ci	 *
60262306a36Sopenharmony_ci	 * This always leaves one free slot so we don't have to
60362306a36Sopenharmony_ci	 * worry about empty vs. full, and this simplifies the
60462306a36Sopenharmony_ci	 * test for ftgmac100_tx_buf_cleanable() below
60562306a36Sopenharmony_ci	 */
60662306a36Sopenharmony_ci	return (priv->tx_clean_pointer - priv->tx_pointer - 1) &
60762306a36Sopenharmony_ci		(priv->tx_q_entries - 1);
60862306a36Sopenharmony_ci}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic bool ftgmac100_tx_buf_cleanable(struct ftgmac100 *priv)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	return priv->tx_pointer != priv->tx_clean_pointer;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cistatic void ftgmac100_free_tx_packet(struct ftgmac100 *priv,
61662306a36Sopenharmony_ci				     unsigned int pointer,
61762306a36Sopenharmony_ci				     struct sk_buff *skb,
61862306a36Sopenharmony_ci				     struct ftgmac100_txdes *txdes,
61962306a36Sopenharmony_ci				     u32 ctl_stat)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	dma_addr_t map = le32_to_cpu(txdes->txdes3);
62262306a36Sopenharmony_ci	size_t len;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (ctl_stat & FTGMAC100_TXDES0_FTS) {
62562306a36Sopenharmony_ci		len = skb_headlen(skb);
62662306a36Sopenharmony_ci		dma_unmap_single(priv->dev, map, len, DMA_TO_DEVICE);
62762306a36Sopenharmony_ci	} else {
62862306a36Sopenharmony_ci		len = FTGMAC100_TXDES0_TXBUF_SIZE(ctl_stat);
62962306a36Sopenharmony_ci		dma_unmap_page(priv->dev, map, len, DMA_TO_DEVICE);
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* Free SKB on last segment */
63362306a36Sopenharmony_ci	if (ctl_stat & FTGMAC100_TXDES0_LTS)
63462306a36Sopenharmony_ci		dev_kfree_skb(skb);
63562306a36Sopenharmony_ci	priv->tx_skbs[pointer] = NULL;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
64162306a36Sopenharmony_ci	struct ftgmac100_txdes *txdes;
64262306a36Sopenharmony_ci	struct sk_buff *skb;
64362306a36Sopenharmony_ci	unsigned int pointer;
64462306a36Sopenharmony_ci	u32 ctl_stat;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	pointer = priv->tx_clean_pointer;
64762306a36Sopenharmony_ci	txdes = &priv->txdes[pointer];
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	ctl_stat = le32_to_cpu(txdes->txdes0);
65062306a36Sopenharmony_ci	if (ctl_stat & FTGMAC100_TXDES0_TXDMA_OWN)
65162306a36Sopenharmony_ci		return false;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	skb = priv->tx_skbs[pointer];
65462306a36Sopenharmony_ci	netdev->stats.tx_packets++;
65562306a36Sopenharmony_ci	netdev->stats.tx_bytes += skb->len;
65662306a36Sopenharmony_ci	ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
65762306a36Sopenharmony_ci	txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return true;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic void ftgmac100_tx_complete(struct ftgmac100 *priv)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Process all completed packets */
66962306a36Sopenharmony_ci	while (ftgmac100_tx_buf_cleanable(priv) &&
67062306a36Sopenharmony_ci	       ftgmac100_tx_complete_packet(priv))
67162306a36Sopenharmony_ci		;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Restart queue if needed */
67462306a36Sopenharmony_ci	smp_mb();
67562306a36Sopenharmony_ci	if (unlikely(netif_queue_stopped(netdev) &&
67662306a36Sopenharmony_ci		     ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)) {
67762306a36Sopenharmony_ci		struct netdev_queue *txq;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		txq = netdev_get_tx_queue(netdev, 0);
68062306a36Sopenharmony_ci		__netif_tx_lock(txq, smp_processor_id());
68162306a36Sopenharmony_ci		if (netif_queue_stopped(netdev) &&
68262306a36Sopenharmony_ci		    ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)
68362306a36Sopenharmony_ci			netif_wake_queue(netdev);
68462306a36Sopenharmony_ci		__netif_tx_unlock(txq);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic bool ftgmac100_prep_tx_csum(struct sk_buff *skb, u32 *csum_vlan)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
69162306a36Sopenharmony_ci		u8 ip_proto = ip_hdr(skb)->protocol;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		*csum_vlan |= FTGMAC100_TXDES1_IP_CHKSUM;
69462306a36Sopenharmony_ci		switch(ip_proto) {
69562306a36Sopenharmony_ci		case IPPROTO_TCP:
69662306a36Sopenharmony_ci			*csum_vlan |= FTGMAC100_TXDES1_TCP_CHKSUM;
69762306a36Sopenharmony_ci			return true;
69862306a36Sopenharmony_ci		case IPPROTO_UDP:
69962306a36Sopenharmony_ci			*csum_vlan |= FTGMAC100_TXDES1_UDP_CHKSUM;
70062306a36Sopenharmony_ci			return true;
70162306a36Sopenharmony_ci		case IPPROTO_IP:
70262306a36Sopenharmony_ci			return true;
70362306a36Sopenharmony_ci		}
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci	return skb_checksum_help(skb) == 0;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,
70962306a36Sopenharmony_ci					     struct net_device *netdev)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
71262306a36Sopenharmony_ci	struct ftgmac100_txdes *txdes, *first;
71362306a36Sopenharmony_ci	unsigned int pointer, nfrags, len, i, j;
71462306a36Sopenharmony_ci	u32 f_ctl_stat, ctl_stat, csum_vlan;
71562306a36Sopenharmony_ci	dma_addr_t map;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* The HW doesn't pad small frames */
71862306a36Sopenharmony_ci	if (eth_skb_pad(skb)) {
71962306a36Sopenharmony_ci		netdev->stats.tx_dropped++;
72062306a36Sopenharmony_ci		return NETDEV_TX_OK;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	/* Reject oversize packets */
72462306a36Sopenharmony_ci	if (unlikely(skb->len > MAX_PKT_SIZE)) {
72562306a36Sopenharmony_ci		if (net_ratelimit())
72662306a36Sopenharmony_ci			netdev_dbg(netdev, "tx packet too big\n");
72762306a36Sopenharmony_ci		goto drop;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Do we have a limit on #fragments ? I yet have to get a reply
73162306a36Sopenharmony_ci	 * from Aspeed. If there's one I haven't hit it.
73262306a36Sopenharmony_ci	 */
73362306a36Sopenharmony_ci	nfrags = skb_shinfo(skb)->nr_frags;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Setup HW checksumming */
73662306a36Sopenharmony_ci	csum_vlan = 0;
73762306a36Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL &&
73862306a36Sopenharmony_ci	    !ftgmac100_prep_tx_csum(skb, &csum_vlan))
73962306a36Sopenharmony_ci		goto drop;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Add VLAN tag */
74262306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
74362306a36Sopenharmony_ci		csum_vlan |= FTGMAC100_TXDES1_INS_VLANTAG;
74462306a36Sopenharmony_ci		csum_vlan |= skb_vlan_tag_get(skb) & 0xffff;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* Get header len */
74862306a36Sopenharmony_ci	len = skb_headlen(skb);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Map the packet head */
75162306a36Sopenharmony_ci	map = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
75262306a36Sopenharmony_ci	if (dma_mapping_error(priv->dev, map)) {
75362306a36Sopenharmony_ci		if (net_ratelimit())
75462306a36Sopenharmony_ci			netdev_err(netdev, "map tx packet head failed\n");
75562306a36Sopenharmony_ci		goto drop;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Grab the next free tx descriptor */
75962306a36Sopenharmony_ci	pointer = priv->tx_pointer;
76062306a36Sopenharmony_ci	txdes = first = &priv->txdes[pointer];
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* Setup it up with the packet head. Don't write the head to the
76362306a36Sopenharmony_ci	 * ring just yet
76462306a36Sopenharmony_ci	 */
76562306a36Sopenharmony_ci	priv->tx_skbs[pointer] = skb;
76662306a36Sopenharmony_ci	f_ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
76762306a36Sopenharmony_ci	f_ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
76862306a36Sopenharmony_ci	f_ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
76962306a36Sopenharmony_ci	f_ctl_stat |= FTGMAC100_TXDES0_FTS;
77062306a36Sopenharmony_ci	if (nfrags == 0)
77162306a36Sopenharmony_ci		f_ctl_stat |= FTGMAC100_TXDES0_LTS;
77262306a36Sopenharmony_ci	txdes->txdes3 = cpu_to_le32(map);
77362306a36Sopenharmony_ci	txdes->txdes1 = cpu_to_le32(csum_vlan);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* Next descriptor */
77662306a36Sopenharmony_ci	pointer = ftgmac100_next_tx_pointer(priv, pointer);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/* Add the fragments */
77962306a36Sopenharmony_ci	for (i = 0; i < nfrags; i++) {
78062306a36Sopenharmony_ci		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci		len = skb_frag_size(frag);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci		/* Map it */
78562306a36Sopenharmony_ci		map = skb_frag_dma_map(priv->dev, frag, 0, len,
78662306a36Sopenharmony_ci				       DMA_TO_DEVICE);
78762306a36Sopenharmony_ci		if (dma_mapping_error(priv->dev, map))
78862306a36Sopenharmony_ci			goto dma_err;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		/* Setup descriptor */
79162306a36Sopenharmony_ci		priv->tx_skbs[pointer] = skb;
79262306a36Sopenharmony_ci		txdes = &priv->txdes[pointer];
79362306a36Sopenharmony_ci		ctl_stat = ftgmac100_base_tx_ctlstat(priv, pointer);
79462306a36Sopenharmony_ci		ctl_stat |= FTGMAC100_TXDES0_TXDMA_OWN;
79562306a36Sopenharmony_ci		ctl_stat |= FTGMAC100_TXDES0_TXBUF_SIZE(len);
79662306a36Sopenharmony_ci		if (i == (nfrags - 1))
79762306a36Sopenharmony_ci			ctl_stat |= FTGMAC100_TXDES0_LTS;
79862306a36Sopenharmony_ci		txdes->txdes0 = cpu_to_le32(ctl_stat);
79962306a36Sopenharmony_ci		txdes->txdes1 = 0;
80062306a36Sopenharmony_ci		txdes->txdes3 = cpu_to_le32(map);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci		/* Next one */
80362306a36Sopenharmony_ci		pointer = ftgmac100_next_tx_pointer(priv, pointer);
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	/* Order the previous packet and descriptor udpates
80762306a36Sopenharmony_ci	 * before setting the OWN bit on the first descriptor.
80862306a36Sopenharmony_ci	 */
80962306a36Sopenharmony_ci	dma_wmb();
81062306a36Sopenharmony_ci	first->txdes0 = cpu_to_le32(f_ctl_stat);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* Update next TX pointer */
81362306a36Sopenharmony_ci	priv->tx_pointer = pointer;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* If there isn't enough room for all the fragments of a new packet
81662306a36Sopenharmony_ci	 * in the TX ring, stop the queue. The sequence below is race free
81762306a36Sopenharmony_ci	 * vs. a concurrent restart in ftgmac100_poll()
81862306a36Sopenharmony_ci	 */
81962306a36Sopenharmony_ci	if (unlikely(ftgmac100_tx_buf_avail(priv) < TX_THRESHOLD)) {
82062306a36Sopenharmony_ci		netif_stop_queue(netdev);
82162306a36Sopenharmony_ci		/* Order the queue stop with the test below */
82262306a36Sopenharmony_ci		smp_mb();
82362306a36Sopenharmony_ci		if (ftgmac100_tx_buf_avail(priv) >= TX_THRESHOLD)
82462306a36Sopenharmony_ci			netif_wake_queue(netdev);
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* Poke transmitter to read the updated TX descriptors */
82862306a36Sopenharmony_ci	iowrite32(1, priv->base + FTGMAC100_OFFSET_NPTXPD);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return NETDEV_TX_OK;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci dma_err:
83362306a36Sopenharmony_ci	if (net_ratelimit())
83462306a36Sopenharmony_ci		netdev_err(netdev, "map tx fragment failed\n");
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* Free head */
83762306a36Sopenharmony_ci	pointer = priv->tx_pointer;
83862306a36Sopenharmony_ci	ftgmac100_free_tx_packet(priv, pointer, skb, first, f_ctl_stat);
83962306a36Sopenharmony_ci	first->txdes0 = cpu_to_le32(f_ctl_stat & priv->txdes0_edotr_mask);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	/* Then all fragments */
84262306a36Sopenharmony_ci	for (j = 0; j < i; j++) {
84362306a36Sopenharmony_ci		pointer = ftgmac100_next_tx_pointer(priv, pointer);
84462306a36Sopenharmony_ci		txdes = &priv->txdes[pointer];
84562306a36Sopenharmony_ci		ctl_stat = le32_to_cpu(txdes->txdes0);
84662306a36Sopenharmony_ci		ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);
84762306a36Sopenharmony_ci		txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask);
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* This cannot be reached if we successfully mapped the
85162306a36Sopenharmony_ci	 * last fragment, so we know ftgmac100_free_tx_packet()
85262306a36Sopenharmony_ci	 * hasn't freed the skb yet.
85362306a36Sopenharmony_ci	 */
85462306a36Sopenharmony_ci drop:
85562306a36Sopenharmony_ci	/* Drop the packet */
85662306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
85762306a36Sopenharmony_ci	netdev->stats.tx_dropped++;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	return NETDEV_TX_OK;
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic void ftgmac100_free_buffers(struct ftgmac100 *priv)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	int i;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* Free all RX buffers */
86762306a36Sopenharmony_ci	for (i = 0; i < priv->rx_q_entries; i++) {
86862306a36Sopenharmony_ci		struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
86962306a36Sopenharmony_ci		struct sk_buff *skb = priv->rx_skbs[i];
87062306a36Sopenharmony_ci		dma_addr_t map = le32_to_cpu(rxdes->rxdes3);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		if (!skb)
87362306a36Sopenharmony_ci			continue;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		priv->rx_skbs[i] = NULL;
87662306a36Sopenharmony_ci		dma_unmap_single(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE);
87762306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* Free all TX buffers */
88162306a36Sopenharmony_ci	for (i = 0; i < priv->tx_q_entries; i++) {
88262306a36Sopenharmony_ci		struct ftgmac100_txdes *txdes = &priv->txdes[i];
88362306a36Sopenharmony_ci		struct sk_buff *skb = priv->tx_skbs[i];
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci		if (!skb)
88662306a36Sopenharmony_ci			continue;
88762306a36Sopenharmony_ci		ftgmac100_free_tx_packet(priv, i, skb, txdes,
88862306a36Sopenharmony_ci					 le32_to_cpu(txdes->txdes0));
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic void ftgmac100_free_rings(struct ftgmac100 *priv)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	/* Free skb arrays */
89562306a36Sopenharmony_ci	kfree(priv->rx_skbs);
89662306a36Sopenharmony_ci	kfree(priv->tx_skbs);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* Free descriptors */
89962306a36Sopenharmony_ci	if (priv->rxdes)
90062306a36Sopenharmony_ci		dma_free_coherent(priv->dev, MAX_RX_QUEUE_ENTRIES *
90162306a36Sopenharmony_ci				  sizeof(struct ftgmac100_rxdes),
90262306a36Sopenharmony_ci				  priv->rxdes, priv->rxdes_dma);
90362306a36Sopenharmony_ci	priv->rxdes = NULL;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if (priv->txdes)
90662306a36Sopenharmony_ci		dma_free_coherent(priv->dev, MAX_TX_QUEUE_ENTRIES *
90762306a36Sopenharmony_ci				  sizeof(struct ftgmac100_txdes),
90862306a36Sopenharmony_ci				  priv->txdes, priv->txdes_dma);
90962306a36Sopenharmony_ci	priv->txdes = NULL;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	/* Free scratch packet buffer */
91262306a36Sopenharmony_ci	if (priv->rx_scratch)
91362306a36Sopenharmony_ci		dma_free_coherent(priv->dev, RX_BUF_SIZE,
91462306a36Sopenharmony_ci				  priv->rx_scratch, priv->rx_scratch_dma);
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic int ftgmac100_alloc_rings(struct ftgmac100 *priv)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	/* Allocate skb arrays */
92062306a36Sopenharmony_ci	priv->rx_skbs = kcalloc(MAX_RX_QUEUE_ENTRIES, sizeof(void *),
92162306a36Sopenharmony_ci				GFP_KERNEL);
92262306a36Sopenharmony_ci	if (!priv->rx_skbs)
92362306a36Sopenharmony_ci		return -ENOMEM;
92462306a36Sopenharmony_ci	priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *),
92562306a36Sopenharmony_ci				GFP_KERNEL);
92662306a36Sopenharmony_ci	if (!priv->tx_skbs)
92762306a36Sopenharmony_ci		return -ENOMEM;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* Allocate descriptors */
93062306a36Sopenharmony_ci	priv->rxdes = dma_alloc_coherent(priv->dev,
93162306a36Sopenharmony_ci					 MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes),
93262306a36Sopenharmony_ci					 &priv->rxdes_dma, GFP_KERNEL);
93362306a36Sopenharmony_ci	if (!priv->rxdes)
93462306a36Sopenharmony_ci		return -ENOMEM;
93562306a36Sopenharmony_ci	priv->txdes = dma_alloc_coherent(priv->dev,
93662306a36Sopenharmony_ci					 MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes),
93762306a36Sopenharmony_ci					 &priv->txdes_dma, GFP_KERNEL);
93862306a36Sopenharmony_ci	if (!priv->txdes)
93962306a36Sopenharmony_ci		return -ENOMEM;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/* Allocate scratch packet buffer */
94262306a36Sopenharmony_ci	priv->rx_scratch = dma_alloc_coherent(priv->dev,
94362306a36Sopenharmony_ci					      RX_BUF_SIZE,
94462306a36Sopenharmony_ci					      &priv->rx_scratch_dma,
94562306a36Sopenharmony_ci					      GFP_KERNEL);
94662306a36Sopenharmony_ci	if (!priv->rx_scratch)
94762306a36Sopenharmony_ci		return -ENOMEM;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	return 0;
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic void ftgmac100_init_rings(struct ftgmac100 *priv)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct ftgmac100_rxdes *rxdes = NULL;
95562306a36Sopenharmony_ci	struct ftgmac100_txdes *txdes = NULL;
95662306a36Sopenharmony_ci	int i;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* Update entries counts */
95962306a36Sopenharmony_ci	priv->rx_q_entries = priv->new_rx_q_entries;
96062306a36Sopenharmony_ci	priv->tx_q_entries = priv->new_tx_q_entries;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (WARN_ON(priv->rx_q_entries < MIN_RX_QUEUE_ENTRIES))
96362306a36Sopenharmony_ci		return;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Initialize RX ring */
96662306a36Sopenharmony_ci	for (i = 0; i < priv->rx_q_entries; i++) {
96762306a36Sopenharmony_ci		rxdes = &priv->rxdes[i];
96862306a36Sopenharmony_ci		rxdes->rxdes0 = 0;
96962306a36Sopenharmony_ci		rxdes->rxdes3 = cpu_to_le32(priv->rx_scratch_dma);
97062306a36Sopenharmony_ci	}
97162306a36Sopenharmony_ci	/* Mark the end of the ring */
97262306a36Sopenharmony_ci	rxdes->rxdes0 |= cpu_to_le32(priv->rxdes0_edorr_mask);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (WARN_ON(priv->tx_q_entries < MIN_RX_QUEUE_ENTRIES))
97562306a36Sopenharmony_ci		return;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* Initialize TX ring */
97862306a36Sopenharmony_ci	for (i = 0; i < priv->tx_q_entries; i++) {
97962306a36Sopenharmony_ci		txdes = &priv->txdes[i];
98062306a36Sopenharmony_ci		txdes->txdes0 = 0;
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci	txdes->txdes0 |= cpu_to_le32(priv->txdes0_edotr_mask);
98362306a36Sopenharmony_ci}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_cistatic int ftgmac100_alloc_rx_buffers(struct ftgmac100 *priv)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	int i;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	for (i = 0; i < priv->rx_q_entries; i++) {
99062306a36Sopenharmony_ci		struct ftgmac100_rxdes *rxdes = &priv->rxdes[i];
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		if (ftgmac100_alloc_rx_buf(priv, i, rxdes, GFP_KERNEL))
99362306a36Sopenharmony_ci			return -ENOMEM;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci	return 0;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int ftgmac100_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct net_device *netdev = bus->priv;
100162306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
100262306a36Sopenharmony_ci	unsigned int phycr;
100362306a36Sopenharmony_ci	int i;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	/* preserve MDC cycle threshold */
100862306a36Sopenharmony_ci	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
101162306a36Sopenharmony_ci		 FTGMAC100_PHYCR_REGAD(regnum) |
101262306a36Sopenharmony_ci		 FTGMAC100_PHYCR_MIIRD;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
101762306a36Sopenharmony_ci		phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci		if ((phycr & FTGMAC100_PHYCR_MIIRD) == 0) {
102062306a36Sopenharmony_ci			int data;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci			data = ioread32(priv->base + FTGMAC100_OFFSET_PHYDATA);
102362306a36Sopenharmony_ci			return FTGMAC100_PHYDATA_MIIRDATA(data);
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		udelay(100);
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	netdev_err(netdev, "mdio read timed out\n");
103062306a36Sopenharmony_ci	return -EIO;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
103462306a36Sopenharmony_ci				   int regnum, u16 value)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct net_device *netdev = bus->priv;
103762306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
103862306a36Sopenharmony_ci	unsigned int phycr;
103962306a36Sopenharmony_ci	int data;
104062306a36Sopenharmony_ci	int i;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/* preserve MDC cycle threshold */
104562306a36Sopenharmony_ci	phycr &= FTGMAC100_PHYCR_MDC_CYCTHR_MASK;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	phycr |= FTGMAC100_PHYCR_PHYAD(phy_addr) |
104862306a36Sopenharmony_ci		 FTGMAC100_PHYCR_REGAD(regnum) |
104962306a36Sopenharmony_ci		 FTGMAC100_PHYCR_MIIWR;
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	data = FTGMAC100_PHYDATA_MIIWDATA(value);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	iowrite32(data, priv->base + FTGMAC100_OFFSET_PHYDATA);
105462306a36Sopenharmony_ci	iowrite32(phycr, priv->base + FTGMAC100_OFFSET_PHYCR);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
105762306a36Sopenharmony_ci		phycr = ioread32(priv->base + FTGMAC100_OFFSET_PHYCR);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		if ((phycr & FTGMAC100_PHYCR_MIIWR) == 0)
106062306a36Sopenharmony_ci			return 0;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci		udelay(100);
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	netdev_err(netdev, "mdio write timed out\n");
106662306a36Sopenharmony_ci	return -EIO;
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic void ftgmac100_get_drvinfo(struct net_device *netdev,
107062306a36Sopenharmony_ci				  struct ethtool_drvinfo *info)
107162306a36Sopenharmony_ci{
107262306a36Sopenharmony_ci	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
107362306a36Sopenharmony_ci	strscpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info));
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic void
107762306a36Sopenharmony_ciftgmac100_get_ringparam(struct net_device *netdev,
107862306a36Sopenharmony_ci			struct ethtool_ringparam *ering,
107962306a36Sopenharmony_ci			struct kernel_ethtool_ringparam *kernel_ering,
108062306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	memset(ering, 0, sizeof(*ering));
108562306a36Sopenharmony_ci	ering->rx_max_pending = MAX_RX_QUEUE_ENTRIES;
108662306a36Sopenharmony_ci	ering->tx_max_pending = MAX_TX_QUEUE_ENTRIES;
108762306a36Sopenharmony_ci	ering->rx_pending = priv->rx_q_entries;
108862306a36Sopenharmony_ci	ering->tx_pending = priv->tx_q_entries;
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic int
109262306a36Sopenharmony_ciftgmac100_set_ringparam(struct net_device *netdev,
109362306a36Sopenharmony_ci			struct ethtool_ringparam *ering,
109462306a36Sopenharmony_ci			struct kernel_ethtool_ringparam *kernel_ering,
109562306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	if (ering->rx_pending > MAX_RX_QUEUE_ENTRIES ||
110062306a36Sopenharmony_ci	    ering->tx_pending > MAX_TX_QUEUE_ENTRIES ||
110162306a36Sopenharmony_ci	    ering->rx_pending < MIN_RX_QUEUE_ENTRIES ||
110262306a36Sopenharmony_ci	    ering->tx_pending < MIN_TX_QUEUE_ENTRIES ||
110362306a36Sopenharmony_ci	    !is_power_of_2(ering->rx_pending) ||
110462306a36Sopenharmony_ci	    !is_power_of_2(ering->tx_pending))
110562306a36Sopenharmony_ci		return -EINVAL;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	priv->new_rx_q_entries = ering->rx_pending;
110862306a36Sopenharmony_ci	priv->new_tx_q_entries = ering->tx_pending;
110962306a36Sopenharmony_ci	if (netif_running(netdev))
111062306a36Sopenharmony_ci		schedule_work(&priv->reset_task);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	return 0;
111362306a36Sopenharmony_ci}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_cistatic void ftgmac100_get_pauseparam(struct net_device *netdev,
111662306a36Sopenharmony_ci				     struct ethtool_pauseparam *pause)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	pause->autoneg = priv->aneg_pause;
112162306a36Sopenharmony_ci	pause->tx_pause = priv->tx_pause;
112262306a36Sopenharmony_ci	pause->rx_pause = priv->rx_pause;
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_cistatic int ftgmac100_set_pauseparam(struct net_device *netdev,
112662306a36Sopenharmony_ci				    struct ethtool_pauseparam *pause)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
112962306a36Sopenharmony_ci	struct phy_device *phydev = netdev->phydev;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	priv->aneg_pause = pause->autoneg;
113262306a36Sopenharmony_ci	priv->tx_pause = pause->tx_pause;
113362306a36Sopenharmony_ci	priv->rx_pause = pause->rx_pause;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	if (phydev)
113662306a36Sopenharmony_ci		phy_set_asym_pause(phydev, pause->rx_pause, pause->tx_pause);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	if (netif_running(netdev)) {
113962306a36Sopenharmony_ci		if (!(phydev && priv->aneg_pause))
114062306a36Sopenharmony_ci			ftgmac100_config_pause(priv);
114162306a36Sopenharmony_ci	}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	return 0;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic const struct ethtool_ops ftgmac100_ethtool_ops = {
114762306a36Sopenharmony_ci	.get_drvinfo		= ftgmac100_get_drvinfo,
114862306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
114962306a36Sopenharmony_ci	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
115062306a36Sopenharmony_ci	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
115162306a36Sopenharmony_ci	.nway_reset		= phy_ethtool_nway_reset,
115262306a36Sopenharmony_ci	.get_ringparam		= ftgmac100_get_ringparam,
115362306a36Sopenharmony_ci	.set_ringparam		= ftgmac100_set_ringparam,
115462306a36Sopenharmony_ci	.get_pauseparam		= ftgmac100_get_pauseparam,
115562306a36Sopenharmony_ci	.set_pauseparam		= ftgmac100_set_pauseparam,
115662306a36Sopenharmony_ci};
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_cistatic irqreturn_t ftgmac100_interrupt(int irq, void *dev_id)
115962306a36Sopenharmony_ci{
116062306a36Sopenharmony_ci	struct net_device *netdev = dev_id;
116162306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
116262306a36Sopenharmony_ci	unsigned int status, new_mask = FTGMAC100_INT_BAD;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/* Fetch and clear interrupt bits, process abnormal ones */
116562306a36Sopenharmony_ci	status = ioread32(priv->base + FTGMAC100_OFFSET_ISR);
116662306a36Sopenharmony_ci	iowrite32(status, priv->base + FTGMAC100_OFFSET_ISR);
116762306a36Sopenharmony_ci	if (unlikely(status & FTGMAC100_INT_BAD)) {
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		/* RX buffer unavailable */
117062306a36Sopenharmony_ci		if (status & FTGMAC100_INT_NO_RXBUF)
117162306a36Sopenharmony_ci			netdev->stats.rx_over_errors++;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		/* received packet lost due to RX FIFO full */
117462306a36Sopenharmony_ci		if (status & FTGMAC100_INT_RPKT_LOST)
117562306a36Sopenharmony_ci			netdev->stats.rx_fifo_errors++;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		/* sent packet lost due to excessive TX collision */
117862306a36Sopenharmony_ci		if (status & FTGMAC100_INT_XPKT_LOST)
117962306a36Sopenharmony_ci			netdev->stats.tx_fifo_errors++;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci		/* AHB error -> Reset the chip */
118262306a36Sopenharmony_ci		if (status & FTGMAC100_INT_AHB_ERR) {
118362306a36Sopenharmony_ci			if (net_ratelimit())
118462306a36Sopenharmony_ci				netdev_warn(netdev,
118562306a36Sopenharmony_ci					   "AHB bus error ! Resetting chip.\n");
118662306a36Sopenharmony_ci			iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
118762306a36Sopenharmony_ci			schedule_work(&priv->reset_task);
118862306a36Sopenharmony_ci			return IRQ_HANDLED;
118962306a36Sopenharmony_ci		}
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci		/* We may need to restart the MAC after such errors, delay
119262306a36Sopenharmony_ci		 * this until after we have freed some Rx buffers though
119362306a36Sopenharmony_ci		 */
119462306a36Sopenharmony_ci		priv->need_mac_restart = true;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		/* Disable those errors until we restart */
119762306a36Sopenharmony_ci		new_mask &= ~status;
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* Only enable "bad" interrupts while NAPI is on */
120162306a36Sopenharmony_ci	iowrite32(new_mask, priv->base + FTGMAC100_OFFSET_IER);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	/* Schedule NAPI bh */
120462306a36Sopenharmony_ci	napi_schedule_irqoff(&priv->napi);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	return IRQ_HANDLED;
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic bool ftgmac100_check_rx(struct ftgmac100 *priv)
121062306a36Sopenharmony_ci{
121162306a36Sopenharmony_ci	struct ftgmac100_rxdes *rxdes = &priv->rxdes[priv->rx_pointer];
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	/* Do we have a packet ? */
121462306a36Sopenharmony_ci	return !!(rxdes->rxdes0 & cpu_to_le32(FTGMAC100_RXDES0_RXPKT_RDY));
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistatic int ftgmac100_poll(struct napi_struct *napi, int budget)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct ftgmac100 *priv = container_of(napi, struct ftgmac100, napi);
122062306a36Sopenharmony_ci	int work_done = 0;
122162306a36Sopenharmony_ci	bool more;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	/* Handle TX completions */
122462306a36Sopenharmony_ci	if (ftgmac100_tx_buf_cleanable(priv))
122562306a36Sopenharmony_ci		ftgmac100_tx_complete(priv);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/* Handle RX packets */
122862306a36Sopenharmony_ci	do {
122962306a36Sopenharmony_ci		more = ftgmac100_rx_packet(priv, &work_done);
123062306a36Sopenharmony_ci	} while (more && work_done < budget);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* The interrupt is telling us to kick the MAC back to life
123462306a36Sopenharmony_ci	 * after an RX overflow
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci	if (unlikely(priv->need_mac_restart)) {
123762306a36Sopenharmony_ci		ftgmac100_start_hw(priv);
123862306a36Sopenharmony_ci		priv->need_mac_restart = false;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		/* Re-enable "bad" interrupts */
124162306a36Sopenharmony_ci		iowrite32(FTGMAC100_INT_BAD,
124262306a36Sopenharmony_ci			  priv->base + FTGMAC100_OFFSET_IER);
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	/* As long as we are waiting for transmit packets to be
124662306a36Sopenharmony_ci	 * completed we keep NAPI going
124762306a36Sopenharmony_ci	 */
124862306a36Sopenharmony_ci	if (ftgmac100_tx_buf_cleanable(priv))
124962306a36Sopenharmony_ci		work_done = budget;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	if (work_done < budget) {
125262306a36Sopenharmony_ci		/* We are about to re-enable all interrupts. However
125362306a36Sopenharmony_ci		 * the HW has been latching RX/TX packet interrupts while
125462306a36Sopenharmony_ci		 * they were masked. So we clear them first, then we need
125562306a36Sopenharmony_ci		 * to re-check if there's something to process
125662306a36Sopenharmony_ci		 */
125762306a36Sopenharmony_ci		iowrite32(FTGMAC100_INT_RXTX,
125862306a36Sopenharmony_ci			  priv->base + FTGMAC100_OFFSET_ISR);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci		/* Push the above (and provides a barrier vs. subsequent
126162306a36Sopenharmony_ci		 * reads of the descriptor).
126262306a36Sopenharmony_ci		 */
126362306a36Sopenharmony_ci		ioread32(priv->base + FTGMAC100_OFFSET_ISR);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		/* Check RX and TX descriptors for more work to do */
126662306a36Sopenharmony_ci		if (ftgmac100_check_rx(priv) ||
126762306a36Sopenharmony_ci		    ftgmac100_tx_buf_cleanable(priv))
126862306a36Sopenharmony_ci			return budget;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		/* deschedule NAPI */
127162306a36Sopenharmony_ci		napi_complete(napi);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci		/* enable all interrupts */
127462306a36Sopenharmony_ci		iowrite32(FTGMAC100_INT_ALL,
127562306a36Sopenharmony_ci			  priv->base + FTGMAC100_OFFSET_IER);
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	return work_done;
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic int ftgmac100_init_all(struct ftgmac100 *priv, bool ignore_alloc_err)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	int err = 0;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/* Re-init descriptors (adjust queue sizes) */
128662306a36Sopenharmony_ci	ftgmac100_init_rings(priv);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	/* Realloc rx descriptors */
128962306a36Sopenharmony_ci	err = ftgmac100_alloc_rx_buffers(priv);
129062306a36Sopenharmony_ci	if (err && !ignore_alloc_err)
129162306a36Sopenharmony_ci		return err;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	/* Reinit and restart HW */
129462306a36Sopenharmony_ci	ftgmac100_init_hw(priv);
129562306a36Sopenharmony_ci	ftgmac100_config_pause(priv);
129662306a36Sopenharmony_ci	ftgmac100_start_hw(priv);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	/* Re-enable the device */
129962306a36Sopenharmony_ci	napi_enable(&priv->napi);
130062306a36Sopenharmony_ci	netif_start_queue(priv->netdev);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	/* Enable all interrupts */
130362306a36Sopenharmony_ci	iowrite32(FTGMAC100_INT_ALL, priv->base + FTGMAC100_OFFSET_IER);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return err;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic void ftgmac100_reset(struct ftgmac100 *priv)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct net_device *netdev = priv->netdev;
131162306a36Sopenharmony_ci	int err;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	netdev_dbg(netdev, "Resetting NIC...\n");
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	/* Lock the world */
131662306a36Sopenharmony_ci	rtnl_lock();
131762306a36Sopenharmony_ci	if (netdev->phydev)
131862306a36Sopenharmony_ci		mutex_lock(&netdev->phydev->lock);
131962306a36Sopenharmony_ci	if (priv->mii_bus)
132062306a36Sopenharmony_ci		mutex_lock(&priv->mii_bus->mdio_lock);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	/* Check if the interface is still up */
132462306a36Sopenharmony_ci	if (!netif_running(netdev))
132562306a36Sopenharmony_ci		goto bail;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	/* Stop the network stack */
132862306a36Sopenharmony_ci	netif_trans_update(netdev);
132962306a36Sopenharmony_ci	napi_disable(&priv->napi);
133062306a36Sopenharmony_ci	netif_tx_disable(netdev);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* Stop and reset the MAC */
133362306a36Sopenharmony_ci	ftgmac100_stop_hw(priv);
133462306a36Sopenharmony_ci	err = ftgmac100_reset_and_config_mac(priv);
133562306a36Sopenharmony_ci	if (err) {
133662306a36Sopenharmony_ci		/* Not much we can do ... it might come back... */
133762306a36Sopenharmony_ci		netdev_err(netdev, "attempting to continue...\n");
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* Free all rx and tx buffers */
134162306a36Sopenharmony_ci	ftgmac100_free_buffers(priv);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	/* Setup everything again and restart chip */
134462306a36Sopenharmony_ci	ftgmac100_init_all(priv, true);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	netdev_dbg(netdev, "Reset done !\n");
134762306a36Sopenharmony_ci bail:
134862306a36Sopenharmony_ci	if (priv->mii_bus)
134962306a36Sopenharmony_ci		mutex_unlock(&priv->mii_bus->mdio_lock);
135062306a36Sopenharmony_ci	if (netdev->phydev)
135162306a36Sopenharmony_ci		mutex_unlock(&netdev->phydev->lock);
135262306a36Sopenharmony_ci	rtnl_unlock();
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic void ftgmac100_reset_task(struct work_struct *work)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	struct ftgmac100 *priv = container_of(work, struct ftgmac100,
135862306a36Sopenharmony_ci					      reset_task);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	ftgmac100_reset(priv);
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_cistatic void ftgmac100_adjust_link(struct net_device *netdev)
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
136662306a36Sopenharmony_ci	struct phy_device *phydev = netdev->phydev;
136762306a36Sopenharmony_ci	bool tx_pause, rx_pause;
136862306a36Sopenharmony_ci	int new_speed;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/* We store "no link" as speed 0 */
137162306a36Sopenharmony_ci	if (!phydev->link)
137262306a36Sopenharmony_ci		new_speed = 0;
137362306a36Sopenharmony_ci	else
137462306a36Sopenharmony_ci		new_speed = phydev->speed;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	/* Grab pause settings from PHY if configured to do so */
137762306a36Sopenharmony_ci	if (priv->aneg_pause) {
137862306a36Sopenharmony_ci		rx_pause = tx_pause = phydev->pause;
137962306a36Sopenharmony_ci		if (phydev->asym_pause)
138062306a36Sopenharmony_ci			tx_pause = !rx_pause;
138162306a36Sopenharmony_ci	} else {
138262306a36Sopenharmony_ci		rx_pause = priv->rx_pause;
138362306a36Sopenharmony_ci		tx_pause = priv->tx_pause;
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	/* Link hasn't changed, do nothing */
138762306a36Sopenharmony_ci	if (phydev->speed == priv->cur_speed &&
138862306a36Sopenharmony_ci	    phydev->duplex == priv->cur_duplex &&
138962306a36Sopenharmony_ci	    rx_pause == priv->rx_pause &&
139062306a36Sopenharmony_ci	    tx_pause == priv->tx_pause)
139162306a36Sopenharmony_ci		return;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* Print status if we have a link or we had one and just lost it,
139462306a36Sopenharmony_ci	 * don't print otherwise.
139562306a36Sopenharmony_ci	 */
139662306a36Sopenharmony_ci	if (new_speed || priv->cur_speed)
139762306a36Sopenharmony_ci		phy_print_status(phydev);
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	priv->cur_speed = new_speed;
140062306a36Sopenharmony_ci	priv->cur_duplex = phydev->duplex;
140162306a36Sopenharmony_ci	priv->rx_pause = rx_pause;
140262306a36Sopenharmony_ci	priv->tx_pause = tx_pause;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* Link is down, do nothing else */
140562306a36Sopenharmony_ci	if (!new_speed)
140662306a36Sopenharmony_ci		return;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* Disable all interrupts */
140962306a36Sopenharmony_ci	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* Release phy lock to allow ftgmac100_reset to aquire it, keeping lock
141262306a36Sopenharmony_ci	 * order consistent to prevent dead lock.
141362306a36Sopenharmony_ci	 */
141462306a36Sopenharmony_ci	if (netdev->phydev)
141562306a36Sopenharmony_ci		mutex_unlock(&netdev->phydev->lock);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	ftgmac100_reset(priv);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (netdev->phydev)
142062306a36Sopenharmony_ci		mutex_lock(&netdev->phydev->lock);
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_cistatic int ftgmac100_mii_probe(struct net_device *netdev)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
142762306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(priv->dev);
142862306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
142962306a36Sopenharmony_ci	struct phy_device *phydev;
143062306a36Sopenharmony_ci	phy_interface_t phy_intf;
143162306a36Sopenharmony_ci	int err;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	/* Default to RGMII. It's a gigabit part after all */
143462306a36Sopenharmony_ci	err = of_get_phy_mode(np, &phy_intf);
143562306a36Sopenharmony_ci	if (err)
143662306a36Sopenharmony_ci		phy_intf = PHY_INTERFACE_MODE_RGMII;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	/* Aspeed only supports these. I don't know about other IP
143962306a36Sopenharmony_ci	 * block vendors so I'm going to just let them through for
144062306a36Sopenharmony_ci	 * now. Note that this is only a warning if for some obscure
144162306a36Sopenharmony_ci	 * reason the DT really means to lie about it or it's a newer
144262306a36Sopenharmony_ci	 * part we don't know about.
144362306a36Sopenharmony_ci	 *
144462306a36Sopenharmony_ci	 * On the Aspeed SoC there are additionally straps and SCU
144562306a36Sopenharmony_ci	 * control bits that could tell us what the interface is
144662306a36Sopenharmony_ci	 * (or allow us to configure it while the IP block is held
144762306a36Sopenharmony_ci	 * in reset). For now I chose to keep this driver away from
144862306a36Sopenharmony_ci	 * those SoC specific bits and assume the device-tree is
144962306a36Sopenharmony_ci	 * right and the SCU has been configured properly by pinmux
145062306a36Sopenharmony_ci	 * or the firmware.
145162306a36Sopenharmony_ci	 */
145262306a36Sopenharmony_ci	if (priv->is_aspeed && !(phy_interface_mode_is_rgmii(phy_intf))) {
145362306a36Sopenharmony_ci		netdev_warn(netdev,
145462306a36Sopenharmony_ci			    "Unsupported PHY mode %s !\n",
145562306a36Sopenharmony_ci			    phy_modes(phy_intf));
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	phydev = phy_find_first(priv->mii_bus);
145962306a36Sopenharmony_ci	if (!phydev) {
146062306a36Sopenharmony_ci		netdev_info(netdev, "%s: no PHY found\n", netdev->name);
146162306a36Sopenharmony_ci		return -ENODEV;
146262306a36Sopenharmony_ci	}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	phydev = phy_connect(netdev, phydev_name(phydev),
146562306a36Sopenharmony_ci			     &ftgmac100_adjust_link, phy_intf);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if (IS_ERR(phydev)) {
146862306a36Sopenharmony_ci		netdev_err(netdev, "%s: Could not attach to PHY\n", netdev->name);
146962306a36Sopenharmony_ci		return PTR_ERR(phydev);
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	/* Indicate that we support PAUSE frames (see comment in
147362306a36Sopenharmony_ci	 * Documentation/networking/phy.rst)
147462306a36Sopenharmony_ci	 */
147562306a36Sopenharmony_ci	phy_support_asym_pause(phydev);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	/* Display what we found */
147862306a36Sopenharmony_ci	phy_attached_info(phydev);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	return 0;
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_cistatic int ftgmac100_open(struct net_device *netdev)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
148662306a36Sopenharmony_ci	int err;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* Allocate ring buffers  */
148962306a36Sopenharmony_ci	err = ftgmac100_alloc_rings(priv);
149062306a36Sopenharmony_ci	if (err) {
149162306a36Sopenharmony_ci		netdev_err(netdev, "Failed to allocate descriptors\n");
149262306a36Sopenharmony_ci		return err;
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	/* When using NC-SI we force the speed to 100Mbit/s full duplex,
149662306a36Sopenharmony_ci	 *
149762306a36Sopenharmony_ci	 * Otherwise we leave it set to 0 (no link), the link
149862306a36Sopenharmony_ci	 * message from the PHY layer will handle setting it up to
149962306a36Sopenharmony_ci	 * something else if needed.
150062306a36Sopenharmony_ci	 */
150162306a36Sopenharmony_ci	if (priv->use_ncsi) {
150262306a36Sopenharmony_ci		priv->cur_duplex = DUPLEX_FULL;
150362306a36Sopenharmony_ci		priv->cur_speed = SPEED_100;
150462306a36Sopenharmony_ci	} else {
150562306a36Sopenharmony_ci		priv->cur_duplex = 0;
150662306a36Sopenharmony_ci		priv->cur_speed = 0;
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	/* Reset the hardware */
151062306a36Sopenharmony_ci	err = ftgmac100_reset_and_config_mac(priv);
151162306a36Sopenharmony_ci	if (err)
151262306a36Sopenharmony_ci		goto err_hw;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	/* Initialize NAPI */
151562306a36Sopenharmony_ci	netif_napi_add(netdev, &priv->napi, ftgmac100_poll);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	/* Grab our interrupt */
151862306a36Sopenharmony_ci	err = request_irq(netdev->irq, ftgmac100_interrupt, 0, netdev->name, netdev);
151962306a36Sopenharmony_ci	if (err) {
152062306a36Sopenharmony_ci		netdev_err(netdev, "failed to request irq %d\n", netdev->irq);
152162306a36Sopenharmony_ci		goto err_irq;
152262306a36Sopenharmony_ci	}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	/* Start things up */
152562306a36Sopenharmony_ci	err = ftgmac100_init_all(priv, false);
152662306a36Sopenharmony_ci	if (err) {
152762306a36Sopenharmony_ci		netdev_err(netdev, "Failed to allocate packet buffers\n");
152862306a36Sopenharmony_ci		goto err_alloc;
152962306a36Sopenharmony_ci	}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (netdev->phydev) {
153262306a36Sopenharmony_ci		/* If we have a PHY, start polling */
153362306a36Sopenharmony_ci		phy_start(netdev->phydev);
153462306a36Sopenharmony_ci	} else if (priv->use_ncsi) {
153562306a36Sopenharmony_ci		/* If using NC-SI, set our carrier on and start the stack */
153662306a36Sopenharmony_ci		netif_carrier_on(netdev);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		/* Start the NCSI device */
153962306a36Sopenharmony_ci		err = ncsi_start_dev(priv->ndev);
154062306a36Sopenharmony_ci		if (err)
154162306a36Sopenharmony_ci			goto err_ncsi;
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	return 0;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci err_ncsi:
154762306a36Sopenharmony_ci	napi_disable(&priv->napi);
154862306a36Sopenharmony_ci	netif_stop_queue(netdev);
154962306a36Sopenharmony_ci err_alloc:
155062306a36Sopenharmony_ci	ftgmac100_free_buffers(priv);
155162306a36Sopenharmony_ci	free_irq(netdev->irq, netdev);
155262306a36Sopenharmony_ci err_irq:
155362306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
155462306a36Sopenharmony_ci err_hw:
155562306a36Sopenharmony_ci	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
155662306a36Sopenharmony_ci	ftgmac100_free_rings(priv);
155762306a36Sopenharmony_ci	return err;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic int ftgmac100_stop(struct net_device *netdev)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	/* Note about the reset task: We are called with the rtnl lock
156562306a36Sopenharmony_ci	 * held, so we are synchronized against the core of the reset
156662306a36Sopenharmony_ci	 * task. We must not try to synchronously cancel it otherwise
156762306a36Sopenharmony_ci	 * we can deadlock. But since it will test for netif_running()
156862306a36Sopenharmony_ci	 * which has already been cleared by the net core, we don't
156962306a36Sopenharmony_ci	 * anything special to do.
157062306a36Sopenharmony_ci	 */
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	/* disable all interrupts */
157362306a36Sopenharmony_ci	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	netif_stop_queue(netdev);
157662306a36Sopenharmony_ci	napi_disable(&priv->napi);
157762306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
157862306a36Sopenharmony_ci	if (netdev->phydev)
157962306a36Sopenharmony_ci		phy_stop(netdev->phydev);
158062306a36Sopenharmony_ci	else if (priv->use_ncsi)
158162306a36Sopenharmony_ci		ncsi_stop_dev(priv->ndev);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	ftgmac100_stop_hw(priv);
158462306a36Sopenharmony_ci	free_irq(netdev->irq, netdev);
158562306a36Sopenharmony_ci	ftgmac100_free_buffers(priv);
158662306a36Sopenharmony_ci	ftgmac100_free_rings(priv);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	return 0;
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic void ftgmac100_tx_timeout(struct net_device *netdev, unsigned int txqueue)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	/* Disable all interrupts */
159662306a36Sopenharmony_ci	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	/* Do the reset outside of interrupt context */
159962306a36Sopenharmony_ci	schedule_work(&priv->reset_task);
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic int ftgmac100_set_features(struct net_device *netdev,
160362306a36Sopenharmony_ci				  netdev_features_t features)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
160662306a36Sopenharmony_ci	netdev_features_t changed = netdev->features ^ features;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	if (!netif_running(netdev))
160962306a36Sopenharmony_ci		return 0;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* Update the vlan filtering bit */
161262306a36Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
161362306a36Sopenharmony_ci		u32 maccr;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		maccr = ioread32(priv->base + FTGMAC100_OFFSET_MACCR);
161662306a36Sopenharmony_ci		if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
161762306a36Sopenharmony_ci			maccr |= FTGMAC100_MACCR_RM_VLAN;
161862306a36Sopenharmony_ci		else
161962306a36Sopenharmony_ci			maccr &= ~FTGMAC100_MACCR_RM_VLAN;
162062306a36Sopenharmony_ci		iowrite32(maccr, priv->base + FTGMAC100_OFFSET_MACCR);
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	return 0;
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
162762306a36Sopenharmony_cistatic void ftgmac100_poll_controller(struct net_device *netdev)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	unsigned long flags;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	local_irq_save(flags);
163262306a36Sopenharmony_ci	ftgmac100_interrupt(netdev->irq, netdev);
163362306a36Sopenharmony_ci	local_irq_restore(flags);
163462306a36Sopenharmony_ci}
163562306a36Sopenharmony_ci#endif
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_cistatic const struct net_device_ops ftgmac100_netdev_ops = {
163862306a36Sopenharmony_ci	.ndo_open		= ftgmac100_open,
163962306a36Sopenharmony_ci	.ndo_stop		= ftgmac100_stop,
164062306a36Sopenharmony_ci	.ndo_start_xmit		= ftgmac100_hard_start_xmit,
164162306a36Sopenharmony_ci	.ndo_set_mac_address	= ftgmac100_set_mac_addr,
164262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
164362306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl,
164462306a36Sopenharmony_ci	.ndo_tx_timeout		= ftgmac100_tx_timeout,
164562306a36Sopenharmony_ci	.ndo_set_rx_mode	= ftgmac100_set_rx_mode,
164662306a36Sopenharmony_ci	.ndo_set_features	= ftgmac100_set_features,
164762306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
164862306a36Sopenharmony_ci	.ndo_poll_controller	= ftgmac100_poll_controller,
164962306a36Sopenharmony_ci#endif
165062306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= ncsi_vlan_rx_add_vid,
165162306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= ncsi_vlan_rx_kill_vid,
165262306a36Sopenharmony_ci};
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_cistatic int ftgmac100_setup_mdio(struct net_device *netdev)
165562306a36Sopenharmony_ci{
165662306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
165762306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(priv->dev);
165862306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
165962306a36Sopenharmony_ci	struct device_node *mdio_np;
166062306a36Sopenharmony_ci	int i, err = 0;
166162306a36Sopenharmony_ci	u32 reg;
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/* initialize mdio bus */
166462306a36Sopenharmony_ci	priv->mii_bus = mdiobus_alloc();
166562306a36Sopenharmony_ci	if (!priv->mii_bus)
166662306a36Sopenharmony_ci		return -EIO;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	if (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
166962306a36Sopenharmony_ci	    of_device_is_compatible(np, "aspeed,ast2500-mac")) {
167062306a36Sopenharmony_ci		/* The AST2600 has a separate MDIO controller */
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci		/* For the AST2400 and AST2500 this driver only supports the
167362306a36Sopenharmony_ci		 * old MDIO interface
167462306a36Sopenharmony_ci		 */
167562306a36Sopenharmony_ci		reg = ioread32(priv->base + FTGMAC100_OFFSET_REVR);
167662306a36Sopenharmony_ci		reg &= ~FTGMAC100_REVR_NEW_MDIO_INTERFACE;
167762306a36Sopenharmony_ci		iowrite32(reg, priv->base + FTGMAC100_OFFSET_REVR);
167862306a36Sopenharmony_ci	}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	priv->mii_bus->name = "ftgmac100_mdio";
168162306a36Sopenharmony_ci	snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
168262306a36Sopenharmony_ci		 pdev->name, pdev->id);
168362306a36Sopenharmony_ci	priv->mii_bus->parent = priv->dev;
168462306a36Sopenharmony_ci	priv->mii_bus->priv = priv->netdev;
168562306a36Sopenharmony_ci	priv->mii_bus->read = ftgmac100_mdiobus_read;
168662306a36Sopenharmony_ci	priv->mii_bus->write = ftgmac100_mdiobus_write;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	for (i = 0; i < PHY_MAX_ADDR; i++)
168962306a36Sopenharmony_ci		priv->mii_bus->irq[i] = PHY_POLL;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	mdio_np = of_get_child_by_name(np, "mdio");
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	err = of_mdiobus_register(priv->mii_bus, mdio_np);
169462306a36Sopenharmony_ci	if (err) {
169562306a36Sopenharmony_ci		dev_err(priv->dev, "Cannot register MDIO bus!\n");
169662306a36Sopenharmony_ci		goto err_register_mdiobus;
169762306a36Sopenharmony_ci	}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	of_node_put(mdio_np);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	return 0;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cierr_register_mdiobus:
170462306a36Sopenharmony_ci	mdiobus_free(priv->mii_bus);
170562306a36Sopenharmony_ci	return err;
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void ftgmac100_phy_disconnect(struct net_device *netdev)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (!netdev->phydev)
171362306a36Sopenharmony_ci		return;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	phy_disconnect(netdev->phydev);
171662306a36Sopenharmony_ci	if (of_phy_is_fixed_link(priv->dev->of_node))
171762306a36Sopenharmony_ci		of_phy_deregister_fixed_link(priv->dev->of_node);
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic void ftgmac100_destroy_mdio(struct net_device *netdev)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	struct ftgmac100 *priv = netdev_priv(netdev);
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	if (!priv->mii_bus)
172562306a36Sopenharmony_ci		return;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	mdiobus_unregister(priv->mii_bus);
172862306a36Sopenharmony_ci	mdiobus_free(priv->mii_bus);
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_cistatic void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	if (unlikely(nd->state != ncsi_dev_state_functional))
173462306a36Sopenharmony_ci		return;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	netdev_dbg(nd->dev, "NCSI interface %s\n",
173762306a36Sopenharmony_ci		   nd->link_up ? "up" : "down");
173862306a36Sopenharmony_ci}
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic int ftgmac100_setup_clk(struct ftgmac100 *priv)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	struct clk *clk;
174362306a36Sopenharmony_ci	int rc;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	clk = devm_clk_get(priv->dev, NULL /* MACCLK */);
174662306a36Sopenharmony_ci	if (IS_ERR(clk))
174762306a36Sopenharmony_ci		return PTR_ERR(clk);
174862306a36Sopenharmony_ci	priv->clk = clk;
174962306a36Sopenharmony_ci	rc = clk_prepare_enable(priv->clk);
175062306a36Sopenharmony_ci	if (rc)
175162306a36Sopenharmony_ci		return rc;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	/* Aspeed specifies a 100MHz clock is required for up to
175462306a36Sopenharmony_ci	 * 1000Mbit link speeds. As NCSI is limited to 100Mbit, 25MHz
175562306a36Sopenharmony_ci	 * is sufficient
175662306a36Sopenharmony_ci	 */
175762306a36Sopenharmony_ci	rc = clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ :
175862306a36Sopenharmony_ci			  FTGMAC_100MHZ);
175962306a36Sopenharmony_ci	if (rc)
176062306a36Sopenharmony_ci		goto cleanup_clk;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* RCLK is for RMII, typically used for NCSI. Optional because it's not
176362306a36Sopenharmony_ci	 * necessary if it's the AST2400 MAC, or the MAC is configured for
176462306a36Sopenharmony_ci	 * RGMII, or the controller is not an ASPEED-based controller.
176562306a36Sopenharmony_ci	 */
176662306a36Sopenharmony_ci	priv->rclk = devm_clk_get_optional(priv->dev, "RCLK");
176762306a36Sopenharmony_ci	rc = clk_prepare_enable(priv->rclk);
176862306a36Sopenharmony_ci	if (!rc)
176962306a36Sopenharmony_ci		return 0;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cicleanup_clk:
177262306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	return rc;
177562306a36Sopenharmony_ci}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_cistatic bool ftgmac100_has_child_node(struct device_node *np, const char *name)
177862306a36Sopenharmony_ci{
177962306a36Sopenharmony_ci	struct device_node *child_np = of_get_child_by_name(np, name);
178062306a36Sopenharmony_ci	bool ret = false;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	if (child_np) {
178362306a36Sopenharmony_ci		ret = true;
178462306a36Sopenharmony_ci		of_node_put(child_np);
178562306a36Sopenharmony_ci	}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	return ret;
178862306a36Sopenharmony_ci}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_cistatic int ftgmac100_probe(struct platform_device *pdev)
179162306a36Sopenharmony_ci{
179262306a36Sopenharmony_ci	struct resource *res;
179362306a36Sopenharmony_ci	int irq;
179462306a36Sopenharmony_ci	struct net_device *netdev;
179562306a36Sopenharmony_ci	struct ftgmac100 *priv;
179662306a36Sopenharmony_ci	struct device_node *np;
179762306a36Sopenharmony_ci	int err = 0;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180062306a36Sopenharmony_ci	if (!res)
180162306a36Sopenharmony_ci		return -ENXIO;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
180462306a36Sopenharmony_ci	if (irq < 0)
180562306a36Sopenharmony_ci		return irq;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	/* setup net_device */
180862306a36Sopenharmony_ci	netdev = alloc_etherdev(sizeof(*priv));
180962306a36Sopenharmony_ci	if (!netdev) {
181062306a36Sopenharmony_ci		err = -ENOMEM;
181162306a36Sopenharmony_ci		goto err_alloc_etherdev;
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	netdev->ethtool_ops = &ftgmac100_ethtool_ops;
181762306a36Sopenharmony_ci	netdev->netdev_ops = &ftgmac100_netdev_ops;
181862306a36Sopenharmony_ci	netdev->watchdog_timeo = 5 * HZ;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	platform_set_drvdata(pdev, netdev);
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	/* setup private data */
182362306a36Sopenharmony_ci	priv = netdev_priv(netdev);
182462306a36Sopenharmony_ci	priv->netdev = netdev;
182562306a36Sopenharmony_ci	priv->dev = &pdev->dev;
182662306a36Sopenharmony_ci	INIT_WORK(&priv->reset_task, ftgmac100_reset_task);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	/* map io memory */
182962306a36Sopenharmony_ci	priv->res = request_mem_region(res->start, resource_size(res),
183062306a36Sopenharmony_ci				       dev_name(&pdev->dev));
183162306a36Sopenharmony_ci	if (!priv->res) {
183262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not reserve memory region\n");
183362306a36Sopenharmony_ci		err = -ENOMEM;
183462306a36Sopenharmony_ci		goto err_req_mem;
183562306a36Sopenharmony_ci	}
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	priv->base = ioremap(res->start, resource_size(res));
183862306a36Sopenharmony_ci	if (!priv->base) {
183962306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
184062306a36Sopenharmony_ci		err = -EIO;
184162306a36Sopenharmony_ci		goto err_ioremap;
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	netdev->irq = irq;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	/* Enable pause */
184762306a36Sopenharmony_ci	priv->tx_pause = true;
184862306a36Sopenharmony_ci	priv->rx_pause = true;
184962306a36Sopenharmony_ci	priv->aneg_pause = true;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	/* MAC address from chip or random one */
185262306a36Sopenharmony_ci	err = ftgmac100_initial_mac(priv);
185362306a36Sopenharmony_ci	if (err)
185462306a36Sopenharmony_ci		goto err_phy_connect;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	np = pdev->dev.of_node;
185762306a36Sopenharmony_ci	if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
185862306a36Sopenharmony_ci		   of_device_is_compatible(np, "aspeed,ast2500-mac") ||
185962306a36Sopenharmony_ci		   of_device_is_compatible(np, "aspeed,ast2600-mac"))) {
186062306a36Sopenharmony_ci		priv->rxdes0_edorr_mask = BIT(30);
186162306a36Sopenharmony_ci		priv->txdes0_edotr_mask = BIT(30);
186262306a36Sopenharmony_ci		priv->is_aspeed = true;
186362306a36Sopenharmony_ci	} else {
186462306a36Sopenharmony_ci		priv->rxdes0_edorr_mask = BIT(15);
186562306a36Sopenharmony_ci		priv->txdes0_edotr_mask = BIT(15);
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	if (np && of_get_property(np, "use-ncsi", NULL)) {
186962306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_NET_NCSI)) {
187062306a36Sopenharmony_ci			dev_err(&pdev->dev, "NCSI stack not enabled\n");
187162306a36Sopenharmony_ci			err = -EINVAL;
187262306a36Sopenharmony_ci			goto err_phy_connect;
187362306a36Sopenharmony_ci		}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci		dev_info(&pdev->dev, "Using NCSI interface\n");
187662306a36Sopenharmony_ci		priv->use_ncsi = true;
187762306a36Sopenharmony_ci		priv->ndev = ncsi_register_dev(netdev, ftgmac100_ncsi_handler);
187862306a36Sopenharmony_ci		if (!priv->ndev) {
187962306a36Sopenharmony_ci			err = -EINVAL;
188062306a36Sopenharmony_ci			goto err_phy_connect;
188162306a36Sopenharmony_ci		}
188262306a36Sopenharmony_ci	} else if (np && of_phy_is_fixed_link(np)) {
188362306a36Sopenharmony_ci		struct phy_device *phy;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci		err = of_phy_register_fixed_link(np);
188662306a36Sopenharmony_ci		if (err) {
188762306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to register fixed PHY\n");
188862306a36Sopenharmony_ci			goto err_phy_connect;
188962306a36Sopenharmony_ci		}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci		phy = of_phy_get_and_connect(priv->netdev, np,
189262306a36Sopenharmony_ci					     &ftgmac100_adjust_link);
189362306a36Sopenharmony_ci		if (!phy) {
189462306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to connect to fixed PHY\n");
189562306a36Sopenharmony_ci			of_phy_deregister_fixed_link(np);
189662306a36Sopenharmony_ci			err = -EINVAL;
189762306a36Sopenharmony_ci			goto err_phy_connect;
189862306a36Sopenharmony_ci		}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci		/* Display what we found */
190162306a36Sopenharmony_ci		phy_attached_info(phy);
190262306a36Sopenharmony_ci	} else if (np && of_get_property(np, "phy-handle", NULL)) {
190362306a36Sopenharmony_ci		struct phy_device *phy;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci		/* Support "mdio"/"phy" child nodes for ast2400/2500 with
190662306a36Sopenharmony_ci		 * an embedded MDIO controller. Automatically scan the DTS for
190762306a36Sopenharmony_ci		 * available PHYs and register them.
190862306a36Sopenharmony_ci		 */
190962306a36Sopenharmony_ci		if (of_device_is_compatible(np, "aspeed,ast2400-mac") ||
191062306a36Sopenharmony_ci		    of_device_is_compatible(np, "aspeed,ast2500-mac")) {
191162306a36Sopenharmony_ci			err = ftgmac100_setup_mdio(netdev);
191262306a36Sopenharmony_ci			if (err)
191362306a36Sopenharmony_ci				goto err_setup_mdio;
191462306a36Sopenharmony_ci		}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		phy = of_phy_get_and_connect(priv->netdev, np,
191762306a36Sopenharmony_ci					     &ftgmac100_adjust_link);
191862306a36Sopenharmony_ci		if (!phy) {
191962306a36Sopenharmony_ci			dev_err(&pdev->dev, "Failed to connect to phy\n");
192062306a36Sopenharmony_ci			err = -EINVAL;
192162306a36Sopenharmony_ci			goto err_phy_connect;
192262306a36Sopenharmony_ci		}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci		/* Indicate that we support PAUSE frames (see comment in
192562306a36Sopenharmony_ci		 * Documentation/networking/phy.rst)
192662306a36Sopenharmony_ci		 */
192762306a36Sopenharmony_ci		phy_support_asym_pause(phy);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		/* Display what we found */
193062306a36Sopenharmony_ci		phy_attached_info(phy);
193162306a36Sopenharmony_ci	} else if (np && !ftgmac100_has_child_node(np, "mdio")) {
193262306a36Sopenharmony_ci		/* Support legacy ASPEED devicetree descriptions that decribe a
193362306a36Sopenharmony_ci		 * MAC with an embedded MDIO controller but have no "mdio"
193462306a36Sopenharmony_ci		 * child node. Automatically scan the MDIO bus for available
193562306a36Sopenharmony_ci		 * PHYs.
193662306a36Sopenharmony_ci		 */
193762306a36Sopenharmony_ci		priv->use_ncsi = false;
193862306a36Sopenharmony_ci		err = ftgmac100_setup_mdio(netdev);
193962306a36Sopenharmony_ci		if (err)
194062306a36Sopenharmony_ci			goto err_setup_mdio;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci		err = ftgmac100_mii_probe(netdev);
194362306a36Sopenharmony_ci		if (err) {
194462306a36Sopenharmony_ci			dev_err(priv->dev, "MII probe failed!\n");
194562306a36Sopenharmony_ci			goto err_ncsi_dev;
194662306a36Sopenharmony_ci		}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (priv->is_aspeed) {
195162306a36Sopenharmony_ci		err = ftgmac100_setup_clk(priv);
195262306a36Sopenharmony_ci		if (err)
195362306a36Sopenharmony_ci			goto err_phy_connect;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		/* Disable ast2600 problematic HW arbitration */
195662306a36Sopenharmony_ci		if (of_device_is_compatible(np, "aspeed,ast2600-mac"))
195762306a36Sopenharmony_ci			iowrite32(FTGMAC100_TM_DEFAULT,
195862306a36Sopenharmony_ci				  priv->base + FTGMAC100_OFFSET_TM);
195962306a36Sopenharmony_ci	}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	/* Default ring sizes */
196262306a36Sopenharmony_ci	priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
196362306a36Sopenharmony_ci	priv->tx_q_entries = priv->new_tx_q_entries = DEF_TX_QUEUE_ENTRIES;
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	/* Base feature set */
196662306a36Sopenharmony_ci	netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM |
196762306a36Sopenharmony_ci		NETIF_F_GRO | NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX |
196862306a36Sopenharmony_ci		NETIF_F_HW_VLAN_CTAG_TX;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (priv->use_ncsi)
197162306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	/* AST2400  doesn't have working HW checksum generation */
197462306a36Sopenharmony_ci	if (np && (of_device_is_compatible(np, "aspeed,ast2400-mac")))
197562306a36Sopenharmony_ci		netdev->hw_features &= ~NETIF_F_HW_CSUM;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	/* AST2600 tx checksum with NCSI is broken */
197862306a36Sopenharmony_ci	if (priv->use_ncsi && of_device_is_compatible(np, "aspeed,ast2600-mac"))
197962306a36Sopenharmony_ci		netdev->hw_features &= ~NETIF_F_HW_CSUM;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	if (np && of_get_property(np, "no-hw-checksum", NULL))
198262306a36Sopenharmony_ci		netdev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM);
198362306a36Sopenharmony_ci	netdev->features |= netdev->hw_features;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	/* register network device */
198662306a36Sopenharmony_ci	err = register_netdev(netdev);
198762306a36Sopenharmony_ci	if (err) {
198862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register netdev\n");
198962306a36Sopenharmony_ci		goto err_register_netdev;
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	netdev_info(netdev, "irq %d, mapped at %p\n", netdev->irq, priv->base);
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	return 0;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_cierr_register_netdev:
199762306a36Sopenharmony_ci	clk_disable_unprepare(priv->rclk);
199862306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
199962306a36Sopenharmony_cierr_phy_connect:
200062306a36Sopenharmony_ci	ftgmac100_phy_disconnect(netdev);
200162306a36Sopenharmony_cierr_ncsi_dev:
200262306a36Sopenharmony_ci	if (priv->ndev)
200362306a36Sopenharmony_ci		ncsi_unregister_dev(priv->ndev);
200462306a36Sopenharmony_ci	ftgmac100_destroy_mdio(netdev);
200562306a36Sopenharmony_cierr_setup_mdio:
200662306a36Sopenharmony_ci	iounmap(priv->base);
200762306a36Sopenharmony_cierr_ioremap:
200862306a36Sopenharmony_ci	release_resource(priv->res);
200962306a36Sopenharmony_cierr_req_mem:
201062306a36Sopenharmony_ci	free_netdev(netdev);
201162306a36Sopenharmony_cierr_alloc_etherdev:
201262306a36Sopenharmony_ci	return err;
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_cistatic int ftgmac100_remove(struct platform_device *pdev)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	struct net_device *netdev;
201862306a36Sopenharmony_ci	struct ftgmac100 *priv;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	netdev = platform_get_drvdata(pdev);
202162306a36Sopenharmony_ci	priv = netdev_priv(netdev);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if (priv->ndev)
202462306a36Sopenharmony_ci		ncsi_unregister_dev(priv->ndev);
202562306a36Sopenharmony_ci	unregister_netdev(netdev);
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	clk_disable_unprepare(priv->rclk);
202862306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	/* There's a small chance the reset task will have been re-queued,
203162306a36Sopenharmony_ci	 * during stop, make sure it's gone before we free the structure.
203262306a36Sopenharmony_ci	 */
203362306a36Sopenharmony_ci	cancel_work_sync(&priv->reset_task);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	ftgmac100_phy_disconnect(netdev);
203662306a36Sopenharmony_ci	ftgmac100_destroy_mdio(netdev);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	iounmap(priv->base);
203962306a36Sopenharmony_ci	release_resource(priv->res);
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	netif_napi_del(&priv->napi);
204262306a36Sopenharmony_ci	free_netdev(netdev);
204362306a36Sopenharmony_ci	return 0;
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_cistatic const struct of_device_id ftgmac100_of_match[] = {
204762306a36Sopenharmony_ci	{ .compatible = "faraday,ftgmac100" },
204862306a36Sopenharmony_ci	{ }
204962306a36Sopenharmony_ci};
205062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ftgmac100_of_match);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_cistatic struct platform_driver ftgmac100_driver = {
205362306a36Sopenharmony_ci	.probe	= ftgmac100_probe,
205462306a36Sopenharmony_ci	.remove	= ftgmac100_remove,
205562306a36Sopenharmony_ci	.driver	= {
205662306a36Sopenharmony_ci		.name		= DRV_NAME,
205762306a36Sopenharmony_ci		.of_match_table	= ftgmac100_of_match,
205862306a36Sopenharmony_ci	},
205962306a36Sopenharmony_ci};
206062306a36Sopenharmony_cimodule_platform_driver(ftgmac100_driver);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ciMODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
206362306a36Sopenharmony_ciMODULE_DESCRIPTION("FTGMAC100 driver");
206462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2065