18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * RDC R6040 Fast Ethernet MAC support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw>
68c2ecf20Sopenharmony_ci * Copyright (C) 2007
78c2ecf20Sopenharmony_ci *	Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
88c2ecf20Sopenharmony_ci * Copyright (C) 2007-2012 Florian Fainelli <f.fainelli@gmail.com>
98c2ecf20Sopenharmony_ci*/
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
148c2ecf20Sopenharmony_ci#include <linux/string.h>
158c2ecf20Sopenharmony_ci#include <linux/timer.h>
168c2ecf20Sopenharmony_ci#include <linux/errno.h>
178c2ecf20Sopenharmony_ci#include <linux/ioport.h>
188c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
198c2ecf20Sopenharmony_ci#include <linux/pci.h>
208c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
218c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
228c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/mii.h>
258c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
268c2ecf20Sopenharmony_ci#include <linux/crc32.h>
278c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
288c2ecf20Sopenharmony_ci#include <linux/bitops.h>
298c2ecf20Sopenharmony_ci#include <linux/io.h>
308c2ecf20Sopenharmony_ci#include <linux/irq.h>
318c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
328c2ecf20Sopenharmony_ci#include <linux/phy.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <asm/processor.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define DRV_NAME	"r6040"
378c2ecf20Sopenharmony_ci#define DRV_VERSION	"0.29"
388c2ecf20Sopenharmony_ci#define DRV_RELDATE	"04Jul2016"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
418c2ecf20Sopenharmony_ci#define TX_TIMEOUT	(6000 * HZ / 1000)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* RDC MAC I/O Size */
448c2ecf20Sopenharmony_ci#define R6040_IO_SIZE	256
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* MAX RDC MAC */
478c2ecf20Sopenharmony_ci#define MAX_MAC		2
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* MAC registers */
508c2ecf20Sopenharmony_ci#define MCR0		0x00	/* Control register 0 */
518c2ecf20Sopenharmony_ci#define  MCR0_RCVEN	0x0002	/* Receive enable */
528c2ecf20Sopenharmony_ci#define  MCR0_PROMISC	0x0020	/* Promiscuous mode */
538c2ecf20Sopenharmony_ci#define  MCR0_HASH_EN	0x0100	/* Enable multicast hash table function */
548c2ecf20Sopenharmony_ci#define  MCR0_XMTEN	0x1000	/* Transmission enable */
558c2ecf20Sopenharmony_ci#define  MCR0_FD	0x8000	/* Full/Half duplex */
568c2ecf20Sopenharmony_ci#define MCR1		0x04	/* Control register 1 */
578c2ecf20Sopenharmony_ci#define  MAC_RST	0x0001	/* Reset the MAC */
588c2ecf20Sopenharmony_ci#define MBCR		0x08	/* Bus control */
598c2ecf20Sopenharmony_ci#define MT_ICR		0x0C	/* TX interrupt control */
608c2ecf20Sopenharmony_ci#define MR_ICR		0x10	/* RX interrupt control */
618c2ecf20Sopenharmony_ci#define MTPR		0x14	/* TX poll command register */
628c2ecf20Sopenharmony_ci#define  TM2TX		0x0001	/* Trigger MAC to transmit */
638c2ecf20Sopenharmony_ci#define MR_BSR		0x18	/* RX buffer size */
648c2ecf20Sopenharmony_ci#define MR_DCR		0x1A	/* RX descriptor control */
658c2ecf20Sopenharmony_ci#define MLSR		0x1C	/* Last status */
668c2ecf20Sopenharmony_ci#define  TX_FIFO_UNDR	0x0200	/* TX FIFO under-run */
678c2ecf20Sopenharmony_ci#define	 TX_EXCEEDC	0x2000	/* Transmit exceed collision */
688c2ecf20Sopenharmony_ci#define  TX_LATEC	0x4000	/* Transmit late collision */
698c2ecf20Sopenharmony_ci#define MMDIO		0x20	/* MDIO control register */
708c2ecf20Sopenharmony_ci#define  MDIO_WRITE	0x4000	/* MDIO write */
718c2ecf20Sopenharmony_ci#define  MDIO_READ	0x2000	/* MDIO read */
728c2ecf20Sopenharmony_ci#define MMRD		0x24	/* MDIO read data register */
738c2ecf20Sopenharmony_ci#define MMWD		0x28	/* MDIO write data register */
748c2ecf20Sopenharmony_ci#define MTD_SA0		0x2C	/* TX descriptor start address 0 */
758c2ecf20Sopenharmony_ci#define MTD_SA1		0x30	/* TX descriptor start address 1 */
768c2ecf20Sopenharmony_ci#define MRD_SA0		0x34	/* RX descriptor start address 0 */
778c2ecf20Sopenharmony_ci#define MRD_SA1		0x38	/* RX descriptor start address 1 */
788c2ecf20Sopenharmony_ci#define MISR		0x3C	/* Status register */
798c2ecf20Sopenharmony_ci#define MIER		0x40	/* INT enable register */
808c2ecf20Sopenharmony_ci#define  MSK_INT	0x0000	/* Mask off interrupts */
818c2ecf20Sopenharmony_ci#define  RX_FINISH	0x0001  /* RX finished */
828c2ecf20Sopenharmony_ci#define  RX_NO_DESC	0x0002  /* No RX descriptor available */
838c2ecf20Sopenharmony_ci#define  RX_FIFO_FULL	0x0004  /* RX FIFO full */
848c2ecf20Sopenharmony_ci#define  RX_EARLY	0x0008  /* RX early */
858c2ecf20Sopenharmony_ci#define  TX_FINISH	0x0010  /* TX finished */
868c2ecf20Sopenharmony_ci#define  TX_EARLY	0x0080  /* TX early */
878c2ecf20Sopenharmony_ci#define  EVENT_OVRFL	0x0100  /* Event counter overflow */
888c2ecf20Sopenharmony_ci#define  LINK_CHANGED	0x0200  /* PHY link changed */
898c2ecf20Sopenharmony_ci#define ME_CISR		0x44	/* Event counter INT status */
908c2ecf20Sopenharmony_ci#define ME_CIER		0x48	/* Event counter INT enable  */
918c2ecf20Sopenharmony_ci#define MR_CNT		0x50	/* Successfully received packet counter */
928c2ecf20Sopenharmony_ci#define ME_CNT0		0x52	/* Event counter 0 */
938c2ecf20Sopenharmony_ci#define ME_CNT1		0x54	/* Event counter 1 */
948c2ecf20Sopenharmony_ci#define ME_CNT2		0x56	/* Event counter 2 */
958c2ecf20Sopenharmony_ci#define ME_CNT3		0x58	/* Event counter 3 */
968c2ecf20Sopenharmony_ci#define MT_CNT		0x5A	/* Successfully transmit packet counter */
978c2ecf20Sopenharmony_ci#define ME_CNT4		0x5C	/* Event counter 4 */
988c2ecf20Sopenharmony_ci#define MP_CNT		0x5E	/* Pause frame counter register */
998c2ecf20Sopenharmony_ci#define MAR0		0x60	/* Hash table 0 */
1008c2ecf20Sopenharmony_ci#define MAR1		0x62	/* Hash table 1 */
1018c2ecf20Sopenharmony_ci#define MAR2		0x64	/* Hash table 2 */
1028c2ecf20Sopenharmony_ci#define MAR3		0x66	/* Hash table 3 */
1038c2ecf20Sopenharmony_ci#define MID_0L		0x68	/* Multicast address MID0 Low */
1048c2ecf20Sopenharmony_ci#define MID_0M		0x6A	/* Multicast address MID0 Medium */
1058c2ecf20Sopenharmony_ci#define MID_0H		0x6C	/* Multicast address MID0 High */
1068c2ecf20Sopenharmony_ci#define MID_1L		0x70	/* MID1 Low */
1078c2ecf20Sopenharmony_ci#define MID_1M		0x72	/* MID1 Medium */
1088c2ecf20Sopenharmony_ci#define MID_1H		0x74	/* MID1 High */
1098c2ecf20Sopenharmony_ci#define MID_2L		0x78	/* MID2 Low */
1108c2ecf20Sopenharmony_ci#define MID_2M		0x7A	/* MID2 Medium */
1118c2ecf20Sopenharmony_ci#define MID_2H		0x7C	/* MID2 High */
1128c2ecf20Sopenharmony_ci#define MID_3L		0x80	/* MID3 Low */
1138c2ecf20Sopenharmony_ci#define MID_3M		0x82	/* MID3 Medium */
1148c2ecf20Sopenharmony_ci#define MID_3H		0x84	/* MID3 High */
1158c2ecf20Sopenharmony_ci#define PHY_CC		0x88	/* PHY status change configuration register */
1168c2ecf20Sopenharmony_ci#define  SCEN		0x8000	/* PHY status change enable */
1178c2ecf20Sopenharmony_ci#define  PHYAD_SHIFT	8	/* PHY address shift */
1188c2ecf20Sopenharmony_ci#define  TMRDIV_SHIFT	0	/* Timer divider shift */
1198c2ecf20Sopenharmony_ci#define PHY_ST		0x8A	/* PHY status register */
1208c2ecf20Sopenharmony_ci#define MAC_SM		0xAC	/* MAC status machine */
1218c2ecf20Sopenharmony_ci#define  MAC_SM_RST	0x0002	/* MAC status machine reset */
1228c2ecf20Sopenharmony_ci#define MD_CSC		0xb6	/* MDC speed control register */
1238c2ecf20Sopenharmony_ci#define  MD_CSC_DEFAULT	0x0030
1248c2ecf20Sopenharmony_ci#define MAC_ID		0xBE	/* Identifier register */
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci#define TX_DCNT		0x80	/* TX descriptor count */
1278c2ecf20Sopenharmony_ci#define RX_DCNT		0x80	/* RX descriptor count */
1288c2ecf20Sopenharmony_ci#define MAX_BUF_SIZE	0x600
1298c2ecf20Sopenharmony_ci#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))
1308c2ecf20Sopenharmony_ci#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))
1318c2ecf20Sopenharmony_ci#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */
1328c2ecf20Sopenharmony_ci#define MCAST_MAX	3	/* Max number multicast addresses to filter */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define MAC_DEF_TIMEOUT	2048	/* Default MAC read/write operation timeout */
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* Descriptor status */
1378c2ecf20Sopenharmony_ci#define DSC_OWNER_MAC	0x8000	/* MAC is the owner of this descriptor */
1388c2ecf20Sopenharmony_ci#define DSC_RX_OK	0x4000	/* RX was successful */
1398c2ecf20Sopenharmony_ci#define DSC_RX_ERR	0x0800	/* RX PHY error */
1408c2ecf20Sopenharmony_ci#define DSC_RX_ERR_DRI	0x0400	/* RX dribble packet */
1418c2ecf20Sopenharmony_ci#define DSC_RX_ERR_BUF	0x0200	/* RX length exceeds buffer size */
1428c2ecf20Sopenharmony_ci#define DSC_RX_ERR_LONG	0x0100	/* RX length > maximum packet length */
1438c2ecf20Sopenharmony_ci#define DSC_RX_ERR_RUNT	0x0080	/* RX packet length < 64 byte */
1448c2ecf20Sopenharmony_ci#define DSC_RX_ERR_CRC	0x0040	/* RX CRC error */
1458c2ecf20Sopenharmony_ci#define DSC_RX_BCAST	0x0020	/* RX broadcast (no error) */
1468c2ecf20Sopenharmony_ci#define DSC_RX_MCAST	0x0010	/* RX multicast (no error) */
1478c2ecf20Sopenharmony_ci#define DSC_RX_MCH_HIT	0x0008	/* RX multicast hit in hash table (no error) */
1488c2ecf20Sopenharmony_ci#define DSC_RX_MIDH_HIT	0x0004	/* RX MID table hit (no error) */
1498c2ecf20Sopenharmony_ci#define DSC_RX_IDX_MID_MASK 3	/* RX mask for the index of matched MIDx */
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"
1528c2ecf20Sopenharmony_ci	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"
1538c2ecf20Sopenharmony_ci	"Florian Fainelli <f.fainelli@gmail.com>");
1548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");
1568c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION " " DRV_RELDATE);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* RX and TX interrupts that we handle */
1598c2ecf20Sopenharmony_ci#define RX_INTS			(RX_FIFO_FULL | RX_NO_DESC | RX_FINISH)
1608c2ecf20Sopenharmony_ci#define TX_INTS			(TX_FINISH)
1618c2ecf20Sopenharmony_ci#define INT_MASK		(RX_INTS | TX_INTS)
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistruct r6040_descriptor {
1648c2ecf20Sopenharmony_ci	u16	status, len;		/* 0-3 */
1658c2ecf20Sopenharmony_ci	__le32	buf;			/* 4-7 */
1668c2ecf20Sopenharmony_ci	__le32	ndesc;			/* 8-B */
1678c2ecf20Sopenharmony_ci	u32	rev1;			/* C-F */
1688c2ecf20Sopenharmony_ci	char	*vbufp;			/* 10-13 */
1698c2ecf20Sopenharmony_ci	struct r6040_descriptor *vndescp;	/* 14-17 */
1708c2ecf20Sopenharmony_ci	struct sk_buff *skb_ptr;	/* 18-1B */
1718c2ecf20Sopenharmony_ci	u32	rev2;			/* 1C-1F */
1728c2ecf20Sopenharmony_ci} __aligned(32);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistruct r6040_private {
1758c2ecf20Sopenharmony_ci	spinlock_t lock;		/* driver lock */
1768c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
1778c2ecf20Sopenharmony_ci	struct r6040_descriptor *rx_insert_ptr;
1788c2ecf20Sopenharmony_ci	struct r6040_descriptor *rx_remove_ptr;
1798c2ecf20Sopenharmony_ci	struct r6040_descriptor *tx_insert_ptr;
1808c2ecf20Sopenharmony_ci	struct r6040_descriptor *tx_remove_ptr;
1818c2ecf20Sopenharmony_ci	struct r6040_descriptor *rx_ring;
1828c2ecf20Sopenharmony_ci	struct r6040_descriptor *tx_ring;
1838c2ecf20Sopenharmony_ci	dma_addr_t rx_ring_dma;
1848c2ecf20Sopenharmony_ci	dma_addr_t tx_ring_dma;
1858c2ecf20Sopenharmony_ci	u16	tx_free_desc;
1868c2ecf20Sopenharmony_ci	u16	mcr0;
1878c2ecf20Sopenharmony_ci	struct net_device *dev;
1888c2ecf20Sopenharmony_ci	struct mii_bus *mii_bus;
1898c2ecf20Sopenharmony_ci	struct napi_struct napi;
1908c2ecf20Sopenharmony_ci	void __iomem *base;
1918c2ecf20Sopenharmony_ci	int old_link;
1928c2ecf20Sopenharmony_ci	int old_duplex;
1938c2ecf20Sopenharmony_ci};
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic char version[] = DRV_NAME
1968c2ecf20Sopenharmony_ci	": RDC R6040 NAPI net driver,"
1978c2ecf20Sopenharmony_ci	"version "DRV_VERSION " (" DRV_RELDATE ")";
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/* Read a word data from PHY Chip */
2008c2ecf20Sopenharmony_cistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
2038c2ecf20Sopenharmony_ci	u16 cmd;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);
2068c2ecf20Sopenharmony_ci	/* Wait for the read bit to be cleared */
2078c2ecf20Sopenharmony_ci	while (limit--) {
2088c2ecf20Sopenharmony_ci		cmd = ioread16(ioaddr + MMDIO);
2098c2ecf20Sopenharmony_ci		if (!(cmd & MDIO_READ))
2108c2ecf20Sopenharmony_ci			break;
2118c2ecf20Sopenharmony_ci		udelay(1);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (limit < 0)
2158c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return ioread16(ioaddr + MMRD);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* Write a word data from PHY Chip */
2218c2ecf20Sopenharmony_cistatic int r6040_phy_write(void __iomem *ioaddr,
2228c2ecf20Sopenharmony_ci					int phy_addr, int reg, u16 val)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
2258c2ecf20Sopenharmony_ci	u16 cmd;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	iowrite16(val, ioaddr + MMWD);
2288c2ecf20Sopenharmony_ci	/* Write the command to the MDIO bus */
2298c2ecf20Sopenharmony_ci	iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);
2308c2ecf20Sopenharmony_ci	/* Wait for the write bit to be cleared */
2318c2ecf20Sopenharmony_ci	while (limit--) {
2328c2ecf20Sopenharmony_ci		cmd = ioread16(ioaddr + MMDIO);
2338c2ecf20Sopenharmony_ci		if (!(cmd & MDIO_WRITE))
2348c2ecf20Sopenharmony_ci			break;
2358c2ecf20Sopenharmony_ci		udelay(1);
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return (limit < 0) ? -ETIMEDOUT : 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct net_device *dev = bus->priv;
2448c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
2458c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return r6040_phy_read(ioaddr, phy_addr, reg);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
2518c2ecf20Sopenharmony_ci						int reg, u16 value)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct net_device *dev = bus->priv;
2548c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
2558c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return r6040_phy_write(ioaddr, phy_addr, reg, value);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void r6040_free_txbufs(struct net_device *dev)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
2638c2ecf20Sopenharmony_ci	int i;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	for (i = 0; i < TX_DCNT; i++) {
2668c2ecf20Sopenharmony_ci		if (lp->tx_insert_ptr->skb_ptr) {
2678c2ecf20Sopenharmony_ci			dma_unmap_single(&lp->pdev->dev,
2688c2ecf20Sopenharmony_ci					 le32_to_cpu(lp->tx_insert_ptr->buf),
2698c2ecf20Sopenharmony_ci					 MAX_BUF_SIZE, DMA_TO_DEVICE);
2708c2ecf20Sopenharmony_ci			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
2718c2ecf20Sopenharmony_ci			lp->tx_insert_ptr->skb_ptr = NULL;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic void r6040_free_rxbufs(struct net_device *dev)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
2808c2ecf20Sopenharmony_ci	int i;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	for (i = 0; i < RX_DCNT; i++) {
2838c2ecf20Sopenharmony_ci		if (lp->rx_insert_ptr->skb_ptr) {
2848c2ecf20Sopenharmony_ci			dma_unmap_single(&lp->pdev->dev,
2858c2ecf20Sopenharmony_ci					 le32_to_cpu(lp->rx_insert_ptr->buf),
2868c2ecf20Sopenharmony_ci					 MAX_BUF_SIZE, DMA_FROM_DEVICE);
2878c2ecf20Sopenharmony_ci			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
2888c2ecf20Sopenharmony_ci			lp->rx_insert_ptr->skb_ptr = NULL;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
2958c2ecf20Sopenharmony_ci				 dma_addr_t desc_dma, int size)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct r6040_descriptor *desc = desc_ring;
2988c2ecf20Sopenharmony_ci	dma_addr_t mapping = desc_dma;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	while (size-- > 0) {
3018c2ecf20Sopenharmony_ci		mapping += sizeof(*desc);
3028c2ecf20Sopenharmony_ci		desc->ndesc = cpu_to_le32(mapping);
3038c2ecf20Sopenharmony_ci		desc->vndescp = desc + 1;
3048c2ecf20Sopenharmony_ci		desc++;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci	desc--;
3078c2ecf20Sopenharmony_ci	desc->ndesc = cpu_to_le32(desc_dma);
3088c2ecf20Sopenharmony_ci	desc->vndescp = desc_ring;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic void r6040_init_txbufs(struct net_device *dev)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	lp->tx_free_desc = TX_DCNT;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
3188c2ecf20Sopenharmony_ci	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int r6040_alloc_rxbufs(struct net_device *dev)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
3248c2ecf20Sopenharmony_ci	struct r6040_descriptor *desc;
3258c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3268c2ecf20Sopenharmony_ci	int rc;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
3298c2ecf20Sopenharmony_ci	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* Allocate skbs for the rx descriptors */
3328c2ecf20Sopenharmony_ci	desc = lp->rx_ring;
3338c2ecf20Sopenharmony_ci	do {
3348c2ecf20Sopenharmony_ci		skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
3358c2ecf20Sopenharmony_ci		if (!skb) {
3368c2ecf20Sopenharmony_ci			rc = -ENOMEM;
3378c2ecf20Sopenharmony_ci			goto err_exit;
3388c2ecf20Sopenharmony_ci		}
3398c2ecf20Sopenharmony_ci		desc->skb_ptr = skb;
3408c2ecf20Sopenharmony_ci		desc->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev,
3418c2ecf20Sopenharmony_ci						       desc->skb_ptr->data,
3428c2ecf20Sopenharmony_ci						       MAX_BUF_SIZE,
3438c2ecf20Sopenharmony_ci						       DMA_FROM_DEVICE));
3448c2ecf20Sopenharmony_ci		desc->status = DSC_OWNER_MAC;
3458c2ecf20Sopenharmony_ci		desc = desc->vndescp;
3468c2ecf20Sopenharmony_ci	} while (desc != lp->rx_ring);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	return 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cierr_exit:
3518c2ecf20Sopenharmony_ci	/* Deallocate all previously allocated skbs */
3528c2ecf20Sopenharmony_ci	r6040_free_rxbufs(dev);
3538c2ecf20Sopenharmony_ci	return rc;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void r6040_reset_mac(struct r6040_private *lp)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
3598c2ecf20Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
3608c2ecf20Sopenharmony_ci	u16 cmd, md_csc;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	md_csc = ioread16(ioaddr + MD_CSC);
3638c2ecf20Sopenharmony_ci	iowrite16(MAC_RST, ioaddr + MCR1);
3648c2ecf20Sopenharmony_ci	while (limit--) {
3658c2ecf20Sopenharmony_ci		cmd = ioread16(ioaddr + MCR1);
3668c2ecf20Sopenharmony_ci		if (cmd & MAC_RST)
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Reset internal state machine */
3718c2ecf20Sopenharmony_ci	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
3728c2ecf20Sopenharmony_ci	iowrite16(0, ioaddr + MAC_SM);
3738c2ecf20Sopenharmony_ci	mdelay(5);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* Restore MDIO clock frequency */
3768c2ecf20Sopenharmony_ci	if (md_csc != MD_CSC_DEFAULT)
3778c2ecf20Sopenharmony_ci		iowrite16(md_csc, ioaddr + MD_CSC);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic void r6040_init_mac_regs(struct net_device *dev)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
3838c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* Mask Off Interrupt */
3868c2ecf20Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* Reset RDC MAC */
3898c2ecf20Sopenharmony_ci	r6040_reset_mac(lp);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* MAC Bus Control Register */
3928c2ecf20Sopenharmony_ci	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/* Buffer Size Register */
3958c2ecf20Sopenharmony_ci	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* Write TX ring start address */
3988c2ecf20Sopenharmony_ci	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
3998c2ecf20Sopenharmony_ci	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* Write RX ring start address */
4028c2ecf20Sopenharmony_ci	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
4038c2ecf20Sopenharmony_ci	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* Set interrupt waiting time and packet numbers */
4068c2ecf20Sopenharmony_ci	iowrite16(0, ioaddr + MT_ICR);
4078c2ecf20Sopenharmony_ci	iowrite16(0, ioaddr + MR_ICR);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Enable interrupts */
4108c2ecf20Sopenharmony_ci	iowrite16(INT_MASK, ioaddr + MIER);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* Enable TX and RX */
4138c2ecf20Sopenharmony_ci	iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Let TX poll the descriptors
4168c2ecf20Sopenharmony_ci	 * we may got called by r6040_tx_timeout which has left
4178c2ecf20Sopenharmony_ci	 * some unsent tx buffers */
4188c2ecf20Sopenharmony_ci	iowrite16(TM2TX, ioaddr + MTPR);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic void r6040_tx_timeout(struct net_device *dev, unsigned int txqueue)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
4248c2ecf20Sopenharmony_ci	void __iomem *ioaddr = priv->base;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	netdev_warn(dev, "transmit timed out, int enable %4.4x "
4278c2ecf20Sopenharmony_ci		"status %4.4x\n",
4288c2ecf20Sopenharmony_ci		ioread16(ioaddr + MIER),
4298c2ecf20Sopenharmony_ci		ioread16(ioaddr + MISR));
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	dev->stats.tx_errors++;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* Reset MAC and re-init all registers */
4348c2ecf20Sopenharmony_ci	r6040_init_mac_regs(dev);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic struct net_device_stats *r6040_get_stats(struct net_device *dev)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
4408c2ecf20Sopenharmony_ci	void __iomem *ioaddr = priv->base;
4418c2ecf20Sopenharmony_ci	unsigned long flags;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
4448c2ecf20Sopenharmony_ci	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
4458c2ecf20Sopenharmony_ci	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);
4468c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	return &dev->stats;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci/* Stop RDC MAC and Free the allocated resource */
4528c2ecf20Sopenharmony_cistatic void r6040_down(struct net_device *dev)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
4558c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
4568c2ecf20Sopenharmony_ci	u16 *adrp;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* Stop MAC */
4598c2ecf20Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Reset RDC MAC */
4628c2ecf20Sopenharmony_ci	r6040_reset_mac(lp);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	/* Restore MAC Address to MIDx */
4658c2ecf20Sopenharmony_ci	adrp = (u16 *) dev->dev_addr;
4668c2ecf20Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
4678c2ecf20Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
4688c2ecf20Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic int r6040_close(struct net_device *dev)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
4748c2ecf20Sopenharmony_ci	struct pci_dev *pdev = lp->pdev;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	phy_stop(dev->phydev);
4778c2ecf20Sopenharmony_ci	napi_disable(&lp->napi);
4788c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	spin_lock_irq(&lp->lock);
4818c2ecf20Sopenharmony_ci	r6040_down(dev);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* Free RX buffer */
4848c2ecf20Sopenharmony_ci	r6040_free_rxbufs(dev);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* Free TX buffer */
4878c2ecf20Sopenharmony_ci	r6040_free_txbufs(dev);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	spin_unlock_irq(&lp->lock);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	free_irq(dev->irq, dev);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* Free Descriptor memory */
4948c2ecf20Sopenharmony_ci	if (lp->rx_ring) {
4958c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, RX_DESC_SIZE, lp->rx_ring,
4968c2ecf20Sopenharmony_ci				  lp->rx_ring_dma);
4978c2ecf20Sopenharmony_ci		lp->rx_ring = NULL;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	if (lp->tx_ring) {
5018c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev, TX_DESC_SIZE, lp->tx_ring,
5028c2ecf20Sopenharmony_ci				  lp->tx_ring_dma);
5038c2ecf20Sopenharmony_ci		lp->tx_ring = NULL;
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return 0;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic int r6040_rx(struct net_device *dev, int limit)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
5128c2ecf20Sopenharmony_ci	struct r6040_descriptor *descptr = priv->rx_remove_ptr;
5138c2ecf20Sopenharmony_ci	struct sk_buff *skb_ptr, *new_skb;
5148c2ecf20Sopenharmony_ci	int count = 0;
5158c2ecf20Sopenharmony_ci	u16 err;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* Limit not reached and the descriptor belongs to the CPU */
5188c2ecf20Sopenharmony_ci	while (count < limit && !(descptr->status & DSC_OWNER_MAC)) {
5198c2ecf20Sopenharmony_ci		/* Read the descriptor status */
5208c2ecf20Sopenharmony_ci		err = descptr->status;
5218c2ecf20Sopenharmony_ci		/* Global error status set */
5228c2ecf20Sopenharmony_ci		if (err & DSC_RX_ERR) {
5238c2ecf20Sopenharmony_ci			/* RX dribble */
5248c2ecf20Sopenharmony_ci			if (err & DSC_RX_ERR_DRI)
5258c2ecf20Sopenharmony_ci				dev->stats.rx_frame_errors++;
5268c2ecf20Sopenharmony_ci			/* Buffer length exceeded */
5278c2ecf20Sopenharmony_ci			if (err & DSC_RX_ERR_BUF)
5288c2ecf20Sopenharmony_ci				dev->stats.rx_length_errors++;
5298c2ecf20Sopenharmony_ci			/* Packet too long */
5308c2ecf20Sopenharmony_ci			if (err & DSC_RX_ERR_LONG)
5318c2ecf20Sopenharmony_ci				dev->stats.rx_length_errors++;
5328c2ecf20Sopenharmony_ci			/* Packet < 64 bytes */
5338c2ecf20Sopenharmony_ci			if (err & DSC_RX_ERR_RUNT)
5348c2ecf20Sopenharmony_ci				dev->stats.rx_length_errors++;
5358c2ecf20Sopenharmony_ci			/* CRC error */
5368c2ecf20Sopenharmony_ci			if (err & DSC_RX_ERR_CRC) {
5378c2ecf20Sopenharmony_ci				spin_lock(&priv->lock);
5388c2ecf20Sopenharmony_ci				dev->stats.rx_crc_errors++;
5398c2ecf20Sopenharmony_ci				spin_unlock(&priv->lock);
5408c2ecf20Sopenharmony_ci			}
5418c2ecf20Sopenharmony_ci			goto next_descr;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		/* Packet successfully received */
5458c2ecf20Sopenharmony_ci		new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
5468c2ecf20Sopenharmony_ci		if (!new_skb) {
5478c2ecf20Sopenharmony_ci			dev->stats.rx_dropped++;
5488c2ecf20Sopenharmony_ci			goto next_descr;
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci		skb_ptr = descptr->skb_ptr;
5518c2ecf20Sopenharmony_ci		skb_ptr->dev = priv->dev;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci		/* Do not count the CRC */
5548c2ecf20Sopenharmony_ci		skb_put(skb_ptr, descptr->len - 4);
5558c2ecf20Sopenharmony_ci		dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf),
5568c2ecf20Sopenharmony_ci				 MAX_BUF_SIZE, DMA_FROM_DEVICE);
5578c2ecf20Sopenharmony_ci		skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci		/* Send to upper layer */
5608c2ecf20Sopenharmony_ci		netif_receive_skb(skb_ptr);
5618c2ecf20Sopenharmony_ci		dev->stats.rx_packets++;
5628c2ecf20Sopenharmony_ci		dev->stats.rx_bytes += descptr->len - 4;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		/* put new skb into descriptor */
5658c2ecf20Sopenharmony_ci		descptr->skb_ptr = new_skb;
5668c2ecf20Sopenharmony_ci		descptr->buf = cpu_to_le32(dma_map_single(&priv->pdev->dev,
5678c2ecf20Sopenharmony_ci							  descptr->skb_ptr->data,
5688c2ecf20Sopenharmony_ci							  MAX_BUF_SIZE,
5698c2ecf20Sopenharmony_ci							  DMA_FROM_DEVICE));
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cinext_descr:
5728c2ecf20Sopenharmony_ci		/* put the descriptor back to the MAC */
5738c2ecf20Sopenharmony_ci		descptr->status = DSC_OWNER_MAC;
5748c2ecf20Sopenharmony_ci		descptr = descptr->vndescp;
5758c2ecf20Sopenharmony_ci		count++;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci	priv->rx_remove_ptr = descptr;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	return count;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_cistatic void r6040_tx(struct net_device *dev)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
5858c2ecf20Sopenharmony_ci	struct r6040_descriptor *descptr;
5868c2ecf20Sopenharmony_ci	void __iomem *ioaddr = priv->base;
5878c2ecf20Sopenharmony_ci	struct sk_buff *skb_ptr;
5888c2ecf20Sopenharmony_ci	u16 err;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	spin_lock(&priv->lock);
5918c2ecf20Sopenharmony_ci	descptr = priv->tx_remove_ptr;
5928c2ecf20Sopenharmony_ci	while (priv->tx_free_desc < TX_DCNT) {
5938c2ecf20Sopenharmony_ci		/* Check for errors */
5948c2ecf20Sopenharmony_ci		err = ioread16(ioaddr + MLSR);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		if (err & TX_FIFO_UNDR)
5978c2ecf20Sopenharmony_ci			dev->stats.tx_fifo_errors++;
5988c2ecf20Sopenharmony_ci		if (err & (TX_EXCEEDC | TX_LATEC))
5998c2ecf20Sopenharmony_ci			dev->stats.tx_carrier_errors++;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		if (descptr->status & DSC_OWNER_MAC)
6028c2ecf20Sopenharmony_ci			break; /* Not complete */
6038c2ecf20Sopenharmony_ci		skb_ptr = descptr->skb_ptr;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		/* Statistic Counter */
6068c2ecf20Sopenharmony_ci		dev->stats.tx_packets++;
6078c2ecf20Sopenharmony_ci		dev->stats.tx_bytes += skb_ptr->len;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf),
6108c2ecf20Sopenharmony_ci				 skb_ptr->len, DMA_TO_DEVICE);
6118c2ecf20Sopenharmony_ci		/* Free buffer */
6128c2ecf20Sopenharmony_ci		dev_kfree_skb(skb_ptr);
6138c2ecf20Sopenharmony_ci		descptr->skb_ptr = NULL;
6148c2ecf20Sopenharmony_ci		/* To next descriptor */
6158c2ecf20Sopenharmony_ci		descptr = descptr->vndescp;
6168c2ecf20Sopenharmony_ci		priv->tx_free_desc++;
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci	priv->tx_remove_ptr = descptr;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	if (priv->tx_free_desc)
6218c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
6228c2ecf20Sopenharmony_ci	spin_unlock(&priv->lock);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int r6040_poll(struct napi_struct *napi, int budget)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	struct r6040_private *priv =
6288c2ecf20Sopenharmony_ci		container_of(napi, struct r6040_private, napi);
6298c2ecf20Sopenharmony_ci	struct net_device *dev = priv->dev;
6308c2ecf20Sopenharmony_ci	void __iomem *ioaddr = priv->base;
6318c2ecf20Sopenharmony_ci	int work_done;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	r6040_tx(dev);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	work_done = r6040_rx(dev, budget);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (work_done < budget) {
6388c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
6398c2ecf20Sopenharmony_ci		/* Enable RX/TX interrupt */
6408c2ecf20Sopenharmony_ci		iowrite16(ioread16(ioaddr + MIER) | RX_INTS | TX_INTS,
6418c2ecf20Sopenharmony_ci			  ioaddr + MIER);
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci	return work_done;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/* The RDC interrupt handler. */
6478c2ecf20Sopenharmony_cistatic irqreturn_t r6040_interrupt(int irq, void *dev_id)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	struct net_device *dev = dev_id;
6508c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
6518c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
6528c2ecf20Sopenharmony_ci	u16 misr, status;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	/* Save MIER */
6558c2ecf20Sopenharmony_ci	misr = ioread16(ioaddr + MIER);
6568c2ecf20Sopenharmony_ci	/* Mask off RDC MAC interrupt */
6578c2ecf20Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);
6588c2ecf20Sopenharmony_ci	/* Read MISR status and clear */
6598c2ecf20Sopenharmony_ci	status = ioread16(ioaddr + MISR);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	if (status == 0x0000 || status == 0xffff) {
6628c2ecf20Sopenharmony_ci		/* Restore RDC MAC interrupt */
6638c2ecf20Sopenharmony_ci		iowrite16(misr, ioaddr + MIER);
6648c2ecf20Sopenharmony_ci		return IRQ_NONE;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	/* RX interrupt request */
6688c2ecf20Sopenharmony_ci	if (status & (RX_INTS | TX_INTS)) {
6698c2ecf20Sopenharmony_ci		if (status & RX_NO_DESC) {
6708c2ecf20Sopenharmony_ci			/* RX descriptor unavailable */
6718c2ecf20Sopenharmony_ci			dev->stats.rx_dropped++;
6728c2ecf20Sopenharmony_ci			dev->stats.rx_missed_errors++;
6738c2ecf20Sopenharmony_ci		}
6748c2ecf20Sopenharmony_ci		if (status & RX_FIFO_FULL)
6758c2ecf20Sopenharmony_ci			dev->stats.rx_fifo_errors++;
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		if (likely(napi_schedule_prep(&lp->napi))) {
6788c2ecf20Sopenharmony_ci			/* Mask off RX interrupt */
6798c2ecf20Sopenharmony_ci			misr &= ~(RX_INTS | TX_INTS);
6808c2ecf20Sopenharmony_ci			__napi_schedule_irqoff(&lp->napi);
6818c2ecf20Sopenharmony_ci		}
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* Restore RDC MAC interrupt */
6858c2ecf20Sopenharmony_ci	iowrite16(misr, ioaddr + MIER);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
6918c2ecf20Sopenharmony_cistatic void r6040_poll_controller(struct net_device *dev)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	disable_irq(dev->irq);
6948c2ecf20Sopenharmony_ci	r6040_interrupt(dev->irq, dev);
6958c2ecf20Sopenharmony_ci	enable_irq(dev->irq);
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci#endif
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci/* Init RDC MAC */
7008c2ecf20Sopenharmony_cistatic int r6040_up(struct net_device *dev)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
7038c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
7048c2ecf20Sopenharmony_ci	int ret;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* Initialise and alloc RX/TX buffers */
7078c2ecf20Sopenharmony_ci	r6040_init_txbufs(dev);
7088c2ecf20Sopenharmony_ci	ret = r6040_alloc_rxbufs(dev);
7098c2ecf20Sopenharmony_ci	if (ret)
7108c2ecf20Sopenharmony_ci		return ret;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	/* improve performance (by RDC guys) */
7138c2ecf20Sopenharmony_ci	r6040_phy_write(ioaddr, 30, 17,
7148c2ecf20Sopenharmony_ci			(r6040_phy_read(ioaddr, 30, 17) | 0x4000));
7158c2ecf20Sopenharmony_ci	r6040_phy_write(ioaddr, 30, 17,
7168c2ecf20Sopenharmony_ci			~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
7178c2ecf20Sopenharmony_ci	r6040_phy_write(ioaddr, 0, 19, 0x0000);
7188c2ecf20Sopenharmony_ci	r6040_phy_write(ioaddr, 0, 30, 0x01F0);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	/* Initialize all MAC registers */
7218c2ecf20Sopenharmony_ci	r6040_init_mac_regs(dev);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	phy_start(dev->phydev);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	return 0;
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci/* Read/set MAC address routines */
7308c2ecf20Sopenharmony_cistatic void r6040_mac_address(struct net_device *dev)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
7338c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
7348c2ecf20Sopenharmony_ci	u16 *adrp;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	/* Reset MAC */
7378c2ecf20Sopenharmony_ci	r6040_reset_mac(lp);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	/* Restore MAC Address */
7408c2ecf20Sopenharmony_ci	adrp = (u16 *) dev->dev_addr;
7418c2ecf20Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
7428c2ecf20Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
7438c2ecf20Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cistatic int r6040_open(struct net_device *dev)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
7498c2ecf20Sopenharmony_ci	int ret;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* Request IRQ and Register interrupt handler */
7528c2ecf20Sopenharmony_ci	ret = request_irq(dev->irq, r6040_interrupt,
7538c2ecf20Sopenharmony_ci		IRQF_SHARED, dev->name, dev);
7548c2ecf20Sopenharmony_ci	if (ret)
7558c2ecf20Sopenharmony_ci		goto out;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* Set MAC address */
7588c2ecf20Sopenharmony_ci	r6040_mac_address(dev);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	/* Allocate Descriptor memory */
7618c2ecf20Sopenharmony_ci	lp->rx_ring =
7628c2ecf20Sopenharmony_ci		dma_alloc_coherent(&lp->pdev->dev, RX_DESC_SIZE,
7638c2ecf20Sopenharmony_ci				   &lp->rx_ring_dma, GFP_KERNEL);
7648c2ecf20Sopenharmony_ci	if (!lp->rx_ring) {
7658c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7668c2ecf20Sopenharmony_ci		goto err_free_irq;
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	lp->tx_ring =
7708c2ecf20Sopenharmony_ci		dma_alloc_coherent(&lp->pdev->dev, TX_DESC_SIZE,
7718c2ecf20Sopenharmony_ci				   &lp->tx_ring_dma, GFP_KERNEL);
7728c2ecf20Sopenharmony_ci	if (!lp->tx_ring) {
7738c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7748c2ecf20Sopenharmony_ci		goto err_free_rx_ring;
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	ret = r6040_up(dev);
7788c2ecf20Sopenharmony_ci	if (ret)
7798c2ecf20Sopenharmony_ci		goto err_free_tx_ring;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	napi_enable(&lp->napi);
7828c2ecf20Sopenharmony_ci	netif_start_queue(dev);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	return 0;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cierr_free_tx_ring:
7878c2ecf20Sopenharmony_ci	dma_free_coherent(&lp->pdev->dev, TX_DESC_SIZE, lp->tx_ring,
7888c2ecf20Sopenharmony_ci			  lp->tx_ring_dma);
7898c2ecf20Sopenharmony_cierr_free_rx_ring:
7908c2ecf20Sopenharmony_ci	dma_free_coherent(&lp->pdev->dev, RX_DESC_SIZE, lp->rx_ring,
7918c2ecf20Sopenharmony_ci			  lp->rx_ring_dma);
7928c2ecf20Sopenharmony_cierr_free_irq:
7938c2ecf20Sopenharmony_ci	free_irq(dev->irq, dev);
7948c2ecf20Sopenharmony_ciout:
7958c2ecf20Sopenharmony_ci	return ret;
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
7998c2ecf20Sopenharmony_ci				    struct net_device *dev)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
8028c2ecf20Sopenharmony_ci	struct r6040_descriptor *descptr;
8038c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
8048c2ecf20Sopenharmony_ci	unsigned long flags;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (skb_put_padto(skb, ETH_ZLEN) < 0)
8078c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	/* Critical Section */
8108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	/* TX resource check */
8138c2ecf20Sopenharmony_ci	if (!lp->tx_free_desc) {
8148c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&lp->lock, flags);
8158c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
8168c2ecf20Sopenharmony_ci		netdev_err(dev, ": no tx descriptor\n");
8178c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/* Set TX descriptor & Transmit it */
8218c2ecf20Sopenharmony_ci	lp->tx_free_desc--;
8228c2ecf20Sopenharmony_ci	descptr = lp->tx_insert_ptr;
8238c2ecf20Sopenharmony_ci	descptr->len = skb->len;
8248c2ecf20Sopenharmony_ci	descptr->skb_ptr = skb;
8258c2ecf20Sopenharmony_ci	descptr->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, skb->data,
8268c2ecf20Sopenharmony_ci						  skb->len, DMA_TO_DEVICE));
8278c2ecf20Sopenharmony_ci	descptr->status = DSC_OWNER_MAC;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	skb_tx_timestamp(skb);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* Trigger the MAC to check the TX descriptor */
8328c2ecf20Sopenharmony_ci	if (!netdev_xmit_more() || netif_queue_stopped(dev))
8338c2ecf20Sopenharmony_ci		iowrite16(TM2TX, ioaddr + MTPR);
8348c2ecf20Sopenharmony_ci	lp->tx_insert_ptr = descptr->vndescp;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	/* If no tx resource, stop */
8378c2ecf20Sopenharmony_ci	if (!lp->tx_free_desc)
8388c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_cistatic void r6040_multicast_list(struct net_device *dev)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
8488c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
8498c2ecf20Sopenharmony_ci	unsigned long flags;
8508c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
8518c2ecf20Sopenharmony_ci	int i;
8528c2ecf20Sopenharmony_ci	u16 *adrp;
8538c2ecf20Sopenharmony_ci	u16 hash_table[4] = { 0 };
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	/* Keep our MAC Address */
8588c2ecf20Sopenharmony_ci	adrp = (u16 *)dev->dev_addr;
8598c2ecf20Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
8608c2ecf20Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
8618c2ecf20Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	/* Clear AMCP & PROM bits */
8648c2ecf20Sopenharmony_ci	lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* Promiscuous mode */
8678c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC)
8688c2ecf20Sopenharmony_ci		lp->mcr0 |= MCR0_PROMISC;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* Enable multicast hash table function to
8718c2ecf20Sopenharmony_ci	 * receive all multicast packets. */
8728c2ecf20Sopenharmony_ci	else if (dev->flags & IFF_ALLMULTI) {
8738c2ecf20Sopenharmony_ci		lp->mcr0 |= MCR0_HASH_EN;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		for (i = 0; i < MCAST_MAX ; i++) {
8768c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
8778c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
8788c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
8798c2ecf20Sopenharmony_ci		}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
8828c2ecf20Sopenharmony_ci			hash_table[i] = 0xffff;
8838c2ecf20Sopenharmony_ci	}
8848c2ecf20Sopenharmony_ci	/* Use internal multicast address registers if the number of
8858c2ecf20Sopenharmony_ci	 * multicast addresses is not greater than MCAST_MAX. */
8868c2ecf20Sopenharmony_ci	else if (netdev_mc_count(dev) <= MCAST_MAX) {
8878c2ecf20Sopenharmony_ci		i = 0;
8888c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
8898c2ecf20Sopenharmony_ci			u16 *adrp = (u16 *) ha->addr;
8908c2ecf20Sopenharmony_ci			iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
8918c2ecf20Sopenharmony_ci			iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
8928c2ecf20Sopenharmony_ci			iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
8938c2ecf20Sopenharmony_ci			i++;
8948c2ecf20Sopenharmony_ci		}
8958c2ecf20Sopenharmony_ci		while (i < MCAST_MAX) {
8968c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
8978c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
8988c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
8998c2ecf20Sopenharmony_ci			i++;
9008c2ecf20Sopenharmony_ci		}
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	/* Otherwise, Enable multicast hash table function. */
9038c2ecf20Sopenharmony_ci	else {
9048c2ecf20Sopenharmony_ci		u32 crc;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		lp->mcr0 |= MCR0_HASH_EN;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci		for (i = 0; i < MCAST_MAX ; i++) {
9098c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
9108c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
9118c2ecf20Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		/* Build multicast hash table */
9158c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
9168c2ecf20Sopenharmony_ci			u8 *addrs = ha->addr;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci			crc = ether_crc(ETH_ALEN, addrs);
9198c2ecf20Sopenharmony_ci			crc >>= 26;
9208c2ecf20Sopenharmony_ci			hash_table[crc >> 4] |= 1 << (crc & 0xf);
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	iowrite16(lp->mcr0, ioaddr + MCR0);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* Fill the MAC hash tables with their values */
9278c2ecf20Sopenharmony_ci	if (lp->mcr0 & MCR0_HASH_EN) {
9288c2ecf20Sopenharmony_ci		iowrite16(hash_table[0], ioaddr + MAR0);
9298c2ecf20Sopenharmony_ci		iowrite16(hash_table[1], ioaddr + MAR1);
9308c2ecf20Sopenharmony_ci		iowrite16(hash_table[2], ioaddr + MAR2);
9318c2ecf20Sopenharmony_ci		iowrite16(hash_table[3], ioaddr + MAR3);
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev,
9388c2ecf20Sopenharmony_ci			struct ethtool_drvinfo *info)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct r6040_private *rp = netdev_priv(dev);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
9438c2ecf20Sopenharmony_ci	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
9448c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = {
9488c2ecf20Sopenharmony_ci	.get_drvinfo		= netdev_get_drvinfo,
9498c2ecf20Sopenharmony_ci	.get_link		= ethtool_op_get_link,
9508c2ecf20Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
9518c2ecf20Sopenharmony_ci	.get_link_ksettings     = phy_ethtool_get_link_ksettings,
9528c2ecf20Sopenharmony_ci	.set_link_ksettings     = phy_ethtool_set_link_ksettings,
9538c2ecf20Sopenharmony_ci};
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic const struct net_device_ops r6040_netdev_ops = {
9568c2ecf20Sopenharmony_ci	.ndo_open		= r6040_open,
9578c2ecf20Sopenharmony_ci	.ndo_stop		= r6040_close,
9588c2ecf20Sopenharmony_ci	.ndo_start_xmit		= r6040_start_xmit,
9598c2ecf20Sopenharmony_ci	.ndo_get_stats		= r6040_get_stats,
9608c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= r6040_multicast_list,
9618c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
9628c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
9638c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= phy_do_ioctl,
9648c2ecf20Sopenharmony_ci	.ndo_tx_timeout		= r6040_tx_timeout,
9658c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
9668c2ecf20Sopenharmony_ci	.ndo_poll_controller	= r6040_poll_controller,
9678c2ecf20Sopenharmony_ci#endif
9688c2ecf20Sopenharmony_ci};
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_cistatic void r6040_adjust_link(struct net_device *dev)
9718c2ecf20Sopenharmony_ci{
9728c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
9738c2ecf20Sopenharmony_ci	struct phy_device *phydev = dev->phydev;
9748c2ecf20Sopenharmony_ci	int status_changed = 0;
9758c2ecf20Sopenharmony_ci	void __iomem *ioaddr = lp->base;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	BUG_ON(!phydev);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (lp->old_link != phydev->link) {
9808c2ecf20Sopenharmony_ci		status_changed = 1;
9818c2ecf20Sopenharmony_ci		lp->old_link = phydev->link;
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	/* reflect duplex change */
9858c2ecf20Sopenharmony_ci	if (phydev->link && (lp->old_duplex != phydev->duplex)) {
9868c2ecf20Sopenharmony_ci		lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0);
9878c2ecf20Sopenharmony_ci		iowrite16(lp->mcr0, ioaddr);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci		status_changed = 1;
9908c2ecf20Sopenharmony_ci		lp->old_duplex = phydev->duplex;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (status_changed)
9948c2ecf20Sopenharmony_ci		phy_print_status(phydev);
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic int r6040_mii_probe(struct net_device *dev)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
10008c2ecf20Sopenharmony_ci	struct phy_device *phydev = NULL;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	phydev = phy_find_first(lp->mii_bus);
10038c2ecf20Sopenharmony_ci	if (!phydev) {
10048c2ecf20Sopenharmony_ci		dev_err(&lp->pdev->dev, "no PHY found\n");
10058c2ecf20Sopenharmony_ci		return -ENODEV;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	phydev = phy_connect(dev, phydev_name(phydev), &r6040_adjust_link,
10098c2ecf20Sopenharmony_ci			     PHY_INTERFACE_MODE_MII);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (IS_ERR(phydev)) {
10128c2ecf20Sopenharmony_ci		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
10138c2ecf20Sopenharmony_ci		return PTR_ERR(phydev);
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	phy_set_max_speed(phydev, SPEED_100);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	lp->old_link = 0;
10198c2ecf20Sopenharmony_ci	lp->old_duplex = -1;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	phy_attached_info(phydev);
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	return 0;
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_cistatic int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
10278c2ecf20Sopenharmony_ci{
10288c2ecf20Sopenharmony_ci	struct net_device *dev;
10298c2ecf20Sopenharmony_ci	struct r6040_private *lp;
10308c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
10318c2ecf20Sopenharmony_ci	int err, io_size = R6040_IO_SIZE;
10328c2ecf20Sopenharmony_ci	static int card_idx = -1;
10338c2ecf20Sopenharmony_ci	int bar = 0;
10348c2ecf20Sopenharmony_ci	u16 *adrp;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	pr_info("%s\n", version);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
10398c2ecf20Sopenharmony_ci	if (err)
10408c2ecf20Sopenharmony_ci		goto err_out;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	/* this should always be supported */
10438c2ecf20Sopenharmony_ci	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
10448c2ecf20Sopenharmony_ci	if (err) {
10458c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n");
10468c2ecf20Sopenharmony_ci		goto err_out_disable_dev;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci	err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
10498c2ecf20Sopenharmony_ci	if (err) {
10508c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n");
10518c2ecf20Sopenharmony_ci		goto err_out_disable_dev;
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	/* IO Size check */
10558c2ecf20Sopenharmony_ci	if (pci_resource_len(pdev, bar) < io_size) {
10568c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
10578c2ecf20Sopenharmony_ci		err = -EIO;
10588c2ecf20Sopenharmony_ci		goto err_out_disable_dev;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	pci_set_master(pdev);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct r6040_private));
10648c2ecf20Sopenharmony_ci	if (!dev) {
10658c2ecf20Sopenharmony_ci		err = -ENOMEM;
10668c2ecf20Sopenharmony_ci		goto err_out_disable_dev;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
10698c2ecf20Sopenharmony_ci	lp = netdev_priv(dev);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	err = pci_request_regions(pdev, DRV_NAME);
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	if (err) {
10748c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request PCI regions\n");
10758c2ecf20Sopenharmony_ci		goto err_out_free_dev;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	ioaddr = pci_iomap(pdev, bar, io_size);
10798c2ecf20Sopenharmony_ci	if (!ioaddr) {
10808c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "ioremap failed for device\n");
10818c2ecf20Sopenharmony_ci		err = -EIO;
10828c2ecf20Sopenharmony_ci		goto err_out_free_res;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	/* If PHY status change register is still set to zero it means the
10868c2ecf20Sopenharmony_ci	 * bootloader didn't initialize it, so we set it to:
10878c2ecf20Sopenharmony_ci	 * - enable phy status change
10888c2ecf20Sopenharmony_ci	 * - enable all phy addresses
10898c2ecf20Sopenharmony_ci	 * - set to lowest timer divider */
10908c2ecf20Sopenharmony_ci	if (ioread16(ioaddr + PHY_CC) == 0)
10918c2ecf20Sopenharmony_ci		iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT |
10928c2ecf20Sopenharmony_ci				7 << TMRDIV_SHIFT, ioaddr + PHY_CC);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	/* Init system & device */
10958c2ecf20Sopenharmony_ci	lp->base = ioaddr;
10968c2ecf20Sopenharmony_ci	dev->irq = pdev->irq;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	spin_lock_init(&lp->lock);
10998c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, dev);
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	/* Set MAC address */
11028c2ecf20Sopenharmony_ci	card_idx++;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	adrp = (u16 *)dev->dev_addr;
11058c2ecf20Sopenharmony_ci	adrp[0] = ioread16(ioaddr + MID_0L);
11068c2ecf20Sopenharmony_ci	adrp[1] = ioread16(ioaddr + MID_0M);
11078c2ecf20Sopenharmony_ci	adrp[2] = ioread16(ioaddr + MID_0H);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/* Some bootloader/BIOSes do not initialize
11108c2ecf20Sopenharmony_ci	 * MAC address, warn about that */
11118c2ecf20Sopenharmony_ci	if (!(adrp[0] || adrp[1] || adrp[2])) {
11128c2ecf20Sopenharmony_ci		netdev_warn(dev, "MAC address not initialized, "
11138c2ecf20Sopenharmony_ci					"generating random\n");
11148c2ecf20Sopenharmony_ci		eth_hw_addr_random(dev);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	/* Link new device into r6040_root_dev */
11188c2ecf20Sopenharmony_ci	lp->pdev = pdev;
11198c2ecf20Sopenharmony_ci	lp->dev = dev;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* Init RDC private data */
11228c2ecf20Sopenharmony_ci	lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	/* The RDC-specific entries in the device structure. */
11258c2ecf20Sopenharmony_ci	dev->netdev_ops = &r6040_netdev_ops;
11268c2ecf20Sopenharmony_ci	dev->ethtool_ops = &netdev_ethtool_ops;
11278c2ecf20Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	lp->mii_bus = mdiobus_alloc();
11328c2ecf20Sopenharmony_ci	if (!lp->mii_bus) {
11338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
11348c2ecf20Sopenharmony_ci		err = -ENOMEM;
11358c2ecf20Sopenharmony_ci		goto err_out_unmap;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	lp->mii_bus->priv = dev;
11398c2ecf20Sopenharmony_ci	lp->mii_bus->read = r6040_mdiobus_read;
11408c2ecf20Sopenharmony_ci	lp->mii_bus->write = r6040_mdiobus_write;
11418c2ecf20Sopenharmony_ci	lp->mii_bus->name = "r6040_eth_mii";
11428c2ecf20Sopenharmony_ci	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
11438c2ecf20Sopenharmony_ci		dev_name(&pdev->dev), card_idx);
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	err = mdiobus_register(lp->mii_bus);
11468c2ecf20Sopenharmony_ci	if (err) {
11478c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register MII bus\n");
11488c2ecf20Sopenharmony_ci		goto err_out_mdio;
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	err = r6040_mii_probe(dev);
11528c2ecf20Sopenharmony_ci	if (err) {
11538c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to probe MII bus\n");
11548c2ecf20Sopenharmony_ci		goto err_out_mdio_unregister;
11558c2ecf20Sopenharmony_ci	}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	/* Register net device. After this dev->name assign */
11588c2ecf20Sopenharmony_ci	err = register_netdev(dev);
11598c2ecf20Sopenharmony_ci	if (err) {
11608c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register net device\n");
11618c2ecf20Sopenharmony_ci		goto err_out_phy_disconnect;
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci	return 0;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_cierr_out_phy_disconnect:
11668c2ecf20Sopenharmony_ci	phy_disconnect(dev->phydev);
11678c2ecf20Sopenharmony_cierr_out_mdio_unregister:
11688c2ecf20Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
11698c2ecf20Sopenharmony_cierr_out_mdio:
11708c2ecf20Sopenharmony_ci	mdiobus_free(lp->mii_bus);
11718c2ecf20Sopenharmony_cierr_out_unmap:
11728c2ecf20Sopenharmony_ci	netif_napi_del(&lp->napi);
11738c2ecf20Sopenharmony_ci	pci_iounmap(pdev, ioaddr);
11748c2ecf20Sopenharmony_cierr_out_free_res:
11758c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
11768c2ecf20Sopenharmony_cierr_out_free_dev:
11778c2ecf20Sopenharmony_ci	free_netdev(dev);
11788c2ecf20Sopenharmony_cierr_out_disable_dev:
11798c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
11808c2ecf20Sopenharmony_cierr_out:
11818c2ecf20Sopenharmony_ci	return err;
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic void r6040_remove_one(struct pci_dev *pdev)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
11878c2ecf20Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	unregister_netdev(dev);
11908c2ecf20Sopenharmony_ci	phy_disconnect(dev->phydev);
11918c2ecf20Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
11928c2ecf20Sopenharmony_ci	mdiobus_free(lp->mii_bus);
11938c2ecf20Sopenharmony_ci	netif_napi_del(&lp->napi);
11948c2ecf20Sopenharmony_ci	pci_iounmap(pdev, lp->base);
11958c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
11968c2ecf20Sopenharmony_ci	free_netdev(dev);
11978c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_cistatic const struct pci_device_id r6040_pci_tbl[] = {
12028c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
12038c2ecf20Sopenharmony_ci	{ 0 }
12048c2ecf20Sopenharmony_ci};
12058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_cistatic struct pci_driver r6040_driver = {
12088c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
12098c2ecf20Sopenharmony_ci	.id_table	= r6040_pci_tbl,
12108c2ecf20Sopenharmony_ci	.probe		= r6040_init_one,
12118c2ecf20Sopenharmony_ci	.remove		= r6040_remove_one,
12128c2ecf20Sopenharmony_ci};
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cimodule_pci_driver(r6040_driver);
1215