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>
71caf09df78a1b40604f200f419b08819e139b858Florian Fainelli * Copyright (C) 2007-2012 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/delay.h>
387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/mii.h>
397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/ethtool.h>
407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/crc32.h>
417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <linux/spinlock.h>
42092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/bitops.h>
43092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/io.h>
44092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/irq.h>
45092427be8cef341c957a93ec2469890501a09bffJeff Garzik#include <linux/uaccess.h>
463831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli#include <linux/phy.h>
477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#include <asm/processor.h>
497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define DRV_NAME	"r6040"
515bdc4f5de1345c221f5b51d73fafe3e5de718a54Florian Fainelli#define DRV_VERSION	"0.28"
525bdc4f5de1345c221f5b51d73fafe3e5de718a54Florian Fainelli#define DRV_RELDATE	"07Oct2011"
537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Time in jiffies before concluding the transmitter is hung. */
555ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu#define TX_TIMEOUT	(6000 * HZ / 1000)
567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* RDC MAC I/O Size */
587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define R6040_IO_SIZE	256
597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* MAX RDC MAC */
617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAX_MAC		2
627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* MAC registers */
647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MCR0		0x00	/* Control register 0 */
654e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_RCVEN	0x0002	/* Receive enable */
66c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin#define  MCR0_PROMISC	0x0020	/* Promiscuous mode */
67c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin#define  MCR0_HASH_EN	0x0100	/* Enable multicast hash table function */
684e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_XMTEN	0x1000	/* Transmission enable */
694e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli#define  MCR0_FD	0x8000	/* Full/Half duplex */
707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MCR1		0x04	/* Control register 1 */
717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MAC_RST	0x0001	/* Reset the MAC */
727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MBCR		0x08	/* Bus control */
737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MT_ICR		0x0C	/* TX interrupt control */
747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_ICR		0x10	/* RX interrupt control */
757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTPR		0x14	/* TX poll command register */
76940ff7ed0e2af6410078addead6ca245f55b72daFlorian Fainelli#define  TM2TX		0x0001	/* Trigger MAC to transmit */
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 */
808dd87a26c7db72ce3124eb20bdbe7394723043feFlorian Fainelli#define  TX_FIFO_UNDR	0x0200	/* TX FIFO under-run */
818dd87a26c7db72ce3124eb20bdbe7394723043feFlorian Fainelli#define	 TX_EXCEEDC	0x2000	/* Transmit exceed collision */
828dd87a26c7db72ce3124eb20bdbe7394723043feFlorian Fainelli#define  TX_LATEC	0x4000	/* Transmit late collision */
837a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMDIO		0x20	/* MDIO control register */
847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MDIO_WRITE	0x4000	/* MDIO write */
857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MDIO_READ	0x2000	/* MDIO read */
867a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMRD		0x24	/* MDIO read data register */
877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MMWD		0x28	/* MDIO write data register */
887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTD_SA0		0x2C	/* TX descriptor start address 0 */
897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MTD_SA1		0x30	/* TX descriptor start address 1 */
907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MRD_SA0		0x34	/* RX descriptor start address 0 */
917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MRD_SA1		0x38	/* RX descriptor start address 1 */
927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MISR		0x3C	/* Status register */
937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MIER		0x40	/* INT enable register */
947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define  MSK_INT	0x0000	/* Mask off interrupts */
953d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_FINISH	0x0001  /* RX finished */
963d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_NO_DESC	0x0002  /* No RX descriptor available */
973d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_FIFO_FULL	0x0004  /* RX FIFO full */
983d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  RX_EARLY	0x0008  /* RX early */
993d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  TX_FINISH	0x0010  /* TX finished */
1003d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  TX_EARLY	0x0080  /* TX early */
1013d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  EVENT_OVRFL	0x0100  /* Event counter overflow */
1023d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli#define  LINK_CHANGED	0x0200  /* PHY link changed */
1037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CISR		0x44	/* Event counter INT status */
1047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CIER		0x48	/* Event counter INT enable  */
1057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MR_CNT		0x50	/* Successfully received packet counter */
1067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT0		0x52	/* Event counter 0 */
1077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT1		0x54	/* Event counter 1 */
1087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT2		0x56	/* Event counter 2 */
1097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT3		0x58	/* Event counter 3 */
1107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MT_CNT		0x5A	/* Successfully transmit packet counter */
1117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define ME_CNT4		0x5C	/* Event counter 4 */
1127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MP_CNT		0x5E	/* Pause frame counter register */
1137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR0		0x60	/* Hash table 0 */
1147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR1		0x62	/* Hash table 1 */
1157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR2		0x64	/* Hash table 2 */
1167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAR3		0x66	/* Hash table 3 */
1177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0L		0x68	/* Multicast address MID0 Low */
1187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0M		0x6A	/* Multicast address MID0 Medium */
1197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_0H		0x6C	/* Multicast address MID0 High */
1207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1L		0x70	/* MID1 Low */
1217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1M		0x72	/* MID1 Medium */
1227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_1H		0x74	/* MID1 High */
1237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2L		0x78	/* MID2 Low */
1247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2M		0x7A	/* MID2 Medium */
1257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_2H		0x7C	/* MID2 High */
1267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3L		0x80	/* MID3 Low */
1277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3M		0x82	/* MID3 Medium */
1287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MID_3H		0x84	/* MID3 High */
1297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define PHY_CC		0x88	/* PHY status change configuration register */
13031171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli#define  SCEN		0x8000	/* PHY status change enable */
13131171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli#define  PHYAD_SHIFT	8	/* PHY address shift */
13231171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli#define  TMRDIV_SHIFT	0	/* Timer divider shift */
1337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define PHY_ST		0x8A	/* PHY status register */
1347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAC_SM		0xAC	/* MAC status machine */
135e1477637967d0d8db3083bacb241c796c3c4f23bFlorian Fainelli#define  MAC_SM_RST	0x0002	/* MAC status machine reset */
1367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAC_ID		0xBE	/* Identifier register */
1377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define TX_DCNT		0x80	/* TX descriptor count */
1397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define RX_DCNT		0x80	/* RX descriptor count */
1407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MAX_BUF_SIZE	0x600
1416c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu#define RX_DESC_SIZE	(RX_DCNT * sizeof(struct r6040_descriptor))
1426c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu#define TX_DESC_SIZE	(TX_DCNT * sizeof(struct r6040_descriptor))
1437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#define MBCR_DEFAULT	0x012A	/* MAC Bus Control Register */
1443bcf8229a8c49769e48d3e0bd1e20d8e003f8106Florian Fainelli#define MCAST_MAX	3	/* Max number multicast addresses to filter */
1457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1462fa15bbdd8a1ac096819df29db8d69b063752beeFlorian Fainelli#define MAC_DEF_TIMEOUT	2048	/* Default MAC read/write operation timeout */
1472fa15bbdd8a1ac096819df29db8d69b063752beeFlorian Fainelli
14832f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli/* Descriptor status */
14932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_OWNER_MAC	0x8000	/* MAC is the owner of this descriptor */
15032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_OK	0x4000	/* RX was successful */
15132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR	0x0800	/* RX PHY error */
15232f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_DRI	0x0400	/* RX dribble packet */
15332f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_BUF	0x0200	/* RX length exceeds buffer size */
15432f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_LONG	0x0100	/* RX length > maximum packet length */
15532f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_RUNT	0x0080	/* RX packet length < 64 byte */
15632f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_ERR_CRC	0x0040	/* RX CRC error */
15732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_BCAST	0x0020	/* RX broadcast (no error) */
15832f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MCAST	0x0010	/* RX multicast (no error) */
15932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MCH_HIT	0x0008	/* RX multicast hit in hash table (no error) */
16032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_MIDH_HIT	0x0004	/* RX MID table hit (no error) */
16132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli#define DSC_RX_IDX_MID_MASK 3	/* RX mask for the index of matched MIDx */
16232f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli
1637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>,"
1647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	"Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>,"
1657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	"Florian Fainelli <florian@openwrt.org>");
1667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_LICENSE("GPL");
1677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver");
168bc4de26040d3bdc170aaa47044adf9d318a06772Florian FainelliMODULE_VERSION(DRV_VERSION " " DRV_RELDATE);
1697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1703d25434816356e8d1e3167c5f7a56d3d81aeb239Florian Fainelli/* RX and TX interrupts that we handle */
171e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define RX_INTS			(RX_FIFO_FULL | RX_NO_DESC | RX_FINISH)
172e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define TX_INTS			(TX_FINISH)
173e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli#define INT_MASK		(RX_INTS | TX_INTS)
1747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstruct r6040_descriptor {
1767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16	status, len;		/* 0-3 */
1777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	__le32	buf;			/* 4-7 */
1787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	__le32	ndesc;			/* 8-B */
1797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u32	rev1;			/* C-F */
1807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	char	*vbufp;			/* 10-13 */
1817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *vndescp;	/* 14-17 */
1827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct sk_buff *skb_ptr;	/* 18-1B */
1837a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u32	rev2;			/* 1C-1F */
184853d5dc95b41babb7001934becad9c944738d8e3Florian Fainelli} __aligned(32);
1857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1867a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstruct r6040_private {
1877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spinlock_t lock;		/* driver lock */
1887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct pci_dev *pdev;
1897a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *rx_insert_ptr;
1907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *rx_remove_ptr;
1917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *tx_insert_ptr;
1927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *tx_remove_ptr;
1936c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	struct r6040_descriptor *rx_ring;
1946c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	struct r6040_descriptor *tx_ring;
1956c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	dma_addr_t rx_ring_dma;
1966c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	dma_addr_t tx_ring_dma;
19749f26720d46476384a090c4e281be73e5de4f1e1Florian Fainelli	u16	tx_free_desc;
1980db0cfcc4ddff3226c8c721760b6a4eaf0e5229aFlorian Fainelli	u16	mcr0;
1997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev;
2003831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct mii_bus *mii_bus;
2017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct napi_struct napi;
2027a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *base;
2033831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev;
2043831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int old_link;
2053831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int old_duplex;
2067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
2077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
208f1e242648bce83ec67f8bc047e1ad1ade7b85725Bill Pembertonstatic char version[] = DRV_NAME
2097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	": RDC R6040 NAPI net driver,"
2109a48ce84004eb61940850c7066af5d222a5f81c9Florian Fainelli	"version "DRV_VERSION " (" DRV_RELDATE ")";
2117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Read a word data from PHY Chip */
213c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainellistatic int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
2147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2152fa15bbdd8a1ac096819df29db8d69b063752beeFlorian Fainelli	int limit = MAC_DEF_TIMEOUT;
2167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 cmd;
2177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO);
2197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Wait for the read bit to be cleared */
2207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (limit--) {
2217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		cmd = ioread16(ioaddr + MMDIO);
22211e5e8f5d14a1229706576184d2cf4c4556ed94cJoe Chou		if (!(cmd & MDIO_READ))
2237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			break;
2244f8d9f3ce0e52adf2cb4e0661f06ef8cfdc97cfeFlorian Fainelli		udelay(1);
2257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
2267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
22709e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli	if (limit < 0)
22809e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli		return -ETIMEDOUT;
22909e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli
2307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return ioread16(ioaddr + MMRD);
2317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Write a word data from PHY Chip */
23409e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainellistatic int r6040_phy_write(void __iomem *ioaddr,
2352154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					int phy_addr, int reg, u16 val)
2367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2372fa15bbdd8a1ac096819df29db8d69b063752beeFlorian Fainelli	int limit = MAC_DEF_TIMEOUT;
2387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 cmd;
2397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(val, ioaddr + MMWD);
2417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Write the command to the MDIO bus */
2427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO);
2437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Wait for the write bit to be cleared */
2447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (limit--) {
2457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		cmd = ioread16(ioaddr + MMDIO);
24611e5e8f5d14a1229706576184d2cf4c4556ed94cJoe Chou		if (!(cmd & MDIO_WRITE))
2477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			break;
2484f8d9f3ce0e52adf2cb4e0661f06ef8cfdc97cfeFlorian Fainelli		udelay(1);
2497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
25009e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli
25109e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli	return (limit < 0) ? -ETIMEDOUT : 0;
2527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2543831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
2557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2563831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct net_device *dev = bus->priv;
2577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
2587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
2597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2603831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return r6040_phy_read(ioaddr, phy_addr, reg);
2617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
2627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
2633831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
2643831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli						int reg, u16 value)
2657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
2663831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct net_device *dev = bus->priv;
2677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
2687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
2697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
27009e7fae97702f9fcc875b56f3b687e88408b32e5Florian Fainelli	return r6040_phy_write(ioaddr, phy_addr, reg, value);
2713831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
2723831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
273b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_free_txbufs(struct net_device *dev)
274b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
275b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
276b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	int i;
277b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
278b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	for (i = 0; i < TX_DCNT; i++) {
279b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		if (lp->tx_insert_ptr->skb_ptr) {
280ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro			pci_unmap_single(lp->pdev,
281ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro				le32_to_cpu(lp->tx_insert_ptr->buf),
282b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				MAX_BUF_SIZE, PCI_DMA_TODEVICE);
283b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			dev_kfree_skb(lp->tx_insert_ptr->skb_ptr);
2843b060be0582373be3c380629d7a6de5f06a311edFlorian Fainelli			lp->tx_insert_ptr->skb_ptr = NULL;
285b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		}
286b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp;
287b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
288b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
289b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
290b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_free_rxbufs(struct net_device *dev)
291b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
292b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
293b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	int i;
294b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
295b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	for (i = 0; i < RX_DCNT; i++) {
296b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		if (lp->rx_insert_ptr->skb_ptr) {
297ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro			pci_unmap_single(lp->pdev,
298ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro				le32_to_cpu(lp->rx_insert_ptr->buf),
299b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
300b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			dev_kfree_skb(lp->rx_insert_ptr->skb_ptr);
301b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli			lp->rx_insert_ptr->skb_ptr = NULL;
302b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		}
303b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp;
304b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
305b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
306b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
307b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainellistatic void r6040_init_ring_desc(struct r6040_descriptor *desc_ring,
308b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli				 dma_addr_t desc_dma, int size)
309b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
310b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_descriptor *desc = desc_ring;
311b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	dma_addr_t mapping = desc_dma;
312b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
313b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	while (size-- > 0) {
3143f6602ad56dc538a846367bd6a05ac7ac4d3e641Julia Lawall		mapping += sizeof(*desc);
315b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc->ndesc = cpu_to_le32(mapping);
316b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc->vndescp = desc + 1;
317b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli		desc++;
318b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	}
319b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc--;
320b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc->ndesc = cpu_to_le32(desc_dma);
321b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	desc->vndescp = desc_ring;
322b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
323b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3243d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic void r6040_init_txbufs(struct net_device *dev)
325b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
326b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
327b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
328b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->tx_free_desc = TX_DCNT;
329b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
330b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring;
331b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT);
332b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
333b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3343d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic int r6040_alloc_rxbufs(struct net_device *dev)
335b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli{
336b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
3373d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	struct r6040_descriptor *desc;
3383d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	struct sk_buff *skb;
3393d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	int rc;
340b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
341b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring;
342b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT);
343b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
3443d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	/* Allocate skbs for the rx descriptors */
3453d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	desc = lp->rx_ring;
3463d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	do {
3473d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
3483d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		if (!skb) {
3493d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli			rc = -ENOMEM;
3503d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli			goto err_exit;
3513d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		}
3523d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc->skb_ptr = skb;
3533d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc->buf = cpu_to_le32(pci_map_single(lp->pdev,
3542154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					desc->skb_ptr->data,
3552154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
35632f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		desc->status = DSC_OWNER_MAC;
3573d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		desc = desc->vndescp;
3583d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	} while (desc != lp->rx_ring);
3593d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
3603d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return 0;
3613d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
3623d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellierr_exit:
3633d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	/* Deallocate all previously allocated skbs */
3643d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	r6040_free_rxbufs(dev);
3653d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return rc;
366fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli}
367fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
36890f750a81a29587846e907d2c8ed60a0586ce632Florian Fainellistatic void r6040_reset_mac(struct r6040_private *lp)
369fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli{
370fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	void __iomem *ioaddr = lp->base;
3712fa15bbdd8a1ac096819df29db8d69b063752beeFlorian Fainelli	int limit = MAC_DEF_TIMEOUT;
372fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	u16 cmd;
373fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
374fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MAC_RST, ioaddr + MCR1);
375fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	while (limit--) {
376fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli		cmd = ioread16(ioaddr + MCR1);
37758dbc691e6ca6689402424db60f4a54745a38c67Florian Fainelli		if (cmd & MAC_RST)
378fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli			break;
379fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	}
38090f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli
381fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Reset internal state machine */
382e1477637967d0d8db3083bacb241c796c3c4f23bFlorian Fainelli	iowrite16(MAC_SM_RST, ioaddr + MAC_SM);
383fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(0, ioaddr + MAC_SM);
384c1d69937ee5818bcde3bed8c012c9f07d60e492eFlorian Fainelli	mdelay(5);
38590f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli}
38690f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli
38790f750a81a29587846e907d2c8ed60a0586ce632Florian Fainellistatic void r6040_init_mac_regs(struct net_device *dev)
38890f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli{
38990f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	struct r6040_private *lp = netdev_priv(dev);
39090f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	void __iomem *ioaddr = lp->base;
39190f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli
39290f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	/* Mask Off Interrupt */
39390f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	iowrite16(MSK_INT, ioaddr + MIER);
39490f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli
39590f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	/* Reset RDC MAC */
39690f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	r6040_reset_mac(lp);
397fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
398fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* MAC Bus Control Register */
399fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MBCR_DEFAULT, ioaddr + MBCR);
400fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
401fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Buffer Size Register */
402fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR);
403fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
404fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Write TX ring start address */
405fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0);
406fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1);
407b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli
408fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Write RX ring start address */
409b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0);
410b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1);
411fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
412fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Set interrupt waiting time and packet numbers */
41331718dedf62fd62e807001138ab5ac76e9b11064Florian Fainelli	iowrite16(0, ioaddr + MT_ICR);
41431718dedf62fd62e807001138ab5ac76e9b11064Florian Fainelli	iowrite16(0, ioaddr + MR_ICR);
415fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
416fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Enable interrupts */
417fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	iowrite16(INT_MASK, ioaddr + MIER);
418fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
419fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Enable TX and RX */
4204e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli	iowrite16(lp->mcr0 | MCR0_RCVEN, ioaddr);
421fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
422fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Let TX poll the descriptors
423fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	 * we may got called by r6040_tx_timeout which has left
424fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	 * some unsent tx buffers */
425940ff7ed0e2af6410078addead6ca245f55b72daFlorian Fainelli	iowrite16(TM2TX, ioaddr + MTPR);
426b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli}
4277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
428106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainellistatic void r6040_tx_timeout(struct net_device *dev)
429106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli{
430106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	struct r6040_private *priv = netdev_priv(dev);
431106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	void __iomem *ioaddr = priv->base;
432106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
4337d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli	netdev_warn(dev, "transmit timed out, int enable %4.4x "
4343831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		"status %4.4x\n",
4357d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		ioread16(ioaddr + MIER),
4363831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		ioread16(ioaddr + MISR));
437106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
438106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli	dev->stats.tx_errors++;
439fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli
440fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Reset MAC and re-init all registers */
441fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	r6040_init_mac_regs(dev);
442106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli}
443106adf3c84d081776a1d1fbb8a047cad12af2bb9Florian Fainelli
4447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic struct net_device_stats *r6040_get_stats(struct net_device *dev)
4457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
4477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
4487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
4497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irqsave(&priv->lock, flags);
451d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1);
452d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	dev->stats.multicast += ioread8(ioaddr + ME_CNT0);
4537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irqrestore(&priv->lock, flags);
4547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
455d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli	return &dev->stats;
4567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
4577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Stop RDC MAC and Free the allocated resource */
4597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_down(struct net_device *dev)
4607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
4627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
4637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
4647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Stop MAC */
4667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MSK_INT, ioaddr + MIER);	/* Mask Off Interrupt */
46790f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli
46890f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	/* Reset RDC MAC */
46990f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	r6040_reset_mac(lp);
4707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Restore MAC Address to MIDx */
4727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *) dev->dev_addr;
4737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
4747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
4757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
47606e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli
47706e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli	phy_stop(lp->phydev);
4787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
4797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4805ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic int r6040_close(struct net_device *dev)
4817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
4827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
48358854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	struct pci_dev *pdev = lp->pdev;
4847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
4857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irq(&lp->lock);
486129cf9a7028fc50b226b8021bc0b76fb38efa81dFlorian Fainelli	napi_disable(&lp->napi);
4877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_stop_queue(dev);
4887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	r6040_down(dev);
48958854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
49058854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	free_irq(dev->irq, dev);
49158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
49258854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free RX buffer */
49358854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	r6040_free_rxbufs(dev);
49458854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
49558854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free TX buffer */
49658854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	r6040_free_txbufs(dev);
49758854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
4987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irq(&lp->lock);
4997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
50058854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	/* Free Descriptor memory */
50158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	if (lp->rx_ring) {
5022154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		pci_free_consistent(pdev,
5032154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli				RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
5045b5103ec2dba07a15861e81cb783dd0fbaed24edHannes Eder		lp->rx_ring = NULL;
50558854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	}
50658854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
50758854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	if (lp->tx_ring) {
5082154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		pci_free_consistent(pdev,
5092154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli				TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
5105b5103ec2dba07a15861e81cb783dd0fbaed24edHannes Eder		lp->tx_ring = NULL;
51158854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli	}
51258854c6b411e9e9f46b39bd7092022f639c41904Florian Fainelli
5137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
5147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
5177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
5187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
5197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5203831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->phydev)
5217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		return -EINVAL;
5223831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
5234cfa580e7eebb8694b875d2caff3b989ada2efacDavid S. Miller	return phy_mii_ioctl(lp->phydev, rq, cmd);
5247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_rx(struct net_device *dev, int limit)
5277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
5287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
5299ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	struct r6040_descriptor *descptr = priv->rx_remove_ptr;
5309ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	struct sk_buff *skb_ptr, *new_skb;
5319ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	int count = 0;
5327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 err;
5337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5349ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	/* Limit not reached and the descriptor belongs to the CPU */
53532f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli	while (count < limit && !(descptr->status & DSC_OWNER_MAC)) {
5369ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Read the descriptor status */
5379ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		err = descptr->status;
5389ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Global error status set */
53932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		if (err & DSC_RX_ERR) {
5409ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* RX dribble */
54132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_DRI)
5429ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_frame_errors++;
54325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi			/* Buffer length exceeded */
54432f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_BUF)
5459ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5469ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* Packet too long */
54732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_LONG)
5489ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5499ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* Packet < 64 bytes */
55032f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_RUNT)
5519ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_length_errors++;
5529ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			/* CRC error */
55332f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli			if (err & DSC_RX_ERR_CRC) {
5549ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				spin_lock(&priv->lock);
5559ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				dev->stats.rx_crc_errors++;
5569ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli				spin_unlock(&priv->lock);
5577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			}
5589ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			goto next_descr;
5599ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		}
5602154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5619ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Packet successfully received */
5629ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		new_skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
5639ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		if (!new_skb) {
5649ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			dev->stats.rx_dropped++;
5659ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli			goto next_descr;
5667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		}
5679ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr = descptr->skb_ptr;
5689ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr->dev = priv->dev;
5692154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5709ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Do not count the CRC */
5719ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_put(skb_ptr, descptr->len - 4);
5729ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
5739ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE);
5749ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev);
5752154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli
5769ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* Send to upper layer */
5779ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		netif_receive_skb(skb_ptr);
5789ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		dev->stats.rx_packets++;
5799ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		dev->stats.rx_bytes += descptr->len - 4;
5809ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli
5819ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* put new skb into descriptor */
5829ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr->skb_ptr = new_skb;
5839ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr->buf = cpu_to_le32(pci_map_single(priv->pdev,
5849ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli						descptr->skb_ptr->data,
5859ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli					MAX_BUF_SIZE, PCI_DMA_FROMDEVICE));
5869ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli
5879ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainellinext_descr:
5889ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		/* put the descriptor back to the MAC */
58932f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		descptr->status = DSC_OWNER_MAC;
5909ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		descptr = descptr->vndescp;
5919ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli		count++;
5927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
5939ca28dc4c75f018201e21b10e34b8161bcb0ffb2Florian Fainelli	priv->rx_remove_ptr = descptr;
5947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5957a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return count;
5967a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
5977a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
5987a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_tx(struct net_device *dev)
5997a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6007a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv = netdev_priv(dev);
6017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *descptr;
6027a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
6037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct sk_buff *skb_ptr;
6047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 err;
6057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock(&priv->lock);
6077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr = priv->tx_remove_ptr;
6087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	while (priv->tx_free_desc < TX_DCNT) {
6097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Check for errors */
6107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		err = ioread16(ioaddr + MLSR);
6117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6128dd87a26c7db72ce3124eb20bdbe7394723043feFlorian Fainelli		if (err & TX_FIFO_UNDR)
6133440ecc4538b7e833b979af9caec613c984b2302Florian Fainelli			dev->stats.tx_fifo_errors++;
6148dd87a26c7db72ce3124eb20bdbe7394723043feFlorian Fainelli		if (err & (TX_EXCEEDC | TX_LATEC))
615d248fd77902fcf33b0bc49ab521930877d94890fFlorian Fainelli			dev->stats.tx_carrier_errors++;
6167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
61732f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli		if (descptr->status & DSC_OWNER_MAC)
618ec6d2d453a932fd50c5fd95d5aac633b4e5f241dFlorian Fainelli			break; /* Not complete */
6197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		skb_ptr = descptr->skb_ptr;
620ed773b4ab1387a25b3be027d45c94daae3c8a607Al Viro		pci_unmap_single(priv->pdev, le32_to_cpu(descptr->buf),
6217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			skb_ptr->len, PCI_DMA_TODEVICE);
6227a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Free buffer */
6237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		dev_kfree_skb_irq(skb_ptr);
6247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr->skb_ptr = NULL;
6257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* To next descriptor */
6267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr = descptr->vndescp;
6277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		priv->tx_free_desc++;
6287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	priv->tx_remove_ptr = descptr;
6307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (priv->tx_free_desc)
6327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		netif_wake_queue(dev);
6337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock(&priv->lock);
6347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int r6040_poll(struct napi_struct *napi, int budget)
6377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *priv =
6397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		container_of(napi, struct r6040_private, napi);
6407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = priv->dev;
6417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = priv->base;
6427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int work_done;
6437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	work_done = r6040_rx(dev, budget);
6457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (work_done < budget) {
647288379f050284087578b77e04f040b57db3db3f8Ben Hutchings		napi_complete(napi);
6487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		/* Enable RX interrupt */
649e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER);
6507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return work_done;
6527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
6537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* The RDC interrupt handler. */
6557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic irqreturn_t r6040_interrupt(int irq, void *dev_id)
6567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
6577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = dev_id;
6587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
6597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
6603e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	u16 misr, status;
6617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6623e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	/* Save MIER */
6633e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	misr = ioread16(ioaddr + MIER);
6647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Mask off RDC MAC interrupt */
6657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(MSK_INT, ioaddr + MIER);
6667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Read MISR status and clear */
6677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	status = ioread16(ioaddr + MISR);
6687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
66935976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli	if (status == 0x0000 || status == 0xffff) {
67035976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli		/* Restore RDC MAC interrupt */
67135976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli		iowrite16(misr, ioaddr + MIER);
6727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		return IRQ_NONE;
67335976d4d557c5017c2180a083e8bd970cf73f3d5Florian Fainelli	}
6747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* RX interrupt request */
676e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli	if (status & RX_INTS) {
677e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		if (status & RX_NO_DESC) {
678e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			/* RX descriptor unavailable */
679e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_dropped++;
680e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_missed_errors++;
681e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		}
682e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli		if (status & RX_FIFO_FULL)
683e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli			dev->stats.rx_fifo_errors++;
684e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli
6850d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier		if (likely(napi_schedule_prep(&lp->napi))) {
6860d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			/* Mask off RX interrupt */
6870d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			misr &= ~RX_INTS;
6880d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier			__napi_schedule(&lp->napi);
6890d9b6e738a22244d38def847a24e5ee6fcedd898Michael Thalmeier		}
6907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
6917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* TX interrupt request */
693e24ddf3aa8a2c4c14df1136e762c315c436488e7Florian Fainelli	if (status & TX_INTS)
6947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		r6040_tx(dev);
6957a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
6963e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	/* Restore RDC MAC interrupt */
6973e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou	iowrite16(misr, ioaddr + MIER);
6983e7c469f07ff14cbf9a814739e1fc99a863e0943Joe Chou
699ec6d2d453a932fd50c5fd95d5aac633b4e5f241dFlorian Fainelli	return IRQ_HANDLED;
7007a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7027a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#ifdef CONFIG_NET_POLL_CONTROLLER
7037a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_poll_controller(struct net_device *dev)
7047a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7057a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	disable_irq(dev->irq);
7065ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	r6040_interrupt(dev->irq, dev);
7077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	enable_irq(dev->irq);
7087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang#endif
7107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Init RDC MAC */
7123d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainellistatic int r6040_up(struct net_device *dev)
7137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
7157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
7163d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	int ret;
7177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
718b4f1255d6839bd970d5ff20a9c3d73f73c9adaa3Florian Fainelli	/* Initialise and alloc RX/TX buffers */
7193d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	r6040_init_txbufs(dev);
7203d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	ret = r6040_alloc_rxbufs(dev);
7213d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	if (ret)
7223d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli		return ret;
7237a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* improve performance (by RDC guys) */
7252154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	r6040_phy_write(ioaddr, 30, 17,
7262154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli			(r6040_phy_read(ioaddr, 30, 17) | 0x4000));
7272154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	r6040_phy_write(ioaddr, 30, 17,
7282154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli			~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
729c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainelli	r6040_phy_write(ioaddr, 0, 19, 0x0000);
730c6e69bb92ed6e22a0931e29daff6539f2bac29b9Florian Fainelli	r6040_phy_write(ioaddr, 0, 30, 0x01F0);
7317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
732fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	/* Initialize all MAC registers */
733fec3a23be0daceeb0695f8296aea07ea1ad073d8Florian Fainelli	r6040_init_mac_regs(dev);
7343d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli
73506e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli	phy_start(lp->phydev);
73606e92c33999fd66128c2256b0461455633c3d53cFlorian Fainelli
7373d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	return 0;
7387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang/* Read/set MAC address routines */
7427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void r6040_mac_address(struct net_device *dev)
7437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
7457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
7467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
7477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
74848529680dc59061eaa13ea3b1047401612b79600Florian Fainelli	/* Reset MAC */
74990f750a81a29587846e907d2c8ed60a0586ce632Florian Fainelli	r6040_reset_mac(lp);
7507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Restore MAC Address */
7527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *) dev->dev_addr;
7537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
7547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
7557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
7567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
7577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7585ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic int r6040_open(struct net_device *dev)
7597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
7605ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	struct r6040_private *lp = netdev_priv(dev);
7617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int ret;
7627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Request IRQ and Register interrupt handler */
76491dcbf36f77c3d563e844fe0ed52ae896654ca7cJulia Lawall	ret = request_irq(dev->irq, r6040_interrupt,
7657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		IRQF_SHARED, dev->name, dev);
7667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (ret)
767ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto out;
7687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set MAC address */
7707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	r6040_mac_address(dev);
7717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Allocate Descriptor memory */
7736c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	lp->rx_ring =
7746c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu		pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma);
775ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	if (!lp->rx_ring) {
776ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		ret = -ENOMEM;
777ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_irq;
778ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	}
7797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7806c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	lp->tx_ring =
7816c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu		pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma);
7826c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	if (!lp->tx_ring) {
783ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		ret = -ENOMEM;
784ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_rx_ring;
7856c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu	}
7866c3231035d7ec31b3830daebd4c742e0b7471661Francois Romieu
7873d4634193aa95a6d04a786fc12b190d0e4295685Florian Fainelli	ret = r6040_up(dev);
788ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	if (ret)
789ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov		goto err_free_tx_ring;
7907a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7917a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	napi_enable(&lp->napi);
7927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_start_queue(dev);
7937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
7947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
795ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov
796ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_tx_ring:
797ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	pci_free_consistent(lp->pdev, TX_DESC_SIZE, lp->tx_ring,
798ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov			lp->tx_ring_dma);
799ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_rx_ring:
800ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring,
801ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov			lp->rx_ring_dma);
802ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanoverr_free_irq:
803ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	free_irq(dev->irq, dev);
804ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanovout:
805ced1de4c9eeded664e5f1b21cfcb0fb70cc0cde3Denis Kirjanov	return ret;
8067a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
8077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
80861357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
80961357325f377889a1daffa14962d705dc814dd0eStephen Hemminger				    struct net_device *dev)
8107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
8117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
8127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_descriptor *descptr;
8137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
8147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
8157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Critical Section */
8177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_irqsave(&lp->lock, flags);
8187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* TX resource check */
8207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!lp->tx_free_desc) {
8217a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		spin_unlock_irqrestore(&lp->lock, flags);
822092427be8cef341c957a93ec2469890501a09bffJeff Garzik		netif_stop_queue(dev);
8237d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		netdev_err(dev, ": no tx descriptor\n");
82461357325f377889a1daffa14962d705dc814dd0eStephen Hemminger		return NETDEV_TX_BUSY;
8257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
8267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Statistic Counter */
8287a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->stats.tx_packets++;
8297a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->stats.tx_bytes += skb->len;
8307a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set TX descriptor & Transmit it */
8317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->tx_free_desc--;
8327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr = lp->tx_insert_ptr;
83331cf344caf444ca7411d89c8ac907d886eeab1a7Florian Fainelli	if (skb->len < ETH_ZLEN)
83431cf344caf444ca7411d89c8ac907d886eeab1a7Florian Fainelli		descptr->len = ETH_ZLEN;
8357a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	else
8367a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		descptr->len = skb->len;
8377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr->skb_ptr = skb;
8397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	descptr->buf = cpu_to_le32(pci_map_single(lp->pdev,
8407a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		skb->data, skb->len, PCI_DMA_TODEVICE));
84132f565df9ba451a24117db67003ed2ae21bab88cFlorian Fainelli	descptr->status = DSC_OWNER_MAC;
8422aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran
8432aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran	skb_tx_timestamp(skb);
8442aa8f4c9d0f88ae7eacac424d8816de225cfe2aaRichard Cochran
8457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Trigger the MAC to check the TX descriptor */
846940ff7ed0e2af6410078addead6ca245f55b72daFlorian Fainelli	iowrite16(TM2TX, ioaddr + MTPR);
8477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->tx_insert_ptr = descptr->vndescp;
8487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* If no tx resource, stop */
8507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!lp->tx_free_desc)
8517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		netif_stop_queue(dev);
8527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_unlock_irqrestore(&lp->lock, flags);
85461357325f377889a1daffa14962d705dc814dd0eStephen Hemminger
85561357325f377889a1daffa14962d705dc814dd0eStephen Hemminger	return NETDEV_TX_OK;
8567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
8577a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8585ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieustatic void r6040_multicast_list(struct net_device *dev)
8597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
8607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp = netdev_priv(dev);
8617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr = lp->base;
8627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unsigned long flags;
86322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
8647a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int i;
865c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	u16 *adrp;
866c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	u16 hash_table[4] = { 0 };
867c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
868c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	spin_lock_irqsave(&lp->lock, flags);
8697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
870c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Keep our MAC Address */
8717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *)dev->dev_addr;
8727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[0], ioaddr + MID_0L);
8737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[1], ioaddr + MID_0M);
8747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	iowrite16(adrp[2], ioaddr + MID_0H);
8757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
8767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Clear AMCP & PROM bits */
877c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	lp->mcr0 = ioread16(ioaddr + MCR0) & ~(MCR0_PROMISC | MCR0_HASH_EN);
8787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
879c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Promiscuous mode */
880c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	if (dev->flags & IFF_PROMISC)
881c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_PROMISC;
8827a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
883c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Enable multicast hash table function to
884c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	 * receive all multicast packets. */
885c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else if (dev->flags & IFF_ALLMULTI) {
886c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_HASH_EN;
8877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
888c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < MCAST_MAX ; i++) {
889c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
890c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
891c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
892c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
8937a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
894c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < 4; i++)
895c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			hash_table[i] = 0xffff;
896c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
897c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Use internal multicast address registers if the number of
898c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	 * multicast addresses is not greater than MCAST_MAX. */
899c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else if (netdev_mc_count(dev) <= MCAST_MAX) {
900c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		i = 0;
90122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		netdev_for_each_mc_addr(ha, dev) {
902c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			u16 *adrp = (u16 *) ha->addr;
903c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
904c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
905c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
906c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			i++;
907c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
908c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		while (i < MCAST_MAX) {
909c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
910c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
911c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
912c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			i++;
913c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
914c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
915c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Otherwise, Enable multicast hash table function. */
916c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	else {
917c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		u32 crc;
9187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
919c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		lp->mcr0 |= MCR0_HASH_EN;
920c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
921c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		for (i = 0; i < MCAST_MAX ; i++) {
922c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1L + 8 * i);
923c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1M + 8 * i);
924c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			iowrite16(0, ioaddr + MID_1H + 8 * i);
925c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		}
9267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
927c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		/* Build multicast hash table */
928c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin		netdev_for_each_mc_addr(ha, dev) {
929c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			u8 *addrs = ha->addr;
930c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
931c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			crc = ether_crc(ETH_ALEN, addrs);
9327a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			crc >>= 26;
933c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin			hash_table[crc >> 4] |= 1 << (crc & 0xf);
9347a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		}
935c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	}
936c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
937c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	iowrite16(lp->mcr0, ioaddr + MCR0);
938c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
939c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	/* Fill the MAC hash tables with their values */
940bbc13ab9d26f4ff675775dd7dc24d5cae17b85d5Florian Fainelli	if (lp->mcr0 & MCR0_HASH_EN) {
9417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[0], ioaddr + MAR0);
9427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[1], ioaddr + MAR1);
9437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[2], ioaddr + MAR2);
9447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang		iowrite16(hash_table[3], ioaddr + MAR3);
9457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
946c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin
947c60c9c71ade23351d9cd9d1ef96ad007eb4a15abShawn Lin	spin_unlock_irqrestore(&lp->lock, flags);
9487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic void netdev_get_drvinfo(struct net_device *dev,
9517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang			struct ethtool_drvinfo *info)
9527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9557826d43f2db45c9305a6e0ba165650e1a203f517Jiri Pirko	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
9567826d43f2db45c9305a6e0ba165650e1a203f517Jiri Pirko	strlcpy(info->version, DRV_VERSION, sizeof(info->version));
9577826d43f2db45c9305a6e0ba165650e1a203f517Jiri Pirko	strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
9587a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9597a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
9617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9643831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return  phy_ethtool_gset(rp->phydev, cmd);
9657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9677a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
9687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
9697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *rp = netdev_priv(dev);
9707a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
9713831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return phy_ethtool_sset(rp->phydev, cmd);
9727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
9737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
974a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemmingerstatic const struct ethtool_ops netdev_ethtool_ops = {
9757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.get_drvinfo		= netdev_get_drvinfo,
9767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.get_settings		= netdev_get_settings,
9777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.set_settings		= netdev_set_settings,
9783831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	.get_link		= ethtool_op_get_link,
979d88e102d0ec43f9bd7c529f46c2f9c4d91ef24b0Richard Cochran	.get_ts_info		= ethtool_op_get_ts_info,
9807a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
9817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
982a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemmingerstatic const struct net_device_ops r6040_netdev_ops = {
983a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_open		= r6040_open,
984a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_stop		= r6040_close,
985a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_start_xmit		= r6040_start_xmit,
986a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_get_stats		= r6040_get_stats,
987afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= r6040_multicast_list,
988a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_change_mtu		= eth_change_mtu,
989a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_validate_addr	= eth_validate_addr,
9902154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	.ndo_set_mac_address	= eth_mac_addr,
991a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_do_ioctl		= r6040_ioctl,
992a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_tx_timeout		= r6040_tx_timeout,
993a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER
994a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	.ndo_poll_controller	= r6040_poll_controller,
995a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger#endif
996a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger};
997a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger
9983831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic void r6040_adjust_link(struct net_device *dev)
9993831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli{
10003831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
10013831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev = lp->phydev;
10023831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int status_changed = 0;
10033831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	void __iomem *ioaddr = lp->base;
10043831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10053831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	BUG_ON(!phydev);
10063831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10073831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (lp->old_link != phydev->link) {
10083831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		status_changed = 1;
10093831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->old_link = phydev->link;
10103831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10113831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10123831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	/* reflect duplex change */
10133831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (phydev->link && (lp->old_duplex != phydev->duplex)) {
10144e16d6ebd65b4f2c4e3f780b4c5704beef64019cFlorian Fainelli		lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? MCR0_FD : 0);
10153831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		iowrite16(lp->mcr0, ioaddr);
10163831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10173831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		status_changed = 1;
10183831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->old_duplex = phydev->duplex;
10193831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10203831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10213831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (status_changed) {
10223831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		pr_info("%s: link %s", dev->name, phydev->link ?
10233831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			"UP" : "DOWN");
10243831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		if (phydev->link)
10253831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			pr_cont(" - %d/%s", phydev->speed,
10263831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli			DUPLEX_FULL == phydev->duplex ? "full" : "half");
10273831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		pr_cont("\n");
10283831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10293831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
10303831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10313831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellistatic int r6040_mii_probe(struct net_device *dev)
10323831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli{
10333831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
10343831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct phy_device *phydev = NULL;
10353831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10363831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev = phy_find_first(lp->mii_bus);
10373831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!phydev) {
10383831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&lp->pdev->dev, "no PHY found\n");
10393831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		return -ENODEV;
10403831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10413831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10423831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
1043f9a8f83b04e0c362a2fc660dbad980d24af209fcFlorian Fainelli			     PHY_INTERFACE_MODE_MII);
10443831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10453831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (IS_ERR(phydev)) {
10463831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&lp->pdev->dev, "could not attach to PHY\n");
10473831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		return PTR_ERR(phydev);
10483831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
10493831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10503831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	/* mask with MAC supported features */
10513831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev->supported &= (SUPPORTED_10baseT_Half
10523831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_10baseT_Full
10533831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_100baseT_Half
10543831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_100baseT_Full
10553831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_Autoneg
10563831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_MII
10573831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli				| SUPPORTED_TP);
10583831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10593831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	phydev->advertising = phydev->supported;
10603831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->phydev = phydev;
10613831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->old_link = 0;
10623831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->old_duplex = -1;
10633831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10643831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
10653831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		"(mii_bus:phy_addr=%s)\n",
10663831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		phydev->drv->name, dev_name(&phydev->dev));
10673831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10683831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	return 0;
10693831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli}
10703831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
10711dd06ae8db716e17ec7e06244b858606edf378c0Greg Kroah-Hartmanstatic int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
10727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
10737a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev;
10747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct r6040_private *lp;
10757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	void __iomem *ioaddr;
10767a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int err, io_size = R6040_IO_SIZE;
10777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	static int card_idx = -1;
10787a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	int bar = 0;
10797a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	u16 *adrp;
10803831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	int i;
10817a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10822154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli	pr_info("%s\n", version);
10837a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10847a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	err = pci_enable_device(pdev);
10857a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (err)
1086b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out;
10877a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
10887a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* this should always be supported */
1089284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
1090b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
10917d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "32-bit PCI DMA addresses"
10927a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang				"not supported by the card\n");
1093acaf8276823302983d681c2cedaaf01918406935Devendra Naga		goto err_out_disable_dev;
10947a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
1095284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
1096b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
10977d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "32-bit PCI DMA addresses"
1098092427be8cef341c957a93ec2469890501a09bffJeff Garzik				"not supported by the card\n");
1099acaf8276823302983d681c2cedaaf01918406935Devendra Naga		goto err_out_disable_dev;
1100092427be8cef341c957a93ec2469890501a09bffJeff Garzik	}
11017a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11027a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* IO Size check */
11036f5bec195839dba3ca0ab8a7a53861e679109c0bMichael Opdenacker	if (pci_resource_len(pdev, bar) < io_size) {
11047d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
1105b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -EIO;
1106acaf8276823302983d681c2cedaaf01918406935Devendra Naga		goto err_out_disable_dev;
11077a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11087a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11097a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_set_master(pdev);
11107a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11117a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev = alloc_etherdev(sizeof(struct r6040_private));
11127a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!dev) {
1113b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -ENOMEM;
1114acaf8276823302983d681c2cedaaf01918406935Devendra Naga		goto err_out_disable_dev;
11157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11167a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	SET_NETDEV_DEV(dev, &pdev->dev);
11177a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp = netdev_priv(dev);
11187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1119b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	err = pci_request_regions(pdev, DRV_NAME);
1120b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli
1121b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	if (err) {
11227d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Failed to request PCI regions\n");
1123b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out_free_dev;
11247a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
11257a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11267a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	ioaddr = pci_iomap(pdev, bar, io_size);
11277a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (!ioaddr) {
11287d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "ioremap failed for device\n");
1129b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		err = -EIO;
1130b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli		goto err_out_free_res;
11317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
113231171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli
113384314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli	/* If PHY status change register is still set to zero it means the
113431171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli	 * bootloader didn't initialize it, so we set it to:
113531171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli	 * - enable phy status change
113631171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli	 * - enable all phy addresses
113731171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli	 * - set to lowest timer divider */
113884314bf92265bccea601ed75ec93944e1a36dd81Florian Fainelli	if (ioread16(ioaddr + PHY_CC) == 0)
113931171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli		iowrite16(SCEN | PHY_MAX_ADDR << PHYAD_SHIFT |
114031171aec23206e00ca4458cc3e3357a5275ccaaaFlorian Fainelli				7 << TMRDIV_SHIFT, ioaddr + PHY_CC);
11417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Init system & device */
11437a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->base = ioaddr;
11447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->irq = pdev->irq;
11457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11467a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	spin_lock_init(&lp->lock);
11477a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_set_drvdata(pdev, dev);
11487a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11497a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Set MAC address */
11507a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	card_idx++;
11517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp = (u16 *)dev->dev_addr;
11537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[0] = ioread16(ioaddr + MID_0L);
11547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[1] = ioread16(ioaddr + MID_0M);
11557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	adrp[2] = ioread16(ioaddr + MID_0H);
11567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11571d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli	/* Some bootloader/BIOSes do not initialize
11581d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli	 * MAC address, warn about that */
11599f1136182f732f6e847fc43bd88b579739d5c211Florian Fainelli	if (!(adrp[0] || adrp[1] || adrp[2])) {
11602154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli		netdev_warn(dev, "MAC address not initialized, "
11612154c704c7240379fae4633359e06e8df875c1fdFlorian Fainelli					"generating random\n");
1162f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka		eth_hw_addr_random(dev);
11639f1136182f732f6e847fc43bd88b579739d5c211Florian Fainelli	}
11641d2b1a76d39433ba9eb065bb31d3594cb491e617Florian Fainelli
11657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Link new device into r6040_root_dev */
11667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	lp->pdev = pdev;
1167129cf9a7028fc50b226b8021bc0b76fb38efa81dFlorian Fainelli	lp->dev = dev;
11687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Init RDC private data */
117077e1e438cbb1b8f9b7a3bb2d4f0264d1dd952d75Cesar Eduardo Barros	lp->mcr0 = MCR0_XMTEN | MCR0_RCVEN;
11717a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
11727a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* The RDC-specific entries in the device structure. */
1173a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger	dev->netdev_ops = &r6040_netdev_ops;
11747a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->ethtool_ops = &netdev_ethtool_ops;
11757a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	dev->watchdog_timeo = TX_TIMEOUT;
1176a7bd89cbb1aa8342617c2f8a6dc0595e5f553115Stephen Hemminger
11777a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	netif_napi_add(dev, &lp->napi, r6040_poll, 64);
11783831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
11793831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus = mdiobus_alloc();
11803831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->mii_bus) {
11813831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
11829c86c0f4ba49b39f909d7f18731b91e563e07065Axel Lin		err = -ENOMEM;
1183e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly		goto err_out_unmap;
1184e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly	}
1185e03f614af7811f9d089862a8700e683dcc6963c6Mark Kelly
11863831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->priv = dev;
11873831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->read = r6040_mdiobus_read;
11883831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->write = r6040_mdiobus_write;
11893831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	lp->mii_bus->name = "r6040_eth_mii";
1190817380e1d05534880a99d84a47cc5a2df111030dFlorian Fainelli	snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
1191817380e1d05534880a99d84a47cc5a2df111030dFlorian Fainelli		dev_name(&pdev->dev), card_idx);
1192b2adaca92c63b9bb8beb021d554f656e387a7648Joe Perches	lp->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
11933831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (!lp->mii_bus->irq) {
11949c86c0f4ba49b39f909d7f18731b91e563e07065Axel Lin		err = -ENOMEM;
11953831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio;
11963831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
11973831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
11983831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	for (i = 0; i < PHY_MAX_ADDR; i++)
11993831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		lp->mii_bus->irq[i] = PHY_POLL;
12003831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
12013831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	err = mdiobus_register(lp->mii_bus);
12023831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (err) {
12033831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "failed to register MII bus\n");
12043831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_irq;
12053831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
12063831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
12073831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	err = r6040_mii_probe(dev);
12083831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	if (err) {
12093831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		dev_err(&pdev->dev, "failed to probe MII bus\n");
12103831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_unregister;
12113831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	}
12123831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli
12137a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	/* Register net device. After this dev->name assign */
12147a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	err = register_netdev(dev);
12157a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	if (err) {
12167d53b80980a598836c56517290b29aa7b0766ef8Florian Fainelli		dev_err(&pdev->dev, "Failed to register net device\n");
12173831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli		goto err_out_mdio_unregister;
12187a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	}
12197a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return 0;
12207a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12213831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio_unregister:
12223831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_unregister(lp->mii_bus);
12233831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio_irq:
12243831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	kfree(lp->mii_bus->irq);
12253831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainellierr_out_mdio:
12263831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_free(lp->mii_bus);
1227b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_unmap:
122820571d8894d1ee5a181e34e8d07ed8472acd30c4Devendra Naga	netif_napi_del(&lp->napi);
1229b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainelli	pci_iounmap(pdev, ioaddr);
1230b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_free_res:
12317a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_release_regions(pdev);
1232b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out_free_dev:
12337a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	free_netdev(dev);
1234acaf8276823302983d681c2cedaaf01918406935Devendra Nagaerr_out_disable_dev:
1235acaf8276823302983d681c2cedaaf01918406935Devendra Naga	pci_disable_device(pdev);
1236b0e453902ad53580a77c2b1baddcc0b2d8ce8accFlorian Fainellierr_out:
12377a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	return err;
12387a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12397a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
1240f1e242648bce83ec67f8bc047e1ad1ade7b85725Bill Pembertonstatic void r6040_remove_one(struct pci_dev *pdev)
12417a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang{
12427a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	struct net_device *dev = pci_get_drvdata(pdev);
12433831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	struct r6040_private *lp = netdev_priv(dev);
12447a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12457a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	unregister_netdev(dev);
12463831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_unregister(lp->mii_bus);
12473831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	kfree(lp->mii_bus->irq);
12483831861b4ad8fd0ad7110048eb3e155628799d2bFlorian Fainelli	mdiobus_free(lp->mii_bus);
124920571d8894d1ee5a181e34e8d07ed8472acd30c4Devendra Naga	netif_napi_del(&lp->napi);
125020571d8894d1ee5a181e34e8d07ed8472acd30c4Devendra Naga	pci_iounmap(pdev, lp->base);
12517a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_release_regions(pdev);
12527a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	free_netdev(dev);
12537a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	pci_disable_device(pdev);
12547a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang}
12557a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12567a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12579baa3c34ac4e27f7e062f266f50cc5dbea26a6c1Benoit Tainestatic const struct pci_device_id r6040_pci_tbl[] = {
12585ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) },
12595ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	{ 0 }
12607a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
12617a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten WangMODULE_DEVICE_TABLE(pci, r6040_pci_tbl);
12627a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
12637a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wangstatic struct pci_driver r6040_driver = {
12645ac5d616327bdbdf632bdf4dc9ae09477f79b6b3Francois Romieu	.name		= DRV_NAME,
12657a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.id_table	= r6040_pci_tbl,
12667a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang	.probe		= r6040_init_one,
1267f1e242648bce83ec67f8bc047e1ad1ade7b85725Bill Pemberton	.remove		= r6040_remove_one,
12687a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang};
12697a47dd7a2f178cc4e87d584b0469eef4b58b7aeaSten Wang
127036efc94b1d09e75fc18b400b0fba8220f967fb44Devendra Nagamodule_pci_driver(r6040_driver);
1271