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