162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * RDC R6040 Fast Ethernet MAC support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw>
662306a36Sopenharmony_ci * Copyright (C) 2007
762306a36Sopenharmony_ci *	Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
862306a36Sopenharmony_ci * Copyright (C) 2007-2012 Florian Fainelli <f.fainelli@gmail.com>
962306a36Sopenharmony_ci*/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/moduleparam.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci#include <linux/timer.h>
1662306a36Sopenharmony_ci#include <linux/errno.h>
1762306a36Sopenharmony_ci#include <linux/ioport.h>
1862306a36Sopenharmony_ci#include <linux/interrupt.h>
1962306a36Sopenharmony_ci#include <linux/pci.h>
2062306a36Sopenharmony_ci#include <linux/netdevice.h>
2162306a36Sopenharmony_ci#include <linux/etherdevice.h>
2262306a36Sopenharmony_ci#include <linux/skbuff.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <linux/mii.h>
2562306a36Sopenharmony_ci#include <linux/ethtool.h>
2662306a36Sopenharmony_ci#include <linux/crc32.h>
2762306a36Sopenharmony_ci#include <linux/spinlock.h>
2862306a36Sopenharmony_ci#include <linux/bitops.h>
2962306a36Sopenharmony_ci#include <linux/io.h>
3062306a36Sopenharmony_ci#include <linux/irq.h>
3162306a36Sopenharmony_ci#include <linux/uaccess.h>
3262306a36Sopenharmony_ci#include <linux/phy.h>
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <asm/processor.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define DRV_NAME	"r6040"
3762306a36Sopenharmony_ci#define DRV_VERSION	"0.29"
3862306a36Sopenharmony_ci#define DRV_RELDATE	"04Jul2016"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
4162306a36Sopenharmony_ci#define TX_TIMEOUT	(6000 * HZ / 1000)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* RDC MAC I/O Size */
4462306a36Sopenharmony_ci#define R6040_IO_SIZE	256
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* MAX RDC MAC */
4762306a36Sopenharmony_ci#define MAX_MAC		2
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* MAC registers */
5062306a36Sopenharmony_ci#define MCR0		0x00	/* Control register 0 */
5162306a36Sopenharmony_ci#define  MCR0_RCVEN	0x0002	/* Receive enable */
5262306a36Sopenharmony_ci#define  MCR0_PROMISC	0x0020	/* Promiscuous mode */
5362306a36Sopenharmony_ci#define  MCR0_HASH_EN	0x0100	/* Enable multicast hash table function */
5462306a36Sopenharmony_ci#define  MCR0_XMTEN	0x1000	/* Transmission enable */
5562306a36Sopenharmony_ci#define  MCR0_FD	0x8000	/* Full/Half duplex */
5662306a36Sopenharmony_ci#define MCR1		0x04	/* Control register 1 */
5762306a36Sopenharmony_ci#define  MAC_RST	0x0001	/* Reset the MAC */
5862306a36Sopenharmony_ci#define MBCR		0x08	/* Bus control */
5962306a36Sopenharmony_ci#define MT_ICR		0x0C	/* TX interrupt control */
6062306a36Sopenharmony_ci#define MR_ICR		0x10	/* RX interrupt control */
6162306a36Sopenharmony_ci#define MTPR		0x14	/* TX poll command register */
6262306a36Sopenharmony_ci#define  TM2TX		0x0001	/* Trigger MAC to transmit */
6362306a36Sopenharmony_ci#define MR_BSR		0x18	/* RX buffer size */
6462306a36Sopenharmony_ci#define MR_DCR		0x1A	/* RX descriptor control */
6562306a36Sopenharmony_ci#define MLSR		0x1C	/* Last status */
6662306a36Sopenharmony_ci#define  TX_FIFO_UNDR	0x0200	/* TX FIFO under-run */
6762306a36Sopenharmony_ci#define	 TX_EXCEEDC	0x2000	/* Transmit exceed collision */
6862306a36Sopenharmony_ci#define  TX_LATEC	0x4000	/* Transmit late collision */
6962306a36Sopenharmony_ci#define MMDIO		0x20	/* MDIO control register */
7062306a36Sopenharmony_ci#define  MDIO_WRITE	0x4000	/* MDIO write */
7162306a36Sopenharmony_ci#define  MDIO_READ	0x2000	/* MDIO read */
7262306a36Sopenharmony_ci#define MMRD		0x24	/* MDIO read data register */
7362306a36Sopenharmony_ci#define MMWD		0x28	/* MDIO write data register */
7462306a36Sopenharmony_ci#define MTD_SA0		0x2C	/* TX descriptor start address 0 */
7562306a36Sopenharmony_ci#define MTD_SA1		0x30	/* TX descriptor start address 1 */
7662306a36Sopenharmony_ci#define MRD_SA0		0x34	/* RX descriptor start address 0 */
7762306a36Sopenharmony_ci#define MRD_SA1		0x38	/* RX descriptor start address 1 */
7862306a36Sopenharmony_ci#define MISR		0x3C	/* Status register */
7962306a36Sopenharmony_ci#define MIER		0x40	/* INT enable register */
8062306a36Sopenharmony_ci#define  MSK_INT	0x0000	/* Mask off interrupts */
8162306a36Sopenharmony_ci#define  RX_FINISH	0x0001  /* RX finished */
8262306a36Sopenharmony_ci#define  RX_NO_DESC	0x0002  /* No RX descriptor available */
8362306a36Sopenharmony_ci#define  RX_FIFO_FULL	0x0004  /* RX FIFO full */
8462306a36Sopenharmony_ci#define  RX_EARLY	0x0008  /* RX early */
8562306a36Sopenharmony_ci#define  TX_FINISH	0x0010  /* TX finished */
8662306a36Sopenharmony_ci#define  TX_EARLY	0x0080  /* TX early */
8762306a36Sopenharmony_ci#define  EVENT_OVRFL	0x0100  /* Event counter overflow */
8862306a36Sopenharmony_ci#define  LINK_CHANGED	0x0200  /* PHY link changed */
8962306a36Sopenharmony_ci#define ME_CISR		0x44	/* Event counter INT status */
9062306a36Sopenharmony_ci#define ME_CIER		0x48	/* Event counter INT enable  */
9162306a36Sopenharmony_ci#define MR_CNT		0x50	/* Successfully received packet counter */
9262306a36Sopenharmony_ci#define ME_CNT0		0x52	/* Event counter 0 */
9362306a36Sopenharmony_ci#define ME_CNT1		0x54	/* Event counter 1 */
9462306a36Sopenharmony_ci#define ME_CNT2		0x56	/* Event counter 2 */
9562306a36Sopenharmony_ci#define ME_CNT3		0x58	/* Event counter 3 */
9662306a36Sopenharmony_ci#define MT_CNT		0x5A	/* Successfully transmit packet counter */
9762306a36Sopenharmony_ci#define ME_CNT4		0x5C	/* Event counter 4 */
9862306a36Sopenharmony_ci#define MP_CNT		0x5E	/* Pause frame counter register */
9962306a36Sopenharmony_ci#define MAR0		0x60	/* Hash table 0 */
10062306a36Sopenharmony_ci#define MAR1		0x62	/* Hash table 1 */
10162306a36Sopenharmony_ci#define MAR2		0x64	/* Hash table 2 */
10262306a36Sopenharmony_ci#define MAR3		0x66	/* Hash table 3 */
10362306a36Sopenharmony_ci#define MID_0L		0x68	/* Multicast address MID0 Low */
10462306a36Sopenharmony_ci#define MID_0M		0x6A	/* Multicast address MID0 Medium */
10562306a36Sopenharmony_ci#define MID_0H		0x6C	/* Multicast address MID0 High */
10662306a36Sopenharmony_ci#define MID_1L		0x70	/* MID1 Low */
10762306a36Sopenharmony_ci#define MID_1M		0x72	/* MID1 Medium */
10862306a36Sopenharmony_ci#define MID_1H		0x74	/* MID1 High */
10962306a36Sopenharmony_ci#define MID_2L		0x78	/* MID2 Low */
11062306a36Sopenharmony_ci#define MID_2M		0x7A	/* MID2 Medium */
11162306a36Sopenharmony_ci#define MID_2H		0x7C	/* MID2 High */
11262306a36Sopenharmony_ci#define MID_3L		0x80	/* MID3 Low */
11362306a36Sopenharmony_ci#define MID_3M		0x82	/* MID3 Medium */
11462306a36Sopenharmony_ci#define MID_3H		0x84	/* MID3 High */
11562306a36Sopenharmony_ci#define PHY_CC		0x88	/* PHY status change configuration register */
11662306a36Sopenharmony_ci#define  SCEN		0x8000	/* PHY status change enable */
11762306a36Sopenharmony_ci#define  PHYAD_SHIFT	8	/* PHY address shift */
11862306a36Sopenharmony_ci#define  TMRDIV_SHIFT	0	/* Timer divider shift */
11962306a36Sopenharmony_ci#define PHY_ST		0x8A	/* PHY status register */
12062306a36Sopenharmony_ci#define MAC_SM		0xAC	/* MAC status machine */
12162306a36Sopenharmony_ci#define  MAC_SM_RST	0x0002	/* MAC status machine reset */
12262306a36Sopenharmony_ci#define MD_CSC		0xb6	/* MDC speed control register */
12362306a36Sopenharmony_ci#define  MD_CSC_DEFAULT	0x0030
12462306a36Sopenharmony_ci#define MAC_ID		0xBE	/* Identifier register */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define TX_DCNT		0x80	/* TX descriptor count */
12762306a36Sopenharmony_ci#define RX_DCNT		0x80	/* RX descriptor count */
12862306a36Sopenharmony_ci#define MAX_BUF_SIZE	0x600
12962306a36Sopenharmony_ci#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))
13062306a36Sopenharmony_ci#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))
13162306a36Sopenharmony_ci#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */
13262306a36Sopenharmony_ci#define MCAST_MAX	3	/* Max number multicast addresses to filter */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#define MAC_DEF_TIMEOUT	2048	/* Default MAC read/write operation timeout */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* Descriptor status */
13762306a36Sopenharmony_ci#define DSC_OWNER_MAC	0x8000	/* MAC is the owner of this descriptor */
13862306a36Sopenharmony_ci#define DSC_RX_OK	0x4000	/* RX was successful */
13962306a36Sopenharmony_ci#define DSC_RX_ERR	0x0800	/* RX PHY error */
14062306a36Sopenharmony_ci#define DSC_RX_ERR_DRI	0x0400	/* RX dribble packet */
14162306a36Sopenharmony_ci#define DSC_RX_ERR_BUF	0x0200	/* RX length exceeds buffer size */
14262306a36Sopenharmony_ci#define DSC_RX_ERR_LONG	0x0100	/* RX length > maximum packet length */
14362306a36Sopenharmony_ci#define DSC_RX_ERR_RUNT	0x0080	/* RX packet length < 64 byte */
14462306a36Sopenharmony_ci#define DSC_RX_ERR_CRC	0x0040	/* RX CRC error */
14562306a36Sopenharmony_ci#define DSC_RX_BCAST	0x0020	/* RX broadcast (no error) */
14662306a36Sopenharmony_ci#define DSC_RX_MCAST	0x0010	/* RX multicast (no error) */
14762306a36Sopenharmony_ci#define DSC_RX_MCH_HIT	0x0008	/* RX multicast hit in hash table (no error) */
14862306a36Sopenharmony_ci#define DSC_RX_MIDH_HIT	0x0004	/* RX MID table hit (no error) */
14962306a36Sopenharmony_ci#define DSC_RX_IDX_MID_MASK 3	/* RX mask for the index of matched MIDx */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"
15262306a36Sopenharmony_ci	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"
15362306a36Sopenharmony_ci	"Florian Fainelli <f.fainelli@gmail.com>");
15462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
15562306a36Sopenharmony_ciMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");
15662306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION " " DRV_RELDATE);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* RX and TX interrupts that we handle */
15962306a36Sopenharmony_ci#define RX_INTS			(RX_FIFO_FULL | RX_NO_DESC | RX_FINISH)
16062306a36Sopenharmony_ci#define TX_INTS			(TX_FINISH)
16162306a36Sopenharmony_ci#define INT_MASK		(RX_INTS | TX_INTS)
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct r6040_descriptor {
16462306a36Sopenharmony_ci	u16	status, len;		/* 0-3 */
16562306a36Sopenharmony_ci	__le32	buf;			/* 4-7 */
16662306a36Sopenharmony_ci	__le32	ndesc;			/* 8-B */
16762306a36Sopenharmony_ci	u32	rev1;			/* C-F */
16862306a36Sopenharmony_ci	char	*vbufp;			/* 10-13 */
16962306a36Sopenharmony_ci	struct r6040_descriptor *vndescp;	/* 14-17 */
17062306a36Sopenharmony_ci	struct sk_buff *skb_ptr;	/* 18-1B */
17162306a36Sopenharmony_ci	u32	rev2;			/* 1C-1F */
17262306a36Sopenharmony_ci} __aligned(32);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistruct r6040_private {
17562306a36Sopenharmony_ci	spinlock_t lock;		/* driver lock */
17662306a36Sopenharmony_ci	struct pci_dev *pdev;
17762306a36Sopenharmony_ci	struct r6040_descriptor *rx_insert_ptr;
17862306a36Sopenharmony_ci	struct r6040_descriptor *rx_remove_ptr;
17962306a36Sopenharmony_ci	struct r6040_descriptor *tx_insert_ptr;
18062306a36Sopenharmony_ci	struct r6040_descriptor *tx_remove_ptr;
18162306a36Sopenharmony_ci	struct r6040_descriptor *rx_ring;
18262306a36Sopenharmony_ci	struct r6040_descriptor *tx_ring;
18362306a36Sopenharmony_ci	dma_addr_t rx_ring_dma;
18462306a36Sopenharmony_ci	dma_addr_t tx_ring_dma;
18562306a36Sopenharmony_ci	u16	tx_free_desc;
18662306a36Sopenharmony_ci	u16	mcr0;
18762306a36Sopenharmony_ci	struct net_device *dev;
18862306a36Sopenharmony_ci	struct mii_bus *mii_bus;
18962306a36Sopenharmony_ci	struct napi_struct napi;
19062306a36Sopenharmony_ci	void __iomem *base;
19162306a36Sopenharmony_ci	int old_link;
19262306a36Sopenharmony_ci	int old_duplex;
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic char version[] = DRV_NAME
19662306a36Sopenharmony_ci	": RDC R6040 NAPI net driver,"
19762306a36Sopenharmony_ci	"version "DRV_VERSION " (" DRV_RELDATE ")";
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/* Read a word data from PHY Chip */
20062306a36Sopenharmony_cistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
20362306a36Sopenharmony_ci	u16 cmd;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	iowrite16(MDIO_READ | reg | (phy_addr << 8), ioaddr + MMDIO);
20662306a36Sopenharmony_ci	/* Wait for the read bit to be cleared */
20762306a36Sopenharmony_ci	while (limit--) {
20862306a36Sopenharmony_ci		cmd = ioread16(ioaddr + MMDIO);
20962306a36Sopenharmony_ci		if (!(cmd & MDIO_READ))
21062306a36Sopenharmony_ci			break;
21162306a36Sopenharmony_ci		udelay(1);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	if (limit < 0)
21562306a36Sopenharmony_ci		return -ETIMEDOUT;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return ioread16(ioaddr + MMRD);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* Write a word data from PHY Chip */
22162306a36Sopenharmony_cistatic int r6040_phy_write(void __iomem *ioaddr,
22262306a36Sopenharmony_ci					int phy_addr, int reg, u16 val)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
22562306a36Sopenharmony_ci	u16 cmd;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	iowrite16(val, ioaddr + MMWD);
22862306a36Sopenharmony_ci	/* Write the command to the MDIO bus */
22962306a36Sopenharmony_ci	iowrite16(MDIO_WRITE | reg | (phy_addr << 8), ioaddr + MMDIO);
23062306a36Sopenharmony_ci	/* Wait for the write bit to be cleared */
23162306a36Sopenharmony_ci	while (limit--) {
23262306a36Sopenharmony_ci		cmd = ioread16(ioaddr + MMDIO);
23362306a36Sopenharmony_ci		if (!(cmd & MDIO_WRITE))
23462306a36Sopenharmony_ci			break;
23562306a36Sopenharmony_ci		udelay(1);
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return (limit < 0) ? -ETIMEDOUT : 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct net_device *dev = bus->priv;
24462306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
24562306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	return r6040_phy_read(ioaddr, phy_addr, reg);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
25162306a36Sopenharmony_ci						int reg, u16 value)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct net_device *dev = bus->priv;
25462306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
25562306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	return r6040_phy_write(ioaddr, phy_addr, reg, value);
25862306a36Sopenharmony_ci}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic void r6040_free_txbufs(struct net_device *dev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
26362306a36Sopenharmony_ci	int i;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	for (i = 0; i < TX_DCNT; i++) {
26662306a36Sopenharmony_ci		if (lp->tx_insert_ptr->skb_ptr) {
26762306a36Sopenharmony_ci			dma_unmap_single(&lp->pdev->dev,
26862306a36Sopenharmony_ci					 le32_to_cpu(lp->tx_insert_ptr->buf),
26962306a36Sopenharmony_ci					 MAX_BUF_SIZE, DMA_TO_DEVICE);
27062306a36Sopenharmony_ci			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
27162306a36Sopenharmony_ci			lp->tx_insert_ptr->skb_ptr = NULL;
27262306a36Sopenharmony_ci		}
27362306a36Sopenharmony_ci		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void r6040_free_rxbufs(struct net_device *dev)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
28062306a36Sopenharmony_ci	int i;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	for (i = 0; i < RX_DCNT; i++) {
28362306a36Sopenharmony_ci		if (lp->rx_insert_ptr->skb_ptr) {
28462306a36Sopenharmony_ci			dma_unmap_single(&lp->pdev->dev,
28562306a36Sopenharmony_ci					 le32_to_cpu(lp->rx_insert_ptr->buf),
28662306a36Sopenharmony_ci					 MAX_BUF_SIZE, DMA_FROM_DEVICE);
28762306a36Sopenharmony_ci			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
28862306a36Sopenharmony_ci			lp->rx_insert_ptr->skb_ptr = NULL;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
29562306a36Sopenharmony_ci				 dma_addr_t desc_dma, int size)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct r6040_descriptor *desc = desc_ring;
29862306a36Sopenharmony_ci	dma_addr_t mapping = desc_dma;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	while (size-- > 0) {
30162306a36Sopenharmony_ci		mapping += sizeof(*desc);
30262306a36Sopenharmony_ci		desc->ndesc = cpu_to_le32(mapping);
30362306a36Sopenharmony_ci		desc->vndescp = desc + 1;
30462306a36Sopenharmony_ci		desc++;
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci	desc--;
30762306a36Sopenharmony_ci	desc->ndesc = cpu_to_le32(desc_dma);
30862306a36Sopenharmony_ci	desc->vndescp = desc_ring;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void r6040_init_txbufs(struct net_device *dev)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	lp->tx_free_desc = TX_DCNT;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
31862306a36Sopenharmony_ci	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int r6040_alloc_rxbufs(struct net_device *dev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
32462306a36Sopenharmony_ci	struct r6040_descriptor *desc;
32562306a36Sopenharmony_ci	struct sk_buff *skb;
32662306a36Sopenharmony_ci	int rc;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
32962306a36Sopenharmony_ci	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Allocate skbs for the rx descriptors */
33262306a36Sopenharmony_ci	desc = lp->rx_ring;
33362306a36Sopenharmony_ci	do {
33462306a36Sopenharmony_ci		skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
33562306a36Sopenharmony_ci		if (!skb) {
33662306a36Sopenharmony_ci			rc = -ENOMEM;
33762306a36Sopenharmony_ci			goto err_exit;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci		desc->skb_ptr = skb;
34062306a36Sopenharmony_ci		desc->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev,
34162306a36Sopenharmony_ci						       desc->skb_ptr->data,
34262306a36Sopenharmony_ci						       MAX_BUF_SIZE,
34362306a36Sopenharmony_ci						       DMA_FROM_DEVICE));
34462306a36Sopenharmony_ci		desc->status = DSC_OWNER_MAC;
34562306a36Sopenharmony_ci		desc = desc->vndescp;
34662306a36Sopenharmony_ci	} while (desc != lp->rx_ring);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cierr_exit:
35162306a36Sopenharmony_ci	/* Deallocate all previously allocated skbs */
35262306a36Sopenharmony_ci	r6040_free_rxbufs(dev);
35362306a36Sopenharmony_ci	return rc;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void r6040_reset_mac(struct r6040_private *lp)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
35962306a36Sopenharmony_ci	int limit = MAC_DEF_TIMEOUT;
36062306a36Sopenharmony_ci	u16 cmd, md_csc;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	md_csc = ioread16(ioaddr + MD_CSC);
36362306a36Sopenharmony_ci	iowrite16(MAC_RST, ioaddr + MCR1);
36462306a36Sopenharmony_ci	while (limit--) {
36562306a36Sopenharmony_ci		cmd = ioread16(ioaddr + MCR1);
36662306a36Sopenharmony_ci		if (cmd & MAC_RST)
36762306a36Sopenharmony_ci			break;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Reset internal state machine */
37162306a36Sopenharmony_ci	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
37262306a36Sopenharmony_ci	iowrite16(0, ioaddr + MAC_SM);
37362306a36Sopenharmony_ci	mdelay(5);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* Restore MDIO clock frequency */
37662306a36Sopenharmony_ci	if (md_csc != MD_CSC_DEFAULT)
37762306a36Sopenharmony_ci		iowrite16(md_csc, ioaddr + MD_CSC);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void r6040_init_mac_regs(struct net_device *dev)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
38362306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Mask Off Interrupt */
38662306a36Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* Reset RDC MAC */
38962306a36Sopenharmony_ci	r6040_reset_mac(lp);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* MAC Bus Control Register */
39262306a36Sopenharmony_ci	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* Buffer Size Register */
39562306a36Sopenharmony_ci	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Write TX ring start address */
39862306a36Sopenharmony_ci	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
39962306a36Sopenharmony_ci	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* Write RX ring start address */
40262306a36Sopenharmony_ci	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
40362306a36Sopenharmony_ci	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Set interrupt waiting time and packet numbers */
40662306a36Sopenharmony_ci	iowrite16(0, ioaddr + MT_ICR);
40762306a36Sopenharmony_ci	iowrite16(0, ioaddr + MR_ICR);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* Enable interrupts */
41062306a36Sopenharmony_ci	iowrite16(INT_MASK, ioaddr + MIER);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* Enable TX and RX */
41362306a36Sopenharmony_ci	iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* Let TX poll the descriptors
41662306a36Sopenharmony_ci	 * we may got called by r6040_tx_timeout which has left
41762306a36Sopenharmony_ci	 * some unsent tx buffers */
41862306a36Sopenharmony_ci	iowrite16(TM2TX, ioaddr + MTPR);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic void r6040_tx_timeout(struct net_device *dev, unsigned int txqueue)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
42462306a36Sopenharmony_ci	void __iomem *ioaddr = priv->base;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	netdev_warn(dev, "transmit timed out, int enable %4.4x "
42762306a36Sopenharmony_ci		"status %4.4x\n",
42862306a36Sopenharmony_ci		ioread16(ioaddr + MIER),
42962306a36Sopenharmony_ci		ioread16(ioaddr + MISR));
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dev->stats.tx_errors++;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Reset MAC and re-init all registers */
43462306a36Sopenharmony_ci	r6040_init_mac_regs(dev);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic struct net_device_stats *r6040_get_stats(struct net_device *dev)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
44062306a36Sopenharmony_ci	void __iomem *ioaddr = priv->base;
44162306a36Sopenharmony_ci	unsigned long flags;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	spin_lock_irqsave(&priv->lock, flags);
44462306a36Sopenharmony_ci	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
44562306a36Sopenharmony_ci	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);
44662306a36Sopenharmony_ci	spin_unlock_irqrestore(&priv->lock, flags);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return &dev->stats;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci/* Stop RDC MAC and Free the allocated resource */
45262306a36Sopenharmony_cistatic void r6040_down(struct net_device *dev)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
45562306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
45662306a36Sopenharmony_ci	const u16 *adrp;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* Stop MAC */
45962306a36Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	/* Reset RDC MAC */
46262306a36Sopenharmony_ci	r6040_reset_mac(lp);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Restore MAC Address to MIDx */
46562306a36Sopenharmony_ci	adrp = (const u16 *) dev->dev_addr;
46662306a36Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
46762306a36Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
46862306a36Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int r6040_close(struct net_device *dev)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
47462306a36Sopenharmony_ci	struct pci_dev *pdev = lp->pdev;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	phy_stop(dev->phydev);
47762306a36Sopenharmony_ci	napi_disable(&lp->napi);
47862306a36Sopenharmony_ci	netif_stop_queue(dev);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	spin_lock_irq(&lp->lock);
48162306a36Sopenharmony_ci	r6040_down(dev);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* Free RX buffer */
48462306a36Sopenharmony_ci	r6040_free_rxbufs(dev);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* Free TX buffer */
48762306a36Sopenharmony_ci	r6040_free_txbufs(dev);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	spin_unlock_irq(&lp->lock);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	free_irq(dev->irq, dev);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/* Free Descriptor memory */
49462306a36Sopenharmony_ci	if (lp->rx_ring) {
49562306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, RX_DESC_SIZE, lp->rx_ring,
49662306a36Sopenharmony_ci				  lp->rx_ring_dma);
49762306a36Sopenharmony_ci		lp->rx_ring = NULL;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (lp->tx_ring) {
50162306a36Sopenharmony_ci		dma_free_coherent(&pdev->dev, TX_DESC_SIZE, lp->tx_ring,
50262306a36Sopenharmony_ci				  lp->tx_ring_dma);
50362306a36Sopenharmony_ci		lp->tx_ring = NULL;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return 0;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic int r6040_rx(struct net_device *dev, int limit)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
51262306a36Sopenharmony_ci	struct r6040_descriptor *descptr = priv->rx_remove_ptr;
51362306a36Sopenharmony_ci	struct sk_buff *skb_ptr, *new_skb;
51462306a36Sopenharmony_ci	int count = 0;
51562306a36Sopenharmony_ci	u16 err;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* Limit not reached and the descriptor belongs to the CPU */
51862306a36Sopenharmony_ci	while (count < limit && !(descptr->status & DSC_OWNER_MAC)) {
51962306a36Sopenharmony_ci		/* Read the descriptor status */
52062306a36Sopenharmony_ci		err = descptr->status;
52162306a36Sopenharmony_ci		/* Global error status set */
52262306a36Sopenharmony_ci		if (err & DSC_RX_ERR) {
52362306a36Sopenharmony_ci			/* RX dribble */
52462306a36Sopenharmony_ci			if (err & DSC_RX_ERR_DRI)
52562306a36Sopenharmony_ci				dev->stats.rx_frame_errors++;
52662306a36Sopenharmony_ci			/* Buffer length exceeded */
52762306a36Sopenharmony_ci			if (err & DSC_RX_ERR_BUF)
52862306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
52962306a36Sopenharmony_ci			/* Packet too long */
53062306a36Sopenharmony_ci			if (err & DSC_RX_ERR_LONG)
53162306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
53262306a36Sopenharmony_ci			/* Packet < 64 bytes */
53362306a36Sopenharmony_ci			if (err & DSC_RX_ERR_RUNT)
53462306a36Sopenharmony_ci				dev->stats.rx_length_errors++;
53562306a36Sopenharmony_ci			/* CRC error */
53662306a36Sopenharmony_ci			if (err & DSC_RX_ERR_CRC) {
53762306a36Sopenharmony_ci				spin_lock(&priv->lock);
53862306a36Sopenharmony_ci				dev->stats.rx_crc_errors++;
53962306a36Sopenharmony_ci				spin_unlock(&priv->lock);
54062306a36Sopenharmony_ci			}
54162306a36Sopenharmony_ci			goto next_descr;
54262306a36Sopenharmony_ci		}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		/* Packet successfully received */
54562306a36Sopenharmony_ci		new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
54662306a36Sopenharmony_ci		if (!new_skb) {
54762306a36Sopenharmony_ci			dev->stats.rx_dropped++;
54862306a36Sopenharmony_ci			goto next_descr;
54962306a36Sopenharmony_ci		}
55062306a36Sopenharmony_ci		skb_ptr = descptr->skb_ptr;
55162306a36Sopenharmony_ci		skb_ptr->dev = priv->dev;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		/* Do not count the CRC */
55462306a36Sopenharmony_ci		skb_put(skb_ptr, descptr->len - ETH_FCS_LEN);
55562306a36Sopenharmony_ci		dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf),
55662306a36Sopenharmony_ci				 MAX_BUF_SIZE, DMA_FROM_DEVICE);
55762306a36Sopenharmony_ci		skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		/* Send to upper layer */
56062306a36Sopenharmony_ci		netif_receive_skb(skb_ptr);
56162306a36Sopenharmony_ci		dev->stats.rx_packets++;
56262306a36Sopenharmony_ci		dev->stats.rx_bytes += descptr->len - ETH_FCS_LEN;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci		/* put new skb into descriptor */
56562306a36Sopenharmony_ci		descptr->skb_ptr = new_skb;
56662306a36Sopenharmony_ci		descptr->buf = cpu_to_le32(dma_map_single(&priv->pdev->dev,
56762306a36Sopenharmony_ci							  descptr->skb_ptr->data,
56862306a36Sopenharmony_ci							  MAX_BUF_SIZE,
56962306a36Sopenharmony_ci							  DMA_FROM_DEVICE));
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_cinext_descr:
57262306a36Sopenharmony_ci		/* put the descriptor back to the MAC */
57362306a36Sopenharmony_ci		descptr->status = DSC_OWNER_MAC;
57462306a36Sopenharmony_ci		descptr = descptr->vndescp;
57562306a36Sopenharmony_ci		count++;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	priv->rx_remove_ptr = descptr;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return count;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void r6040_tx(struct net_device *dev)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct r6040_private *priv = netdev_priv(dev);
58562306a36Sopenharmony_ci	struct r6040_descriptor *descptr;
58662306a36Sopenharmony_ci	void __iomem *ioaddr = priv->base;
58762306a36Sopenharmony_ci	struct sk_buff *skb_ptr;
58862306a36Sopenharmony_ci	u16 err;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	spin_lock(&priv->lock);
59162306a36Sopenharmony_ci	descptr = priv->tx_remove_ptr;
59262306a36Sopenharmony_ci	while (priv->tx_free_desc < TX_DCNT) {
59362306a36Sopenharmony_ci		/* Check for errors */
59462306a36Sopenharmony_ci		err = ioread16(ioaddr + MLSR);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		if (err & TX_FIFO_UNDR)
59762306a36Sopenharmony_ci			dev->stats.tx_fifo_errors++;
59862306a36Sopenharmony_ci		if (err & (TX_EXCEEDC | TX_LATEC))
59962306a36Sopenharmony_ci			dev->stats.tx_carrier_errors++;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci		if (descptr->status & DSC_OWNER_MAC)
60262306a36Sopenharmony_ci			break; /* Not complete */
60362306a36Sopenharmony_ci		skb_ptr = descptr->skb_ptr;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		/* Statistic Counter */
60662306a36Sopenharmony_ci		dev->stats.tx_packets++;
60762306a36Sopenharmony_ci		dev->stats.tx_bytes += skb_ptr->len;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		dma_unmap_single(&priv->pdev->dev, le32_to_cpu(descptr->buf),
61062306a36Sopenharmony_ci				 skb_ptr->len, DMA_TO_DEVICE);
61162306a36Sopenharmony_ci		/* Free buffer */
61262306a36Sopenharmony_ci		dev_kfree_skb(skb_ptr);
61362306a36Sopenharmony_ci		descptr->skb_ptr = NULL;
61462306a36Sopenharmony_ci		/* To next descriptor */
61562306a36Sopenharmony_ci		descptr = descptr->vndescp;
61662306a36Sopenharmony_ci		priv->tx_free_desc++;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	priv->tx_remove_ptr = descptr;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (priv->tx_free_desc)
62162306a36Sopenharmony_ci		netif_wake_queue(dev);
62262306a36Sopenharmony_ci	spin_unlock(&priv->lock);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic int r6040_poll(struct napi_struct *napi, int budget)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct r6040_private *priv =
62862306a36Sopenharmony_ci		container_of(napi, struct r6040_private, napi);
62962306a36Sopenharmony_ci	struct net_device *dev = priv->dev;
63062306a36Sopenharmony_ci	void __iomem *ioaddr = priv->base;
63162306a36Sopenharmony_ci	int work_done;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	r6040_tx(dev);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	work_done = r6040_rx(dev, budget);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (work_done < budget) {
63862306a36Sopenharmony_ci		napi_complete_done(napi, work_done);
63962306a36Sopenharmony_ci		/* Enable RX/TX interrupt */
64062306a36Sopenharmony_ci		iowrite16(ioread16(ioaddr + MIER) | RX_INTS | TX_INTS,
64162306a36Sopenharmony_ci			  ioaddr + MIER);
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci	return work_done;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/* The RDC interrupt handler. */
64762306a36Sopenharmony_cistatic irqreturn_t r6040_interrupt(int irq, void *dev_id)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct net_device *dev = dev_id;
65062306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
65162306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
65262306a36Sopenharmony_ci	u16 misr, status;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* Save MIER */
65562306a36Sopenharmony_ci	misr = ioread16(ioaddr + MIER);
65662306a36Sopenharmony_ci	/* Mask off RDC MAC interrupt */
65762306a36Sopenharmony_ci	iowrite16(MSK_INT, ioaddr + MIER);
65862306a36Sopenharmony_ci	/* Read MISR status and clear */
65962306a36Sopenharmony_ci	status = ioread16(ioaddr + MISR);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (status == 0x0000 || status == 0xffff) {
66262306a36Sopenharmony_ci		/* Restore RDC MAC interrupt */
66362306a36Sopenharmony_ci		iowrite16(misr, ioaddr + MIER);
66462306a36Sopenharmony_ci		return IRQ_NONE;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	/* RX interrupt request */
66862306a36Sopenharmony_ci	if (status & (RX_INTS | TX_INTS)) {
66962306a36Sopenharmony_ci		if (status & RX_NO_DESC) {
67062306a36Sopenharmony_ci			/* RX descriptor unavailable */
67162306a36Sopenharmony_ci			dev->stats.rx_dropped++;
67262306a36Sopenharmony_ci			dev->stats.rx_missed_errors++;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci		if (status & RX_FIFO_FULL)
67562306a36Sopenharmony_ci			dev->stats.rx_fifo_errors++;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci		if (likely(napi_schedule_prep(&lp->napi))) {
67862306a36Sopenharmony_ci			/* Mask off RX interrupt */
67962306a36Sopenharmony_ci			misr &= ~(RX_INTS | TX_INTS);
68062306a36Sopenharmony_ci			__napi_schedule_irqoff(&lp->napi);
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Restore RDC MAC interrupt */
68562306a36Sopenharmony_ci	iowrite16(misr, ioaddr + MIER);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	return IRQ_HANDLED;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
69162306a36Sopenharmony_cistatic void r6040_poll_controller(struct net_device *dev)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	disable_irq(dev->irq);
69462306a36Sopenharmony_ci	r6040_interrupt(dev->irq, dev);
69562306a36Sopenharmony_ci	enable_irq(dev->irq);
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci#endif
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci/* Init RDC MAC */
70062306a36Sopenharmony_cistatic int r6040_up(struct net_device *dev)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
70362306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
70462306a36Sopenharmony_ci	int ret;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Initialise and alloc RX/TX buffers */
70762306a36Sopenharmony_ci	r6040_init_txbufs(dev);
70862306a36Sopenharmony_ci	ret = r6040_alloc_rxbufs(dev);
70962306a36Sopenharmony_ci	if (ret)
71062306a36Sopenharmony_ci		return ret;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	/* improve performance (by RDC guys) */
71362306a36Sopenharmony_ci	r6040_phy_write(ioaddr, 30, 17,
71462306a36Sopenharmony_ci			(r6040_phy_read(ioaddr, 30, 17) | 0x4000));
71562306a36Sopenharmony_ci	r6040_phy_write(ioaddr, 30, 17,
71662306a36Sopenharmony_ci			~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
71762306a36Sopenharmony_ci	r6040_phy_write(ioaddr, 0, 19, 0x0000);
71862306a36Sopenharmony_ci	r6040_phy_write(ioaddr, 0, 30, 0x01F0);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	/* Initialize all MAC registers */
72162306a36Sopenharmony_ci	r6040_init_mac_regs(dev);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	phy_start(dev->phydev);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return 0;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci/* Read/set MAC address routines */
73062306a36Sopenharmony_cistatic void r6040_mac_address(struct net_device *dev)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
73362306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
73462306a36Sopenharmony_ci	const u16 *adrp;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* Reset MAC */
73762306a36Sopenharmony_ci	r6040_reset_mac(lp);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	/* Restore MAC Address */
74062306a36Sopenharmony_ci	adrp = (const u16 *) dev->dev_addr;
74162306a36Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
74262306a36Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
74362306a36Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int r6040_open(struct net_device *dev)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
74962306a36Sopenharmony_ci	int ret;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	/* Request IRQ and Register interrupt handler */
75262306a36Sopenharmony_ci	ret = request_irq(dev->irq, r6040_interrupt,
75362306a36Sopenharmony_ci		IRQF_SHARED, dev->name, dev);
75462306a36Sopenharmony_ci	if (ret)
75562306a36Sopenharmony_ci		goto out;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Set MAC address */
75862306a36Sopenharmony_ci	r6040_mac_address(dev);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/* Allocate Descriptor memory */
76162306a36Sopenharmony_ci	lp->rx_ring =
76262306a36Sopenharmony_ci		dma_alloc_coherent(&lp->pdev->dev, RX_DESC_SIZE,
76362306a36Sopenharmony_ci				   &lp->rx_ring_dma, GFP_KERNEL);
76462306a36Sopenharmony_ci	if (!lp->rx_ring) {
76562306a36Sopenharmony_ci		ret = -ENOMEM;
76662306a36Sopenharmony_ci		goto err_free_irq;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	lp->tx_ring =
77062306a36Sopenharmony_ci		dma_alloc_coherent(&lp->pdev->dev, TX_DESC_SIZE,
77162306a36Sopenharmony_ci				   &lp->tx_ring_dma, GFP_KERNEL);
77262306a36Sopenharmony_ci	if (!lp->tx_ring) {
77362306a36Sopenharmony_ci		ret = -ENOMEM;
77462306a36Sopenharmony_ci		goto err_free_rx_ring;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	ret = r6040_up(dev);
77862306a36Sopenharmony_ci	if (ret)
77962306a36Sopenharmony_ci		goto err_free_tx_ring;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	napi_enable(&lp->napi);
78262306a36Sopenharmony_ci	netif_start_queue(dev);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cierr_free_tx_ring:
78762306a36Sopenharmony_ci	dma_free_coherent(&lp->pdev->dev, TX_DESC_SIZE, lp->tx_ring,
78862306a36Sopenharmony_ci			  lp->tx_ring_dma);
78962306a36Sopenharmony_cierr_free_rx_ring:
79062306a36Sopenharmony_ci	dma_free_coherent(&lp->pdev->dev, RX_DESC_SIZE, lp->rx_ring,
79162306a36Sopenharmony_ci			  lp->rx_ring_dma);
79262306a36Sopenharmony_cierr_free_irq:
79362306a36Sopenharmony_ci	free_irq(dev->irq, dev);
79462306a36Sopenharmony_ciout:
79562306a36Sopenharmony_ci	return ret;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
79962306a36Sopenharmony_ci				    struct net_device *dev)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
80262306a36Sopenharmony_ci	struct r6040_descriptor *descptr;
80362306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
80462306a36Sopenharmony_ci	unsigned long flags;
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (skb_put_padto(skb, ETH_ZLEN) < 0)
80762306a36Sopenharmony_ci		return NETDEV_TX_OK;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/* Critical Section */
81062306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* TX resource check */
81362306a36Sopenharmony_ci	if (!lp->tx_free_desc) {
81462306a36Sopenharmony_ci		spin_unlock_irqrestore(&lp->lock, flags);
81562306a36Sopenharmony_ci		netif_stop_queue(dev);
81662306a36Sopenharmony_ci		netdev_err(dev, ": no tx descriptor\n");
81762306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Set TX descriptor & Transmit it */
82162306a36Sopenharmony_ci	lp->tx_free_desc--;
82262306a36Sopenharmony_ci	descptr = lp->tx_insert_ptr;
82362306a36Sopenharmony_ci	descptr->len = skb->len;
82462306a36Sopenharmony_ci	descptr->skb_ptr = skb;
82562306a36Sopenharmony_ci	descptr->buf = cpu_to_le32(dma_map_single(&lp->pdev->dev, skb->data,
82662306a36Sopenharmony_ci						  skb->len, DMA_TO_DEVICE));
82762306a36Sopenharmony_ci	descptr->status = DSC_OWNER_MAC;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	skb_tx_timestamp(skb);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Trigger the MAC to check the TX descriptor */
83262306a36Sopenharmony_ci	if (!netdev_xmit_more() || netif_queue_stopped(dev))
83362306a36Sopenharmony_ci		iowrite16(TM2TX, ioaddr + MTPR);
83462306a36Sopenharmony_ci	lp->tx_insert_ptr = descptr->vndescp;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	/* If no tx resource, stop */
83762306a36Sopenharmony_ci	if (!lp->tx_free_desc)
83862306a36Sopenharmony_ci		netif_stop_queue(dev);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return NETDEV_TX_OK;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void r6040_multicast_list(struct net_device *dev)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
84862306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
84962306a36Sopenharmony_ci	unsigned long flags;
85062306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
85162306a36Sopenharmony_ci	int i;
85262306a36Sopenharmony_ci	const u16 *adrp;
85362306a36Sopenharmony_ci	u16 hash_table[4] = { 0 };
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	spin_lock_irqsave(&lp->lock, flags);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	/* Keep our MAC Address */
85862306a36Sopenharmony_ci	adrp = (const u16 *)dev->dev_addr;
85962306a36Sopenharmony_ci	iowrite16(adrp[0], ioaddr + MID_0L);
86062306a36Sopenharmony_ci	iowrite16(adrp[1], ioaddr + MID_0M);
86162306a36Sopenharmony_ci	iowrite16(adrp[2], ioaddr + MID_0H);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* Clear AMCP & PROM bits */
86462306a36Sopenharmony_ci	lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	/* Promiscuous mode */
86762306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC)
86862306a36Sopenharmony_ci		lp->mcr0 |= MCR0_PROMISC;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* Enable multicast hash table function to
87162306a36Sopenharmony_ci	 * receive all multicast packets. */
87262306a36Sopenharmony_ci	else if (dev->flags & IFF_ALLMULTI) {
87362306a36Sopenharmony_ci		lp->mcr0 |= MCR0_HASH_EN;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		for (i = 0; i < MCAST_MAX ; i++) {
87662306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
87762306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
87862306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
87962306a36Sopenharmony_ci		}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		for (i = 0; i < 4; i++)
88262306a36Sopenharmony_ci			hash_table[i] = 0xffff;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci	/* Use internal multicast address registers if the number of
88562306a36Sopenharmony_ci	 * multicast addresses is not greater than MCAST_MAX. */
88662306a36Sopenharmony_ci	else if (netdev_mc_count(dev) <= MCAST_MAX) {
88762306a36Sopenharmony_ci		i = 0;
88862306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
88962306a36Sopenharmony_ci			u16 *adrp = (u16 *) ha->addr;
89062306a36Sopenharmony_ci			iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
89162306a36Sopenharmony_ci			iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
89262306a36Sopenharmony_ci			iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
89362306a36Sopenharmony_ci			i++;
89462306a36Sopenharmony_ci		}
89562306a36Sopenharmony_ci		while (i < MCAST_MAX) {
89662306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
89762306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
89862306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
89962306a36Sopenharmony_ci			i++;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci	/* Otherwise, Enable multicast hash table function. */
90362306a36Sopenharmony_ci	else {
90462306a36Sopenharmony_ci		u32 crc;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci		lp->mcr0 |= MCR0_HASH_EN;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci		for (i = 0; i < MCAST_MAX ; i++) {
90962306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1L + 8 * i);
91062306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1M + 8 * i);
91162306a36Sopenharmony_ci			iowrite16(0, ioaddr + MID_1H + 8 * i);
91262306a36Sopenharmony_ci		}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		/* Build multicast hash table */
91562306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
91662306a36Sopenharmony_ci			u8 *addrs = ha->addr;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci			crc = ether_crc(ETH_ALEN, addrs);
91962306a36Sopenharmony_ci			crc >>= 26;
92062306a36Sopenharmony_ci			hash_table[crc >> 4] |= 1 << (crc & 0xf);
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	iowrite16(lp->mcr0, ioaddr + MCR0);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	/* Fill the MAC hash tables with their values */
92762306a36Sopenharmony_ci	if (lp->mcr0 & MCR0_HASH_EN) {
92862306a36Sopenharmony_ci		iowrite16(hash_table[0], ioaddr + MAR0);
92962306a36Sopenharmony_ci		iowrite16(hash_table[1], ioaddr + MAR1);
93062306a36Sopenharmony_ci		iowrite16(hash_table[2], ioaddr + MAR2);
93162306a36Sopenharmony_ci		iowrite16(hash_table[3], ioaddr + MAR3);
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	spin_unlock_irqrestore(&lp->lock, flags);
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev,
93862306a36Sopenharmony_ci			struct ethtool_drvinfo *info)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct r6040_private *rp = netdev_priv(dev);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
94362306a36Sopenharmony_ci	strscpy(info->version, DRV_VERSION, sizeof(info->version));
94462306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
94562306a36Sopenharmony_ci}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = {
94862306a36Sopenharmony_ci	.get_drvinfo		= netdev_get_drvinfo,
94962306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
95062306a36Sopenharmony_ci	.get_ts_info		= ethtool_op_get_ts_info,
95162306a36Sopenharmony_ci	.get_link_ksettings     = phy_ethtool_get_link_ksettings,
95262306a36Sopenharmony_ci	.set_link_ksettings     = phy_ethtool_set_link_ksettings,
95362306a36Sopenharmony_ci	.nway_reset		= phy_ethtool_nway_reset,
95462306a36Sopenharmony_ci};
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic const struct net_device_ops r6040_netdev_ops = {
95762306a36Sopenharmony_ci	.ndo_open		= r6040_open,
95862306a36Sopenharmony_ci	.ndo_stop		= r6040_close,
95962306a36Sopenharmony_ci	.ndo_start_xmit		= r6040_start_xmit,
96062306a36Sopenharmony_ci	.ndo_get_stats		= r6040_get_stats,
96162306a36Sopenharmony_ci	.ndo_set_rx_mode	= r6040_multicast_list,
96262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
96362306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
96462306a36Sopenharmony_ci	.ndo_eth_ioctl		= phy_do_ioctl,
96562306a36Sopenharmony_ci	.ndo_tx_timeout		= r6040_tx_timeout,
96662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
96762306a36Sopenharmony_ci	.ndo_poll_controller	= r6040_poll_controller,
96862306a36Sopenharmony_ci#endif
96962306a36Sopenharmony_ci};
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic void r6040_adjust_link(struct net_device *dev)
97262306a36Sopenharmony_ci{
97362306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
97462306a36Sopenharmony_ci	struct phy_device *phydev = dev->phydev;
97562306a36Sopenharmony_ci	int status_changed = 0;
97662306a36Sopenharmony_ci	void __iomem *ioaddr = lp->base;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	BUG_ON(!phydev);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (lp->old_link != phydev->link) {
98162306a36Sopenharmony_ci		status_changed = 1;
98262306a36Sopenharmony_ci		lp->old_link = phydev->link;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* reflect duplex change */
98662306a36Sopenharmony_ci	if (phydev->link && (lp->old_duplex != phydev->duplex)) {
98762306a36Sopenharmony_ci		lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0);
98862306a36Sopenharmony_ci		iowrite16(lp->mcr0, ioaddr);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci		status_changed = 1;
99162306a36Sopenharmony_ci		lp->old_duplex = phydev->duplex;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	if (status_changed)
99562306a36Sopenharmony_ci		phy_print_status(phydev);
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int r6040_mii_probe(struct net_device *dev)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
100162306a36Sopenharmony_ci	struct phy_device *phydev = NULL;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	phydev = phy_find_first(lp->mii_bus);
100462306a36Sopenharmony_ci	if (!phydev) {
100562306a36Sopenharmony_ci		dev_err(&lp->pdev->dev, "no PHY found\n");
100662306a36Sopenharmony_ci		return -ENODEV;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	phydev = phy_connect(dev, phydev_name(phydev), &r6040_adjust_link,
101062306a36Sopenharmony_ci			     PHY_INTERFACE_MODE_MII);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (IS_ERR(phydev)) {
101362306a36Sopenharmony_ci		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
101462306a36Sopenharmony_ci		return PTR_ERR(phydev);
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	phy_set_max_speed(phydev, SPEED_100);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	lp->old_link = 0;
102062306a36Sopenharmony_ci	lp->old_duplex = -1;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	phy_attached_info(phydev);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return 0;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_cistatic int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	struct net_device *dev;
103062306a36Sopenharmony_ci	struct r6040_private *lp;
103162306a36Sopenharmony_ci	void __iomem *ioaddr;
103262306a36Sopenharmony_ci	int err, io_size = R6040_IO_SIZE;
103362306a36Sopenharmony_ci	static int card_idx = -1;
103462306a36Sopenharmony_ci	u16 addr[ETH_ALEN / 2];
103562306a36Sopenharmony_ci	int bar = 0;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	pr_info("%s\n", version);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	err = pci_enable_device(pdev);
104062306a36Sopenharmony_ci	if (err)
104162306a36Sopenharmony_ci		goto err_out;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* this should always be supported */
104462306a36Sopenharmony_ci	err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
104562306a36Sopenharmony_ci	if (err) {
104662306a36Sopenharmony_ci		dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n");
104762306a36Sopenharmony_ci		goto err_out_disable_dev;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci	err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
105062306a36Sopenharmony_ci	if (err) {
105162306a36Sopenharmony_ci		dev_err(&pdev->dev, "32-bit PCI DMA addresses not supported by the card\n");
105262306a36Sopenharmony_ci		goto err_out_disable_dev;
105362306a36Sopenharmony_ci	}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* IO Size check */
105662306a36Sopenharmony_ci	if (pci_resource_len(pdev, bar) < io_size) {
105762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
105862306a36Sopenharmony_ci		err = -EIO;
105962306a36Sopenharmony_ci		goto err_out_disable_dev;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	pci_set_master(pdev);
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct r6040_private));
106562306a36Sopenharmony_ci	if (!dev) {
106662306a36Sopenharmony_ci		err = -ENOMEM;
106762306a36Sopenharmony_ci		goto err_out_disable_dev;
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
107062306a36Sopenharmony_ci	lp = netdev_priv(dev);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	err = pci_request_regions(pdev, DRV_NAME);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (err) {
107562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to request PCI regions\n");
107662306a36Sopenharmony_ci		goto err_out_free_dev;
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	ioaddr = pci_iomap(pdev, bar, io_size);
108062306a36Sopenharmony_ci	if (!ioaddr) {
108162306a36Sopenharmony_ci		dev_err(&pdev->dev, "ioremap failed for device\n");
108262306a36Sopenharmony_ci		err = -EIO;
108362306a36Sopenharmony_ci		goto err_out_free_res;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* If PHY status change register is still set to zero it means the
108762306a36Sopenharmony_ci	 * bootloader didn't initialize it, so we set it to:
108862306a36Sopenharmony_ci	 * - enable phy status change
108962306a36Sopenharmony_ci	 * - enable all phy addresses
109062306a36Sopenharmony_ci	 * - set to lowest timer divider */
109162306a36Sopenharmony_ci	if (ioread16(ioaddr + PHY_CC) == 0)
109262306a36Sopenharmony_ci		iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT |
109362306a36Sopenharmony_ci				7 << TMRDIV_SHIFT, ioaddr + PHY_CC);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	/* Init system & device */
109662306a36Sopenharmony_ci	lp->base = ioaddr;
109762306a36Sopenharmony_ci	dev->irq = pdev->irq;
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	spin_lock_init(&lp->lock);
110062306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/* Set MAC address */
110362306a36Sopenharmony_ci	card_idx++;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	addr[0] = ioread16(ioaddr + MID_0L);
110662306a36Sopenharmony_ci	addr[1] = ioread16(ioaddr + MID_0M);
110762306a36Sopenharmony_ci	addr[2] = ioread16(ioaddr + MID_0H);
110862306a36Sopenharmony_ci	eth_hw_addr_set(dev, (u8 *)addr);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* Some bootloader/BIOSes do not initialize
111162306a36Sopenharmony_ci	 * MAC address, warn about that */
111262306a36Sopenharmony_ci	if (!(addr[0] || addr[1] || addr[2])) {
111362306a36Sopenharmony_ci		netdev_warn(dev, "MAC address not initialized, "
111462306a36Sopenharmony_ci					"generating random\n");
111562306a36Sopenharmony_ci		eth_hw_addr_random(dev);
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* Link new device into r6040_root_dev */
111962306a36Sopenharmony_ci	lp->pdev = pdev;
112062306a36Sopenharmony_ci	lp->dev = dev;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	/* Init RDC private data */
112362306a36Sopenharmony_ci	lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	/* The RDC-specific entries in the device structure. */
112662306a36Sopenharmony_ci	dev->netdev_ops = &r6040_netdev_ops;
112762306a36Sopenharmony_ci	dev->ethtool_ops = &netdev_ethtool_ops;
112862306a36Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	netif_napi_add(dev, &lp->napi, r6040_poll);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	lp->mii_bus = mdiobus_alloc();
113362306a36Sopenharmony_ci	if (!lp->mii_bus) {
113462306a36Sopenharmony_ci		dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
113562306a36Sopenharmony_ci		err = -ENOMEM;
113662306a36Sopenharmony_ci		goto err_out_unmap;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	lp->mii_bus->priv = dev;
114062306a36Sopenharmony_ci	lp->mii_bus->read = r6040_mdiobus_read;
114162306a36Sopenharmony_ci	lp->mii_bus->write = r6040_mdiobus_write;
114262306a36Sopenharmony_ci	lp->mii_bus->name = "r6040_eth_mii";
114362306a36Sopenharmony_ci	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
114462306a36Sopenharmony_ci		dev_name(&pdev->dev), card_idx);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	err = mdiobus_register(lp->mii_bus);
114762306a36Sopenharmony_ci	if (err) {
114862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to register MII bus\n");
114962306a36Sopenharmony_ci		goto err_out_mdio;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	err = r6040_mii_probe(dev);
115362306a36Sopenharmony_ci	if (err) {
115462306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to probe MII bus\n");
115562306a36Sopenharmony_ci		goto err_out_mdio_unregister;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	/* Register net device. After this dev->name assign */
115962306a36Sopenharmony_ci	err = register_netdev(dev);
116062306a36Sopenharmony_ci	if (err) {
116162306a36Sopenharmony_ci		dev_err(&pdev->dev, "Failed to register net device\n");
116262306a36Sopenharmony_ci		goto err_out_phy_disconnect;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci	return 0;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cierr_out_phy_disconnect:
116762306a36Sopenharmony_ci	phy_disconnect(dev->phydev);
116862306a36Sopenharmony_cierr_out_mdio_unregister:
116962306a36Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
117062306a36Sopenharmony_cierr_out_mdio:
117162306a36Sopenharmony_ci	mdiobus_free(lp->mii_bus);
117262306a36Sopenharmony_cierr_out_unmap:
117362306a36Sopenharmony_ci	netif_napi_del(&lp->napi);
117462306a36Sopenharmony_ci	pci_iounmap(pdev, ioaddr);
117562306a36Sopenharmony_cierr_out_free_res:
117662306a36Sopenharmony_ci	pci_release_regions(pdev);
117762306a36Sopenharmony_cierr_out_free_dev:
117862306a36Sopenharmony_ci	free_netdev(dev);
117962306a36Sopenharmony_cierr_out_disable_dev:
118062306a36Sopenharmony_ci	pci_disable_device(pdev);
118162306a36Sopenharmony_cierr_out:
118262306a36Sopenharmony_ci	return err;
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_cistatic void r6040_remove_one(struct pci_dev *pdev)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
118862306a36Sopenharmony_ci	struct r6040_private *lp = netdev_priv(dev);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	unregister_netdev(dev);
119162306a36Sopenharmony_ci	phy_disconnect(dev->phydev);
119262306a36Sopenharmony_ci	mdiobus_unregister(lp->mii_bus);
119362306a36Sopenharmony_ci	mdiobus_free(lp->mii_bus);
119462306a36Sopenharmony_ci	netif_napi_del(&lp->napi);
119562306a36Sopenharmony_ci	pci_iounmap(pdev, lp->base);
119662306a36Sopenharmony_ci	pci_release_regions(pdev);
119762306a36Sopenharmony_ci	free_netdev(dev);
119862306a36Sopenharmony_ci	pci_disable_device(pdev);
119962306a36Sopenharmony_ci}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic const struct pci_device_id r6040_pci_tbl[] = {
120362306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
120462306a36Sopenharmony_ci	{ 0 }
120562306a36Sopenharmony_ci};
120662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic struct pci_driver r6040_driver = {
120962306a36Sopenharmony_ci	.name		= DRV_NAME,
121062306a36Sopenharmony_ci	.id_table	= r6040_pci_tbl,
121162306a36Sopenharmony_ci	.probe		= r6040_init_one,
121262306a36Sopenharmony_ci	.remove		= r6040_remove_one,
121362306a36Sopenharmony_ci};
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cimodule_pci_driver(r6040_driver);
1216