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