17a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/*
27a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * RDC R6040 Fast Ethernet MAC support
37a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang *
47a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw>
57a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * Copyright (C) 2007
65ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu *	Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
77a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang *	Florian Fainelli <florian@openwrt.org>
87a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang *
97a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * This program is free software; you can redistribute it and/or
107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * modify it under the terms of the GNU General Public License
117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * as published by the Free Software Foundation; either version 2
127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * of the License, or (at your option) any later version.
137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang *
147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * This program is distributed in the hope that it will be useful,
157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * but WITHOUT ANY WARRANTY; without even the implied warranty of
167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * GNU General Public License for more details.
187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang *
197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * You should have received a copy of the GNU General Public License
207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * along with this program; if not, write to the
217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang * Boston, MA  02110-1301, USA.
237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang*/
247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/kernel.h>
267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/module.h>
277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/moduleparam.h>
287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/string.h>
297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/timer.h>
307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/errno.h>
317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/ioport.h>
327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/interrupt.h>
337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/pci.h>
347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/netdevice.h>
357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/etherdevice.h>
367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/skbuff.h>
377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/init.h>
387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/delay.h>
397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/mii.h>
407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/ethtool.h>
417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/crc32.h>
427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/spinlock.h>
43092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/bitops.h>
44092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/io.h>
45092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/irq.h>
46092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/uaccess.h>
473831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli#include <linux/phy.h>
487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <asm/processor.h>
507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define DRV_NAME	"r6040"
525bdc4f5de1345c221f5b51d73fafe3e5de718a54Florian Fainelli#define DRV_VERSION	"0.28"
535bdc4f5de1345c221f5b51d73fafe3e5de718a54Florian Fainelli#define DRV_RELDATE	"07Oct2011"
547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Time in jiffies before concluding the transmitter is hung. */
565ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu#define TX_TIMEOUT	(6000 * HZ / 1000)
577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* RDC MAC I/O Size */
597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define R6040_IO_SIZE	256
607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* MAX RDC MAC */
627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAX_MAC		2
637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* MAC registers */
657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MCR0		0x00	/* Control register 0 */
664e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_RCVEN	0x0002	/* Receive enable */
67c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin#define  MCR0_PROMISC	0x0020	/* Promiscuous mode */
68c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin#define  MCR0_HASH_EN	0x0100	/* Enable multicast hash table function */
694e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_XMTEN	0x1000	/* Transmission enable */
704e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_FD	0x8000	/* Full/Half duplex */
717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MCR1		0x04	/* Control register 1 */
727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MAC_RST	0x0001	/* Reset the MAC */
737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MBCR		0x08	/* Bus control */
747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MT_ICR		0x0C	/* TX interrupt control */
757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_ICR		0x10	/* RX interrupt control */
767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTPR		0x14	/* TX poll command register */
777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_BSR		0x18	/* RX buffer size */
787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_DCR		0x1A	/* RX descriptor control */
797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MLSR		0x1C	/* Last status */
807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMDIO		0x20	/* MDIO control register */
817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MDIO_WRITE	0x4000	/* MDIO write */
827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MDIO_READ	0x2000	/* MDIO read */
837a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMRD		0x24	/* MDIO read data register */
847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMWD		0x28	/* MDIO write data register */
857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTD_SA0		0x2C	/* TX descriptor start address 0 */
867a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTD_SA1		0x30	/* TX descriptor start address 1 */
877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MRD_SA0		0x34	/* RX descriptor start address 0 */
887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MRD_SA1		0x38	/* RX descriptor start address 1 */
897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MISR		0x3C	/* Status register */
907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MIER		0x40	/* INT enable register */
917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MSK_INT	0x0000	/* Mask off interrupts */
923d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_FINISH	0x0001  /* RX finished */
933d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_NO_DESC	0x0002  /* No RX descriptor available */
943d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_FIFO_FULL	0x0004  /* RX FIFO full */
953d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_EARLY	0x0008  /* RX early */
963d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  TX_FINISH	0x0010  /* TX finished */
973d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  TX_EARLY	0x0080  /* TX early */
983d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  EVENT_OVRFL	0x0100  /* Event counter overflow */
993d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  LINK_CHANGED	0x0200  /* PHY link changed */
1007a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CISR		0x44	/* Event counter INT status */
1017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CIER		0x48	/* Event counter INT enable  */
1027a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_CNT		0x50	/* Successfully received packet counter */
1037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT0		0x52	/* Event counter 0 */
1047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT1		0x54	/* Event counter 1 */
1057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT2		0x56	/* Event counter 2 */
1067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT3		0x58	/* Event counter 3 */
1077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MT_CNT		0x5A	/* Successfully transmit packet counter */
1087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT4		0x5C	/* Event counter 4 */
1097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MP_CNT		0x5E	/* Pause frame counter register */
1107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR0		0x60	/* Hash table 0 */
1117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR1		0x62	/* Hash table 1 */
1127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR2		0x64	/* Hash table 2 */
1137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR3		0x66	/* Hash table 3 */
1147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0L		0x68	/* Multicast address MID0 Low */
1157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0M		0x6A	/* Multicast address MID0 Medium */
1167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0H		0x6C	/* Multicast address MID0 High */
1177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1L		0x70	/* MID1 Low */
1187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1M		0x72	/* MID1 Medium */
1197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1H		0x74	/* MID1 High */
1207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2L		0x78	/* MID2 Low */
1217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2M		0x7A	/* MID2 Medium */
1227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2H		0x7C	/* MID2 High */
1237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3L		0x80	/* MID3 Low */
1247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3M		0x82	/* MID3 Medium */
1257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3H		0x84	/* MID3 High */
1267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define PHY_CC		0x88	/* PHY status change configuration register */
1277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define PHY_ST		0x8A	/* PHY status register */
1287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAC_SM		0xAC	/* MAC status machine */
129e1477637967d0d8db3083bacb241c796c3c4f23bFlorian Fainelli#define  MAC_SM_RST	0x0002	/* MAC status machine reset */
1307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAC_ID		0xBE	/* Identifier register */
1317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define TX_DCNT		0x80	/* TX descriptor count */
1337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define RX_DCNT		0x80	/* RX descriptor count */
1347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAX_BUF_SIZE	0x600
1356c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))
1366c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))
1377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */
1383bcf8229a8c49769e48d3e0bd1e20d8e003f8106Florian Fainelli#define MCAST_MAX	3	/* Max number multicast addresses to filter */
1397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
14032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli/* Descriptor status */
14132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_OWNER_MAC	0x8000	/* MAC is the owner of this descriptor */
14232f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_OK	0x4000	/* RX was successful */
14332f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR	0x0800	/* RX PHY error */
14432f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_DRI	0x0400	/* RX dribble packet */
14532f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_BUF	0x0200	/* RX length exceeds buffer size */
14632f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_LONG	0x0100	/* RX length > maximum packet length */
14732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_RUNT	0x0080	/* RX packet length < 64 byte */
14832f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_CRC	0x0040	/* RX CRC error */
14932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_BCAST	0x0020	/* RX broadcast (no error) */
15032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MCAST	0x0010	/* RX multicast (no error) */
15132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MCH_HIT	0x0008	/* RX multicast hit in hash table (no error) */
15232f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MIDH_HIT	0x0004	/* RX MID table hit (no error) */
15332f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_IDX_MID_MASK 3	/* RX mask for the index of matched MIDx */
15432f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli
1557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"
1567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"
1577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	"Florian Fainelli <florian@openwrt.org>");
1587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_LICENSE("GPL");
1597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");
160bc4de26040d3bdc170aaa47044adf9d318a06772Florian FainelliMODULE_VERSION(DRV_VERSION " " DRV_RELDATE);
1617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1623d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli/* RX and TX interrupts that we handle */
163e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define RX_INTS			(RX_FIFO_FULL | RX_NO_DESC | RX_FINISH)
164e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define TX_INTS			(TX_FINISH)
165e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define INT_MASK		(RX_INTS | TX_INTS)
1667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstruct r6040_descriptor {
1687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16	status, len;		/* 0-3 */
1697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	__le32	buf;			/* 4-7 */
1707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	__le32	ndesc;			/* 8-B */
1717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u32	rev1;			/* C-F */
1727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	char	*vbufp;			/* 10-13 */
1737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *vndescp;	/* 14-17 */
1747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct sk_buff *skb_ptr;	/* 18-1B */
1757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u32	rev2;			/* 1C-1F */
176853d5dc95b41babb7001934becad9c944738d8e3Florian Fainelli} __aligned(32);
1777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstruct r6040_private {
1797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spinlock_t lock;		/* driver lock */
1807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct pci_dev *pdev;
1817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *rx_insert_ptr;
1827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *rx_remove_ptr;
1837a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *tx_insert_ptr;
1847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *tx_remove_ptr;
1856c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	struct r6040_descriptor *rx_ring;
1866c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	struct r6040_descriptor *tx_ring;
1876c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	dma_addr_t rx_ring_dma;
1886c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	dma_addr_t tx_ring_dma;
18949f26720d46476384a090c4e281be73e5de4f1e1Florian Fainelli	u16	tx_free_desc;
1907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16	mcr0, mcr1;
1917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev;
1923831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct mii_bus *mii_bus;
1937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct napi_struct napi;
1947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *base;
1953831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev;
1963831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int old_link;
1973831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int old_duplex;
1987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
1997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2002154c704c7240379fae4633359e06e8df875c1fdFlorian Fainellistatic char version[] __devinitdata = DRV_NAME
2017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	": RDC R6040 NAPI net driver,"
2029a48ce84004eb61940850c7066af5d222a5f81c9Florian Fainelli	"version "DRV_VERSION " (" DRV_RELDATE ")";
2037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Read a word data from PHY Chip */
205c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainellistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
2067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int limit = 2048;
2087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 cmd;
2097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);
2117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Wait for the read bit to be cleared */
2127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (limit--) {
2137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		cmd = ioread16(ioaddr + MMDIO);
21411e5e8f5d14a1229706576184d2cf4c4556ed94cJoe Chou		if (!(cmd & MDIO_READ))
2157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			break;
2167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
2177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return ioread16(ioaddr + MMRD);
2197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Write a word data from PHY Chip */
2222154c704c7240379fae4633359e06e8df875c1fdFlorian Fainellistatic void r6040_phy_write(void __iomem *ioaddr,
2232154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					int phy_addr, int reg, u16 val)
2247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int limit = 2048;
2267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 cmd;
2277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(val, ioaddr + MMWD);
2297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Write the command to the MDIO bus */
2307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);
2317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Wait for the write bit to be cleared */
2327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (limit--) {
2337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		cmd = ioread16(ioaddr + MMDIO);
23411e5e8f5d14a1229706576184d2cf4c4556ed94cJoe Chou		if (!(cmd & MDIO_WRITE))
2357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			break;
2367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
2377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2393831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
2407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2413831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct net_device *dev = bus->priv;
2427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
2437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
2447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2453831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return r6040_phy_read(ioaddr, phy_addr, reg);
2467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2483831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
2493831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli						int reg, u16 value)
2507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2513831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct net_device *dev = bus->priv;
2527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
2537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
2547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2553831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	r6040_phy_write(ioaddr, phy_addr, reg, value);
2563831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
2573831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return 0;
2583831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
2593831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
2603831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mdiobus_reset(struct mii_bus *bus)
2613831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli{
2623831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return 0;
2637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
265b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_free_txbufs(struct net_device *dev)
266b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
267b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
268b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	int i;
269b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
270b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	for (i = 0; i < TX_DCNT; i++) {
271b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		if (lp->tx_insert_ptr->skb_ptr) {
272ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro			pci_unmap_single(lp->pdev,
273ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro				le32_to_cpu(lp->tx_insert_ptr->buf),
274b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
275b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
2763b060be0582373be3c380629d7a6de5f06a311edFlorian Fainelli			lp->tx_insert_ptr->skb_ptr = NULL;
277b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		}
278b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
279b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
280b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
281b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
282b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_free_rxbufs(struct net_device *dev)
283b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
284b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
285b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	int i;
286b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
287b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	for (i = 0; i < RX_DCNT; i++) {
288b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		if (lp->rx_insert_ptr->skb_ptr) {
289ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro			pci_unmap_single(lp->pdev,
290ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro				le32_to_cpu(lp->rx_insert_ptr->buf),
291b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
292b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
293b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			lp->rx_insert_ptr->skb_ptr = NULL;
294b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		}
295b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
296b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
297b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
298b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
299b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
300b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				 dma_addr_t desc_dma, int size)
301b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
302b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_descriptor *desc = desc_ring;
303b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	dma_addr_t mapping = desc_dma;
304b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
305b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	while (size-- > 0) {
3063f6602ad56dc538a846367bd6a05ac7ac4d3e641Julia Lawall		mapping += sizeof(*desc);
307b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc->ndesc = cpu_to_le32(mapping);
308b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc->vndescp = desc + 1;
309b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc++;
310b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
311b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc--;
312b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc->ndesc = cpu_to_le32(desc_dma);
313b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc->vndescp = desc_ring;
314b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
315b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3163d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic void r6040_init_txbufs(struct net_device *dev)
317b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
318b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
319b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
320b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->tx_free_desc = TX_DCNT;
321b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
322b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
323b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
324b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
325b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3263d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic int r6040_alloc_rxbufs(struct net_device *dev)
327b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
328b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
3293d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	struct r6040_descriptor *desc;
3303d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	struct sk_buff *skb;
3313d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	int rc;
332b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
333b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
334b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
335b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3363d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	/* Allocate skbs for the rx descriptors */
3373d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	desc = lp->rx_ring;
3383d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	do {
3393d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
3403d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		if (!skb) {
3417d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli			netdev_err(dev, "failed to alloc skb for rx\n");
3423d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli			rc = -ENOMEM;
3433d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli			goto err_exit;
3443d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		}
3453d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc->skb_ptr = skb;
3463d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc->buf = cpu_to_le32(pci_map_single(lp->pdev,
3472154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					desc->skb_ptr->data,
3482154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
34932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		desc->status = DSC_OWNER_MAC;
3503d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc = desc->vndescp;
3513d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	} while (desc != lp->rx_ring);
3523d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
3533d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return 0;
3543d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
3553d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellierr_exit:
3563d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	/* Deallocate all previously allocated skbs */
3573d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	r6040_free_rxbufs(dev);
3583d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return rc;
359fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli}
360fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
361fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainellistatic void r6040_init_mac_regs(struct net_device *dev)
362fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli{
363fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
364fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	void __iomem *ioaddr = lp->base;
365fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	int limit = 2048;
366fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	u16 cmd;
367fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
368fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Mask Off Interrupt */
369fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MSK_INT, ioaddr + MIER);
370fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
371fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Reset RDC MAC */
372fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MAC_RST, ioaddr + MCR1);
373fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	while (limit--) {
374fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli		cmd = ioread16(ioaddr + MCR1);
37558dbc691e6ca6689402424db60f4a54745a38c67Florian Fainelli		if (cmd & MAC_RST)
376fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli			break;
377fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	}
378fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Reset internal state machine */
379e1477637967d0d8db3083bacb241c796c3c4f23bFlorian Fainelli	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
380fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(0, ioaddr + MAC_SM);
381c1d69937ee5818bcde3bed8c012c9f07d60e492eFlorian Fainelli	mdelay(5);
382fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
383fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* MAC Bus Control Register */
384fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
385fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
386fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Buffer Size Register */
387fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
388fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
389fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Write TX ring start address */
390fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
391fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
392b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
393fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Write RX ring start address */
394b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
395b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
396fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
397fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Set interrupt waiting time and packet numbers */
39831718dedf62fd62e807001138ab5ac76e9b11064Florian Fainelli	iowrite16(0, ioaddr + MT_ICR);
39931718dedf62fd62e807001138ab5ac76e9b11064Florian Fainelli	iowrite16(0, ioaddr + MR_ICR);
400fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
401fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Enable interrupts */
402fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(INT_MASK, ioaddr + MIER);
403fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
404fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Enable TX and RX */
4054e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli	iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr);
406fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
407fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Let TX poll the descriptors
408fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	 * we may got called by r6040_tx_timeout which has left
409fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	 * some unsent tx buffers */
410fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(0x01, ioaddr + MTPR);
411b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
4127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
413106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainellistatic void r6040_tx_timeout(struct net_device *dev)
414106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli{
415106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	struct r6040_private *priv = netdev_priv(dev);
416106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	void __iomem *ioaddr = priv->base;
417106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
4187d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli	netdev_warn(dev, "transmit timed out, int enable %4.4x "
4193831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		"status %4.4x\n",
4207d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		ioread16(ioaddr + MIER),
4213831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		ioread16(ioaddr + MISR));
422106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
423106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	dev->stats.tx_errors++;
424fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
425fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Reset MAC and re-init all registers */
426fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	r6040_init_mac_regs(dev);
427106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli}
428106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
4297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic struct net_device_stats *r6040_get_stats(struct net_device *dev)
4307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
4327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
4337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
4347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irqsave(&priv->lock, flags);
436d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
437d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);
4387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irqrestore(&priv->lock, flags);
4397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
440d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	return &dev->stats;
4417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
4427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Stop RDC MAC and Free the allocated resource */
4447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_down(struct net_device *dev)
4457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
4477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
4487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int limit = 2048;
4497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
4507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 cmd;
4517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Stop MAC */
4537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */
4547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MAC_RST, ioaddr + MCR1);	/* Reset RDC MAC */
4557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (limit--) {
4567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		cmd = ioread16(ioaddr + MCR1);
45758dbc691e6ca6689402424db60f4a54745a38c67Florian Fainelli		if (cmd & MAC_RST)
4587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			break;
4597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
4607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Restore MAC Address to MIDx */
4627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *) dev->dev_addr;
4637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
4647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
4657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
46606e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli
46706e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli	phy_stop(lp->phydev);
4687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
4697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4705ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic int r6040_close(struct net_device *dev)
4717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
47358854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	struct pci_dev *pdev = lp->pdev;
4747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irq(&lp->lock);
476129cf9a7028fc50b226b8021bc0b76fb38efa81dFlorian Fainelli	napi_disable(&lp->napi);
4777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_stop_queue(dev);
4787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	r6040_down(dev);
47958854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
48058854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	free_irq(dev->irq, dev);
48158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
48258854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free RX buffer */
48358854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	r6040_free_rxbufs(dev);
48458854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
48558854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free TX buffer */
48658854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	r6040_free_txbufs(dev);
48758854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
4887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irq(&lp->lock);
4897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
49058854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free Descriptor memory */
49158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	if (lp->rx_ring) {
4922154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		pci_free_consistent(pdev,
4932154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli				RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
4945b5103ec2dba07a15861e81cb783dd0fbaed24edHannes Eder		lp->rx_ring = NULL;
49558854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	}
49658854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
49758854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	if (lp->tx_ring) {
4982154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		pci_free_consistent(pdev,
4992154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli				TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
5005b5103ec2dba07a15861e81cb783dd0fbaed24edHannes Eder		lp->tx_ring = NULL;
50158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	}
50258854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
5037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
5047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
5077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
5087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
5097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5103831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->phydev)
5117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		return -EINVAL;
5123831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
5134cfa580e7eebb8694b875d2caff3b989ada2efacDavid S. Miller	return phy_mii_ioctl(lp->phydev, rq, cmd);
5147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_rx(struct net_device *dev, int limit)
5177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
5187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
5199ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	struct r6040_descriptor *descptr = priv->rx_remove_ptr;
5209ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	struct sk_buff *skb_ptr, *new_skb;
5219ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	int count = 0;
5227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 err;
5237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5249ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	/* Limit not reached and the descriptor belongs to the CPU */
52532f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli	while (count < limit && !(descptr->status & DSC_OWNER_MAC)) {
5269ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Read the descriptor status */
5279ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		err = descptr->status;
5289ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Global error status set */
52932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		if (err & DSC_RX_ERR) {
5309ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* RX dribble */
53132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_DRI)
5329ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_frame_errors++;
53325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi			/* Buffer length exceeded */
53432f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_BUF)
5359ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5369ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* Packet too long */
53732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_LONG)
5389ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5399ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* Packet < 64 bytes */
54032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_RUNT)
5419ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5429ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* CRC error */
54332f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_CRC) {
5449ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				spin_lock(&priv->lock);
5459ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_crc_errors++;
5469ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				spin_unlock(&priv->lock);
5477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			}
5489ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			goto next_descr;
5499ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		}
5502154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5519ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Packet successfully received */
5529ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
5539ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		if (!new_skb) {
5549ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			dev->stats.rx_dropped++;
5559ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			goto next_descr;
5567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		}
5579ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr = descptr->skb_ptr;
5589ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr->dev = priv->dev;
5592154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5609ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Do not count the CRC */
5619ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_put(skb_ptr, descptr->len - 4);
5629ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
5639ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
5649ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
5652154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5669ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Send to upper layer */
5679ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		netif_receive_skb(skb_ptr);
5689ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		dev->stats.rx_packets++;
5699ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		dev->stats.rx_bytes += descptr->len - 4;
5709ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli
5719ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* put new skb into descriptor */
5729ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr->skb_ptr = new_skb;
5739ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr->buf = cpu_to_le32(pci_map_single(priv->pdev,
5749ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli						descptr->skb_ptr->data,
5759ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
5769ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli
5779ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainellinext_descr:
5789ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* put the descriptor back to the MAC */
57932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		descptr->status = DSC_OWNER_MAC;
5809ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr = descptr->vndescp;
5819ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		count++;
5827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
5839ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	priv->rx_remove_ptr = descptr;
5847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return count;
5867a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_tx(struct net_device *dev)
5897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
5907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
5917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *descptr;
5927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
5937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct sk_buff *skb_ptr;
5947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 err;
5957a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5967a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock(&priv->lock);
5977a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr = priv->tx_remove_ptr;
5987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (priv->tx_free_desc < TX_DCNT) {
5997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Check for errors */
6007a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		err = ioread16(ioaddr + MLSR);
6017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
602d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli		if (err & 0x0200)
603d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli			dev->stats.rx_fifo_errors++;
604d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli		if (err & (0x2000 | 0x4000))
605d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli			dev->stats.tx_carrier_errors++;
6067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
60732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		if (descptr->status & DSC_OWNER_MAC)
608ec6d2d453a932fd50c5fd95d5aac633b4e5f241dFlorian Fainelli			break; /* Not complete */
6097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		skb_ptr = descptr->skb_ptr;
610ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
6117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			skb_ptr->len, PCI_DMA_TODEVICE);
6127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Free buffer */
6137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		dev_kfree_skb_irq(skb_ptr);
6147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr->skb_ptr = NULL;
6157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* To next descriptor */
6167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr = descptr->vndescp;
6177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		priv->tx_free_desc++;
6187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	priv->tx_remove_ptr = descptr;
6207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (priv->tx_free_desc)
6227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		netif_wake_queue(dev);
6237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock(&priv->lock);
6247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_poll(struct napi_struct *napi, int budget)
6277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv =
6297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		container_of(napi, struct r6040_private, napi);
6307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = priv->dev;
6317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
6327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int work_done;
6337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	work_done = r6040_rx(dev, budget);
6357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (work_done < budget) {
637288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
6387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Enable RX interrupt */
639e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER);
6407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return work_done;
6427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* The RDC interrupt handler. */
6457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic irqreturn_t r6040_interrupt(int irq, void *dev_id)
6467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = dev_id;
6487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
6497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
6503e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	u16 misr, status;
6517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6523e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	/* Save MIER */
6533e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	misr = ioread16(ioaddr + MIER);
6547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Mask off RDC MAC interrupt */
6557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MSK_INT, ioaddr + MIER);
6567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Read MISR status and clear */
6577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	status = ioread16(ioaddr + MISR);
6587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
65935976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli	if (status == 0x0000 || status == 0xffff) {
66035976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli		/* Restore RDC MAC interrupt */
66135976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli		iowrite16(misr, ioaddr + MIER);
6627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		return IRQ_NONE;
66335976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli	}
6647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* RX interrupt request */
666e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli	if (status & RX_INTS) {
667e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		if (status & RX_NO_DESC) {
668e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			/* RX descriptor unavailable */
669e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_dropped++;
670e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_missed_errors++;
671e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		}
672e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		if (status & RX_FIFO_FULL)
673e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_fifo_errors++;
674e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli
6750d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier		if (likely(napi_schedule_prep(&lp->napi))) {
6760d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			/* Mask off RX interrupt */
6770d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			misr &= ~RX_INTS;
6780d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			__napi_schedule(&lp->napi);
6790d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier		}
6807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* TX interrupt request */
683e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli	if (status & TX_INTS)
6847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		r6040_tx(dev);
6857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6863e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	/* Restore RDC MAC interrupt */
6873e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	iowrite16(misr, ioaddr + MIER);
6883e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou
689ec6d2d453a932fd50c5fd95d5aac633b4e5f241dFlorian Fainelli	return IRQ_HANDLED;
6907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#ifdef CONFIG_NET_POLL_CONTROLLER
6937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_poll_controller(struct net_device *dev)
6947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6957a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	disable_irq(dev->irq);
6965ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	r6040_interrupt(dev->irq, dev);
6977a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	enable_irq(dev->irq);
6987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#endif
7007a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Init RDC MAC */
7023d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic int r6040_up(struct net_device *dev)
7037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
7057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
7063d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	int ret;
7077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
708b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	/* Initialise and alloc RX/TX buffers */
7093d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	r6040_init_txbufs(dev);
7103d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	ret = r6040_alloc_rxbufs(dev);
7113d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	if (ret)
7123d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		return ret;
7137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* improve performance (by RDC guys) */
7152154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	r6040_phy_write(ioaddr, 30, 17,
7162154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli			(r6040_phy_read(ioaddr, 30, 17) | 0x4000));
7172154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	r6040_phy_write(ioaddr, 30, 17,
7182154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli			~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
719c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainelli	r6040_phy_write(ioaddr, 0, 19, 0x0000);
720c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainelli	r6040_phy_write(ioaddr, 0, 30, 0x01F0);
7217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
722fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Initialize all MAC registers */
723fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	r6040_init_mac_regs(dev);
7243d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
72506e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli	phy_start(lp->phydev);
72606e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli
7273d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return 0;
7287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Read/set MAC address routines */
7327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_mac_address(struct net_device *dev)
7337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
7357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
7367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
7377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
73848529680dc59061eaa13ea3b1047401612b79600Florian Fainelli	/* Reset MAC */
73948529680dc59061eaa13ea3b1047401612b79600Florian Fainelli	iowrite16(MAC_RST, ioaddr + MCR1);
74048529680dc59061eaa13ea3b1047401612b79600Florian Fainelli	/* Reset internal state machine */
74148529680dc59061eaa13ea3b1047401612b79600Florian Fainelli	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
7427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(0, ioaddr + MAC_SM);
743c1d69937ee5818bcde3bed8c012c9f07d60e492eFlorian Fainelli	mdelay(5);
7447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Restore MAC Address */
7467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *) dev->dev_addr;
7477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
7487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
7497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
75042099d7a3941d4aaf853caac92b3ae76149fc6e7Otavio Salvador
75142099d7a3941d4aaf853caac92b3ae76149fc6e7Otavio Salvador	/* Store MAC Address in perm_addr */
75242099d7a3941d4aaf853caac92b3ae76149fc6e7Otavio Salvador	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
7537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7555ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic int r6040_open(struct net_device *dev)
7567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7575ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	struct r6040_private *lp = netdev_priv(dev);
7587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int ret;
7597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Request IRQ and Register interrupt handler */
76191dcbf36f77c3d563e844fe0ed52ae896654ca7cJulia Lawall	ret = request_irq(dev->irq, r6040_interrupt,
7627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		IRQF_SHARED, dev->name, dev);
7637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (ret)
764ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto out;
7657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set MAC address */
7677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	r6040_mac_address(dev);
7687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Allocate Descriptor memory */
7706c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	lp->rx_ring =
7716c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu		pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma);
772ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	if (!lp->rx_ring) {
773ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		ret = -ENOMEM;
774ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_irq;
775ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	}
7767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7776c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	lp->tx_ring =
7786c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu		pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma);
7796c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	if (!lp->tx_ring) {
780ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		ret = -ENOMEM;
781ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_rx_ring;
7826c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	}
7836c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu
7843d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	ret = r6040_up(dev);
785ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	if (ret)
786ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_tx_ring;
7877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	napi_enable(&lp->napi);
7897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_start_queue(dev);
7907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
792ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov
793ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_tx_ring:
794ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
795ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov			lp->tx_ring_dma);
796ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_rx_ring:
797ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
798ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov			lp->rx_ring_dma);
799ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_irq:
800ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	free_irq(dev->irq, dev);
801ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanovout:
802ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	return ret;
8037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
8047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
80561357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
80661357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				    struct net_device *dev)
8077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
8087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
8097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *descptr;
8107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
8117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
8127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Critical Section */
8147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irqsave(&lp->lock, flags);
8157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* TX resource check */
8177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!lp->tx_free_desc) {
8187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		spin_unlock_irqrestore(&lp->lock, flags);
819092427be8cef341c957a93ec2469890501a09bffJeff Garzik		netif_stop_queue(dev);
8207d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		netdev_err(dev, ": no tx descriptor\n");
82161357325f377889a1daffa14962d705dc814dd0eStephen Hemminger		return NETDEV_TX_BUSY;
8227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
8237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Statistic Counter */
8257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->stats.tx_packets++;
8267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->stats.tx_bytes += skb->len;
8277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set TX descriptor & Transmit it */
8287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->tx_free_desc--;
8297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr = lp->tx_insert_ptr;
8307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (skb->len < MISR)
8317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr->len = MISR;
8327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	else
8337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr->len = skb->len;
8347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr->skb_ptr = skb;
8367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr->buf = cpu_to_le32(pci_map_single(lp->pdev,
8377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		skb->data, skb->len, PCI_DMA_TODEVICE));
83832f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli	descptr->status = DSC_OWNER_MAC;
8392aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran
8402aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran	skb_tx_timestamp(skb);
8412aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran
8427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Trigger the MAC to check the TX descriptor */
8437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(0x01, ioaddr + MTPR);
8447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->tx_insert_ptr = descptr->vndescp;
8457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* If no tx resource, stop */
8477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!lp->tx_free_desc)
8487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		netif_stop_queue(dev);
8497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irqrestore(&lp->lock, flags);
85161357325f377889a1daffa14962d705dc814dd0eStephen Hemminger
85261357325f377889a1daffa14962d705dc814dd0eStephen Hemminger	return NETDEV_TX_OK;
8537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
8547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8555ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic void r6040_multicast_list(struct net_device *dev)
8567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
8577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
8587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
8597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
86022bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
8617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int i;
862c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	u16 *adrp;
863c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	u16 hash_table[4] = { 0 };
864c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
865c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	spin_lock_irqsave(&lp->lock, flags);
8667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
867c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Keep our MAC Address */
8687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *)dev->dev_addr;
8697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
8707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
8717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
8727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Clear AMCP & PROM bits */
874c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
8757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
876c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Promiscuous mode */
877c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	if (dev->flags & IFF_PROMISC)
878c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_PROMISC;
8797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
880c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Enable multicast hash table function to
881c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	 * receive all multicast packets. */
882c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else if (dev->flags & IFF_ALLMULTI) {
883c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_HASH_EN;
8847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
885c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < MCAST_MAX ; i++) {
886c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
887c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
888c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
889c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
8907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
891c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < 4; i++)
892c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			hash_table[i] = 0xffff;
893c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
894c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Use internal multicast address registers if the number of
895c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	 * multicast addresses is not greater than MCAST_MAX. */
896c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else if (netdev_mc_count(dev) <= MCAST_MAX) {
897c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		i = 0;
89822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		netdev_for_each_mc_addr(ha, dev) {
899c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			u16 *adrp = (u16 *) ha->addr;
900c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
901c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
902c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
903c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			i++;
904c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
905c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		while (i < MCAST_MAX) {
906c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
907c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
908c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
909c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			i++;
910c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
911c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
912c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Otherwise, Enable multicast hash table function. */
913c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else {
914c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		u32 crc;
9157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
916c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_HASH_EN;
917c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
918c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < MCAST_MAX ; i++) {
919c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
920c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
921c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
922c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
9237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
924c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		/* Build multicast hash table */
925c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		netdev_for_each_mc_addr(ha, dev) {
926c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			u8 *addrs = ha->addr;
927c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
928c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			crc = ether_crc(ETH_ALEN, addrs);
9297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			crc >>= 26;
930c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			hash_table[crc >> 4] |= 1 << (crc & 0xf);
9317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		}
932c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
933c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
934c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	iowrite16(lp->mcr0, ioaddr + MCR0);
935c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
936c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Fill the MAC hash tables with their values */
937bbc13ab9d26f4ff675775dd7dc24d5cae17b85d5Florian Fainelli	if (lp->mcr0 & MCR0_HASH_EN) {
9387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[0], ioaddr + MAR0);
9397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[1], ioaddr + MAR1);
9407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[2], ioaddr + MAR2);
9417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[3], ioaddr + MAR3);
9427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
943c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
944c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	spin_unlock_irqrestore(&lp->lock, flags);
9457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void netdev_get_drvinfo(struct net_device *dev,
9487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			struct ethtool_drvinfo *info)
9497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	strcpy(info->driver, DRV_NAME);
9537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	strcpy(info->version, DRV_VERSION);
9547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	strcpy(info->bus_info, pci_name(rp->pdev));
9557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
9587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9613831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return  phy_ethtool_gset(rp->phydev, cmd);
9627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
9657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9683831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return phy_ethtool_sset(rp->phydev, cmd);
9697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
971a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemmingerstatic const struct ethtool_ops netdev_ethtool_ops = {
9727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.get_drvinfo		= netdev_get_drvinfo,
9737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.get_settings		= netdev_get_settings,
9747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.set_settings		= netdev_set_settings,
9753831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	.get_link		= ethtool_op_get_link,
9767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
9777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
978a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemmingerstatic const struct net_device_ops r6040_netdev_ops = {
979a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_open		= r6040_open,
980a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_stop		= r6040_close,
981a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_start_xmit		= r6040_start_xmit,
982a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_get_stats		= r6040_get_stats,
983afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= r6040_multicast_list,
984a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_change_mtu		= eth_change_mtu,
985a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
9862154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	.ndo_set_mac_address	= eth_mac_addr,
987a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_do_ioctl		= r6040_ioctl,
988a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_tx_timeout		= r6040_tx_timeout,
989a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER
990a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_poll_controller	= r6040_poll_controller,
991a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger#endif
992a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger};
993a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger
9943831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic void r6040_adjust_link(struct net_device *dev)
9953831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli{
9963831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
9973831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev = lp->phydev;
9983831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int status_changed = 0;
9993831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	void __iomem *ioaddr = lp->base;
10003831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10013831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	BUG_ON(!phydev);
10023831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10033831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (lp->old_link != phydev->link) {
10043831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		status_changed = 1;
10053831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->old_link = phydev->link;
10063831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10073831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10083831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	/* reflect duplex change */
10093831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (phydev->link && (lp->old_duplex != phydev->duplex)) {
10104e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli		lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0);
10113831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		iowrite16(lp->mcr0, ioaddr);
10123831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10133831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		status_changed = 1;
10143831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->old_duplex = phydev->duplex;
10153831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10163831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10173831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (status_changed) {
10183831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		pr_info("%s: link %s", dev->name, phydev->link ?
10193831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			"UP" : "DOWN");
10203831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		if (phydev->link)
10213831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			pr_cont(" - %d/%s", phydev->speed,
10223831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			DUPLEX_FULL == phydev->duplex ? "full" : "half");
10233831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		pr_cont("\n");
10243831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10253831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
10263831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10273831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mii_probe(struct net_device *dev)
10283831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli{
10293831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
10303831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev = NULL;
10313831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10323831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev = phy_find_first(lp->mii_bus);
10333831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!phydev) {
10343831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&lp->pdev->dev, "no PHY found\n");
10353831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		return -ENODEV;
10363831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10373831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10383831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
10393831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				0, PHY_INTERFACE_MODE_MII);
10403831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10413831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (IS_ERR(phydev)) {
10423831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
10433831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		return PTR_ERR(phydev);
10443831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10453831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10463831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	/* mask with MAC supported features */
10473831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev->supported &= (SUPPORTED_10baseT_Half
10483831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_10baseT_Full
10493831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_100baseT_Half
10503831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_100baseT_Full
10513831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_Autoneg
10523831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_MII
10533831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_TP);
10543831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10553831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev->advertising = phydev->supported;
10563831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->phydev = phydev;
10573831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->old_link = 0;
10583831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->old_duplex = -1;
10593831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10603831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
10613831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		"(mii_bus:phy_addr=%s)\n",
10623831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		phydev->drv->name, dev_name(&phydev->dev));
10633831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10643831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return 0;
10653831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
10663831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int __devinit r6040_init_one(struct pci_dev *pdev,
10687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang					 const struct pci_device_id *ent)
10697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
10707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev;
10717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp;
10727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr;
10737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int err, io_size = R6040_IO_SIZE;
10747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	static int card_idx = -1;
10757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int bar = 0;
10767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
10773831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int i;
10787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10792154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	pr_info("%s\n", version);
10807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	err = pci_enable_device(pdev);
10827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (err)
1083b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
10847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* this should always be supported */
1086284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
1087b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
10887d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "32-bit PCI DMA addresses"
10897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang				"not supported by the card\n");
1090b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
10917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
1092284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
1093b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
10947d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "32-bit PCI DMA addresses"
1095092427be8cef341c957a93ec2469890501a09bffJeff Garzik				"not supported by the card\n");
1096b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
1097092427be8cef341c957a93ec2469890501a09bffJeff Garzik	}
10987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* IO Size check */
11006f5bec195839dba3ca0ab8a7a53861e679109c0bMichael Opdenacker	if (pci_resource_len(pdev, bar) < io_size) {
11017d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
1102b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -EIO;
1103b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
11047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_set_master(pdev);
11077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev = alloc_etherdev(sizeof(struct r6040_private));
11097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!dev) {
1110b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -ENOMEM;
1111b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
11127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	SET_NETDEV_DEV(dev, &pdev->dev);
11147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp = netdev_priv(dev);
11157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1116b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	err = pci_request_regions(pdev, DRV_NAME);
1117b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli
1118b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
11197d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Failed to request PCI regions\n");
1120b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out_free_dev;
11217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	ioaddr = pci_iomap(pdev, bar, io_size);
11247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!ioaddr) {
11257d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "ioremap failed for device\n");
1126b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -EIO;
1127b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out_free_res;
11287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
112984314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli	/* If PHY status change register is still set to zero it means the
113084314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli	 * bootloader didn't initialize it */
113184314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli	if (ioread16(ioaddr + PHY_CC) == 0)
113284314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli		iowrite16(0x9f07, ioaddr + PHY_CC);
11337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Init system & device */
11357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->base = ioaddr;
11367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->irq = pdev->irq;
11377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_init(&lp->lock);
11397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_set_drvdata(pdev, dev);
11407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set MAC address */
11427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	card_idx++;
11437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *)dev->dev_addr;
11457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[0] = ioread16(ioaddr + MID_0L);
11467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[1] = ioread16(ioaddr + MID_0M);
11477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[2] = ioread16(ioaddr + MID_0H);
11487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11491d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli	/* Some bootloader/BIOSes do not initialize
11501d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli	 * MAC address, warn about that */
11519f1136182f732f6e847fc43bd88b579739d5c211Florian Fainelli	if (!(adrp[0] || adrp[1] || adrp[2])) {
11522154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		netdev_warn(dev, "MAC address not initialized, "
11532154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					"generating random\n");
1154f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka		eth_hw_addr_random(dev);
11559f1136182f732f6e847fc43bd88b579739d5c211Florian Fainelli	}
11561d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli
11577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Link new device into r6040_root_dev */
11587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->pdev = pdev;
1159129cf9a7028fc50b226b8021bc0b76fb38efa81dFlorian Fainelli	lp->dev = dev;
11607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Init RDC private data */
116277e1e438cbb1b8f9b7a3bb2d4f0264d1dd952d75Cesar Eduardo Barros	lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN;
11637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* The RDC-specific entries in the device structure. */
1165a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	dev->netdev_ops = &r6040_netdev_ops;
11667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->ethtool_ops = &netdev_ethtool_ops;
11677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->watchdog_timeo = TX_TIMEOUT;
1168a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger
11697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
11703831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
11713831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus = mdiobus_alloc();
11723831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->mii_bus) {
11733831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
11749c86c0f4ba49b39f909d7f18731b91e563e07065Axel Lin		err = -ENOMEM;
1175e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly		goto err_out_unmap;
1176e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly	}
1177e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly
11783831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->priv = dev;
11793831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->read = r6040_mdiobus_read;
11803831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->write = r6040_mdiobus_write;
11813831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->reset = r6040_mdiobus_reset;
11823831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->name = "r6040_eth_mii";
1183817380e1d05534880a99d84a47cc5a2df111030dFlorian Fainelli	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
1184817380e1d05534880a99d84a47cc5a2df111030dFlorian Fainelli		dev_name(&pdev->dev), card_idx);
11853831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
11863831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->mii_bus->irq) {
11873831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
11889c86c0f4ba49b39f909d7f18731b91e563e07065Axel Lin		err = -ENOMEM;
11893831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio;
11903831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
11913831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
11923831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	for (i = 0; i < PHY_MAX_ADDR; i++)
11933831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->mii_bus->irq[i] = PHY_POLL;
11943831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
11953831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	err = mdiobus_register(lp->mii_bus);
11963831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (err) {
11973831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "failed to register MII bus\n");
11983831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_irq;
11993831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
12003831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
12013831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	err = r6040_mii_probe(dev);
12023831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (err) {
12033831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "failed to probe MII bus\n");
12043831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_unregister;
12053831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
12063831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
12077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Register net device. After this dev->name assign */
12087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	err = register_netdev(dev);
12097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (err) {
12107d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Failed to register net device\n");
12113831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_unregister;
12127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
12137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
12147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12153831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio_unregister:
12163831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_unregister(lp->mii_bus);
12173831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio_irq:
12183831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	kfree(lp->mii_bus->irq);
12193831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio:
12203831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_free(lp->mii_bus);
1221b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_unmap:
1222b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	pci_iounmap(pdev, ioaddr);
1223b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_free_res:
12247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_release_regions(pdev);
1225b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_free_dev:
12267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	free_netdev(dev);
1227b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out:
12287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return err;
12297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void __devexit r6040_remove_one(struct pci_dev *pdev)
12327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
12337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = pci_get_drvdata(pdev);
12343831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
12357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unregister_netdev(dev);
12373831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_unregister(lp->mii_bus);
12383831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	kfree(lp->mii_bus->irq);
12393831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_free(lp->mii_bus);
12407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_release_regions(pdev);
12417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	free_netdev(dev);
12427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_disable_device(pdev);
12437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_set_drvdata(pdev, NULL);
12447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1247a3aa18842a5303fc28fcc4d57dbd16618bd830a0Alexey Dobriyanstatic DEFINE_PCI_DEVICE_TABLE(r6040_pci_tbl) = {
12485ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
12495ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	{ 0 }
12507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
12517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
12527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic struct pci_driver r6040_driver = {
12545ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	.name		= DRV_NAME,
12557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.id_table	= r6040_pci_tbl,
12567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.probe		= r6040_init_one,
12577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.remove		= __devexit_p(r6040_remove_one),
12587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
12597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int __init r6040_init(void)
12627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
12637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return pci_register_driver(&r6040_driver);
12647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void __exit r6040_cleanup(void)
12687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
12697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_unregister_driver(&r6040_driver);
12707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangmodule_init(r6040_init);
12737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangmodule_exit(r6040_cleanup);
1274