162306a36Sopenharmony_ci/* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Written 1998-2001 by Donald Becker. 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci Current Maintainer: Kevin Brace <kevinbrace@bracecomputerlab.com> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci This software may be used and distributed according to the terms of 862306a36Sopenharmony_ci the GNU General Public License (GPL), incorporated herein by reference. 962306a36Sopenharmony_ci Drivers based on or derived from this code fall under the GPL and must 1062306a36Sopenharmony_ci retain the authorship, copyright and license notice. This file is not 1162306a36Sopenharmony_ci a complete program and may only be used when the entire operating 1262306a36Sopenharmony_ci system is licensed under the GPL. 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci This driver is designed for the VIA VT86C100A Rhine-I. 1562306a36Sopenharmony_ci It also works with the Rhine-II (6102) and Rhine-III (6105/6105L/6105LOM 1662306a36Sopenharmony_ci and management NIC 6105M). 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 1962306a36Sopenharmony_ci Scyld Computing Corporation 2062306a36Sopenharmony_ci 410 Severn Ave., Suite 210 2162306a36Sopenharmony_ci Annapolis MD 21403 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci This driver contains some changes from the original Donald Becker 2562306a36Sopenharmony_ci version. He may or may not be interested in bug reports on this 2662306a36Sopenharmony_ci code. You can find his versions at: 2762306a36Sopenharmony_ci http://www.scyld.com/network/via-rhine.html 2862306a36Sopenharmony_ci [link no longer provides useful info -jgarzik] 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci*/ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DRV_NAME "via-rhine" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <linux/types.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* A few user-configurable values. 3962306a36Sopenharmony_ci These may be modified when a driver module is loaded. */ 4062306a36Sopenharmony_cistatic int debug = 0; 4162306a36Sopenharmony_ci#define RHINE_MSG_DEFAULT \ 4262306a36Sopenharmony_ci (0x0000) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-frames scheme. 4562306a36Sopenharmony_ci Setting to > 1518 effectively disables this feature. */ 4662306a36Sopenharmony_ci#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \ 4762306a36Sopenharmony_ci defined(CONFIG_SPARC) || defined(__ia64__) || \ 4862306a36Sopenharmony_ci defined(__sh__) || defined(__mips__) 4962306a36Sopenharmony_cistatic int rx_copybreak = 1518; 5062306a36Sopenharmony_ci#else 5162306a36Sopenharmony_cistatic int rx_copybreak; 5262306a36Sopenharmony_ci#endif 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Work-around for broken BIOSes: they are unable to get the chip back out of 5562306a36Sopenharmony_ci power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */ 5662306a36Sopenharmony_cistatic bool avoid_D3; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * In case you are looking for 'options[]' or 'full_duplex[]', they 6062306a36Sopenharmony_ci * are gone. Use ethtool(8) instead. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). 6462306a36Sopenharmony_ci The Rhine has a 64 element 8390-like hash table. */ 6562306a36Sopenharmony_cistatic const int multicast_filter_limit = 32; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Operational parameters that are set at compile time. */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Keep the ring sizes a power of two for compile efficiency. 7162306a36Sopenharmony_ci * The compiler will convert <unsigned>'%'<2^N> into a bit mask. 7262306a36Sopenharmony_ci * Making the Tx ring too large decreases the effectiveness of channel 7362306a36Sopenharmony_ci * bonding and packet priority. 7462306a36Sopenharmony_ci * With BQL support, we can increase TX ring safely. 7562306a36Sopenharmony_ci * There are no ill effects from too-large receive rings. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci#define TX_RING_SIZE 64 7862306a36Sopenharmony_ci#define TX_QUEUE_LEN (TX_RING_SIZE - 6) /* Limit ring entries actually used. */ 7962306a36Sopenharmony_ci#define RX_RING_SIZE 64 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Operational parameters that usually are not changed. */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 8462306a36Sopenharmony_ci#define TX_TIMEOUT (2*HZ) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#include <linux/module.h> 8962306a36Sopenharmony_ci#include <linux/moduleparam.h> 9062306a36Sopenharmony_ci#include <linux/kernel.h> 9162306a36Sopenharmony_ci#include <linux/string.h> 9262306a36Sopenharmony_ci#include <linux/timer.h> 9362306a36Sopenharmony_ci#include <linux/errno.h> 9462306a36Sopenharmony_ci#include <linux/ioport.h> 9562306a36Sopenharmony_ci#include <linux/interrupt.h> 9662306a36Sopenharmony_ci#include <linux/pci.h> 9762306a36Sopenharmony_ci#include <linux/of.h> 9862306a36Sopenharmony_ci#include <linux/of_irq.h> 9962306a36Sopenharmony_ci#include <linux/platform_device.h> 10062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 10162306a36Sopenharmony_ci#include <linux/netdevice.h> 10262306a36Sopenharmony_ci#include <linux/etherdevice.h> 10362306a36Sopenharmony_ci#include <linux/skbuff.h> 10462306a36Sopenharmony_ci#include <linux/init.h> 10562306a36Sopenharmony_ci#include <linux/delay.h> 10662306a36Sopenharmony_ci#include <linux/mii.h> 10762306a36Sopenharmony_ci#include <linux/ethtool.h> 10862306a36Sopenharmony_ci#include <linux/crc32.h> 10962306a36Sopenharmony_ci#include <linux/if_vlan.h> 11062306a36Sopenharmony_ci#include <linux/bitops.h> 11162306a36Sopenharmony_ci#include <linux/workqueue.h> 11262306a36Sopenharmony_ci#include <asm/processor.h> /* Processor type for cache alignment. */ 11362306a36Sopenharmony_ci#include <asm/io.h> 11462306a36Sopenharmony_ci#include <asm/irq.h> 11562306a36Sopenharmony_ci#include <linux/uaccess.h> 11662306a36Sopenharmony_ci#include <linux/dmi.h> 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciMODULE_AUTHOR("Donald Becker <becker@scyld.com>"); 11962306a36Sopenharmony_ciMODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver"); 12062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cimodule_param(debug, int, 0); 12362306a36Sopenharmony_cimodule_param(rx_copybreak, int, 0); 12462306a36Sopenharmony_cimodule_param(avoid_D3, bool, 0); 12562306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "VIA Rhine debug message flags"); 12662306a36Sopenharmony_ciMODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames"); 12762306a36Sopenharmony_ciMODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)"); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define MCAM_SIZE 32 13062306a36Sopenharmony_ci#define VCAM_SIZE 32 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci Theory of Operation 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciI. Board Compatibility 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciThis driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet 13862306a36Sopenharmony_cicontroller. 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciII. Board-specific settings 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ciBoards with this chip are functional only in a bus-master PCI slot. 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciMany operational settings are loaded from the EEPROM to the Config word at 14562306a36Sopenharmony_cioffset 0x78. For most of these settings, this driver assumes that they are 14662306a36Sopenharmony_cicorrect. 14762306a36Sopenharmony_ciIf this driver is compiled to use PCI memory space operations the EEPROM 14862306a36Sopenharmony_cimust be configured to enable memory ops. 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciIII. Driver operation 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ciIIIa. Ring buffers 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ciThis driver uses two statically allocated fixed-size descriptor lists 15562306a36Sopenharmony_ciformed into rings by a branch from the final descriptor to the beginning of 15662306a36Sopenharmony_cithe list. The ring sizes are set at compile time by RX/TX_RING_SIZE. 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciIIIb/c. Transmit/Receive Structure 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciThis driver attempts to use a zero-copy receive and transmit scheme. 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciAlas, all data buffers are required to start on a 32 bit boundary, so 16362306a36Sopenharmony_cithe driver must often copy transmit packets into bounce buffers. 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ciThe driver allocates full frame size skbuffs for the Rx ring buffers at 16662306a36Sopenharmony_ciopen() time and passes the skb->data field to the chip as receive data 16762306a36Sopenharmony_cibuffers. When an incoming frame is less than RX_COPYBREAK bytes long, 16862306a36Sopenharmony_cia fresh skbuff is allocated and the frame is copied to the new skbuff. 16962306a36Sopenharmony_ciWhen the incoming frame is larger, the skbuff is passed directly up the 17062306a36Sopenharmony_ciprotocol stack. Buffers consumed this way are replaced by newly allocated 17162306a36Sopenharmony_ciskbuffs in the last phase of rhine_rx(). 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciThe RX_COPYBREAK value is chosen to trade-off the memory wasted by 17462306a36Sopenharmony_ciusing a full-sized skbuff for small frames vs. the copying costs of larger 17562306a36Sopenharmony_ciframes. New boards are typically used in generously configured machines 17662306a36Sopenharmony_ciand the underfilled buffers have negligible impact compared to the benefit of 17762306a36Sopenharmony_cia single allocation size, so the default value of zero results in never 17862306a36Sopenharmony_cicopying packets. When copying is done, the cost is usually mitigated by using 17962306a36Sopenharmony_cia combined copy/checksum routine. Copying also preloads the cache, which is 18062306a36Sopenharmony_cimost useful with small frames. 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciSince the VIA chips are only able to transfer data to buffers on 32 bit 18362306a36Sopenharmony_ciboundaries, the IP header at offset 14 in an ethernet frame isn't 18462306a36Sopenharmony_cilongword aligned for further processing. Copying these unaligned buffers 18562306a36Sopenharmony_cihas the beneficial effect of 16-byte aligning the IP header. 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciIIId. Synchronization 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciThe driver runs as two independent, single-threaded flows of control. One 19062306a36Sopenharmony_ciis the send-packet routine, which enforces single-threaded use by the 19162306a36Sopenharmony_cinetdev_priv(dev)->lock spinlock. The other thread is the interrupt handler, 19262306a36Sopenharmony_ciwhich is single threaded by the hardware and interrupt handling software. 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciThe send packet thread has partial control over the Tx ring. It locks the 19562306a36Sopenharmony_cinetdev_priv(dev)->lock whenever it's queuing a Tx packet. If the next slot in 19662306a36Sopenharmony_cithe ring is not available it stops the transmit queue by 19762306a36Sopenharmony_cicalling netif_stop_queue. 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ciThe interrupt handler has exclusive control over the Rx ring and records stats 20062306a36Sopenharmony_cifrom the Tx ring. After reaping the stats, it marks the Tx queue entry as 20162306a36Sopenharmony_ciempty by incrementing the dirty_tx mark. If at least half of the entries in 20262306a36Sopenharmony_cithe Rx ring are available the transmit queue is woken up if it was stopped. 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ciIV. Notes 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ciIVb. References 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciPreliminary VT86C100A manual from http://www.via.com.tw/ 20962306a36Sopenharmony_cihttp://www.scyld.com/expert/100mbps.html 21062306a36Sopenharmony_cihttp://www.scyld.com/expert/NWay.html 21162306a36Sopenharmony_ciftp://ftp.via.com.tw/public/lan/Products/NIC/VT86C100A/Datasheet/VT86C100A03.pdf 21262306a36Sopenharmony_ciftp://ftp.via.com.tw/public/lan/Products/NIC/VT6102/Datasheet/VT6102_021.PDF 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ciIVc. Errata 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ciThe VT86C100A manual is not reliable information. 21862306a36Sopenharmony_ciThe 3043 chip does not handle unaligned transmit or receive buffers, resulting 21962306a36Sopenharmony_ciin significant performance degradation for bounce buffer copies on transmit 22062306a36Sopenharmony_ciand unaligned IP headers on receive. 22162306a36Sopenharmony_ciThe chip does not pad to minimum transmit length. 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci*/ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* This table drives the PCI probe routines. It's mostly boilerplate in all 22762306a36Sopenharmony_ci of the drivers, and will likely be provided by some future kernel. 22862306a36Sopenharmony_ci Note the matching code -- the first table entry matchs all 56** cards but 22962306a36Sopenharmony_ci second only the 1234 card. 23062306a36Sopenharmony_ci*/ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cienum rhine_revs { 23362306a36Sopenharmony_ci VT86C100A = 0x00, 23462306a36Sopenharmony_ci VTunknown0 = 0x20, 23562306a36Sopenharmony_ci VT6102 = 0x40, 23662306a36Sopenharmony_ci VT8231 = 0x50, /* Integrated MAC */ 23762306a36Sopenharmony_ci VT8233 = 0x60, /* Integrated MAC */ 23862306a36Sopenharmony_ci VT8235 = 0x74, /* Integrated MAC */ 23962306a36Sopenharmony_ci VT8237 = 0x78, /* Integrated MAC */ 24062306a36Sopenharmony_ci VT8251 = 0x7C, /* Integrated MAC */ 24162306a36Sopenharmony_ci VT6105 = 0x80, 24262306a36Sopenharmony_ci VT6105_B0 = 0x83, 24362306a36Sopenharmony_ci VT6105L = 0x8A, 24462306a36Sopenharmony_ci VT6107 = 0x8C, 24562306a36Sopenharmony_ci VTunknown2 = 0x8E, 24662306a36Sopenharmony_ci VT6105M = 0x90, /* Management adapter */ 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cienum rhine_quirks { 25062306a36Sopenharmony_ci rqWOL = 0x0001, /* Wake-On-LAN support */ 25162306a36Sopenharmony_ci rqForceReset = 0x0002, 25262306a36Sopenharmony_ci rq6patterns = 0x0040, /* 6 instead of 4 patterns for WOL */ 25362306a36Sopenharmony_ci rqStatusWBRace = 0x0080, /* Tx Status Writeback Error possible */ 25462306a36Sopenharmony_ci rqRhineI = 0x0100, /* See comment below */ 25562306a36Sopenharmony_ci rqIntPHY = 0x0200, /* Integrated PHY */ 25662306a36Sopenharmony_ci rqMgmt = 0x0400, /* Management adapter */ 25762306a36Sopenharmony_ci rqNeedEnMMIO = 0x0800, /* Whether the core needs to be 25862306a36Sopenharmony_ci * switched from PIO mode to MMIO 25962306a36Sopenharmony_ci * (only applies to PCI) 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci/* 26362306a36Sopenharmony_ci * rqRhineI: VT86C100A (aka Rhine-I) uses different bits to enable 26462306a36Sopenharmony_ci * MMIO as well as for the collision counter and the Tx FIFO underflow 26562306a36Sopenharmony_ci * indicator. In addition, Tx and Rx buffers need to 4 byte aligned. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* Beware of PCI posted writes */ 26962306a36Sopenharmony_ci#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0) 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic const struct pci_device_id rhine_pci_tbl[] = { 27262306a36Sopenharmony_ci { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */ 27362306a36Sopenharmony_ci { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */ 27462306a36Sopenharmony_ci { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */ 27562306a36Sopenharmony_ci { 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6105M */ 27662306a36Sopenharmony_ci { } /* terminate list */ 27762306a36Sopenharmony_ci}; 27862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rhine_pci_tbl); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* OpenFirmware identifiers for platform-bus devices 28162306a36Sopenharmony_ci * The .data field is currently only used to store quirks 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_cistatic u32 vt8500_quirks = rqWOL | rqForceReset | rq6patterns; 28462306a36Sopenharmony_cistatic const struct of_device_id rhine_of_tbl[] = { 28562306a36Sopenharmony_ci { .compatible = "via,vt8500-rhine", .data = &vt8500_quirks }, 28662306a36Sopenharmony_ci { } /* terminate list */ 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rhine_of_tbl); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* Offsets to the device registers. */ 29162306a36Sopenharmony_cienum register_offsets { 29262306a36Sopenharmony_ci StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08, 29362306a36Sopenharmony_ci ChipCmd1=0x09, TQWake=0x0A, 29462306a36Sopenharmony_ci IntrStatus=0x0C, IntrEnable=0x0E, 29562306a36Sopenharmony_ci MulticastFilter0=0x10, MulticastFilter1=0x14, 29662306a36Sopenharmony_ci RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54, 29762306a36Sopenharmony_ci MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, PCIBusConfig1=0x6F, 29862306a36Sopenharmony_ci MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74, 29962306a36Sopenharmony_ci ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B, 30062306a36Sopenharmony_ci RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81, 30162306a36Sopenharmony_ci StickyHW=0x83, IntrStatus2=0x84, 30262306a36Sopenharmony_ci CamMask=0x88, CamCon=0x92, CamAddr=0x93, 30362306a36Sopenharmony_ci WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4, 30462306a36Sopenharmony_ci WOLcrClr1=0xA6, WOLcgClr=0xA7, 30562306a36Sopenharmony_ci PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD, 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* Bits in ConfigD */ 30962306a36Sopenharmony_cienum backoff_bits { 31062306a36Sopenharmony_ci BackOptional=0x01, BackModify=0x02, 31162306a36Sopenharmony_ci BackCaptureEffect=0x04, BackRandom=0x08 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* Bits in the TxConfig (TCR) register */ 31562306a36Sopenharmony_cienum tcr_bits { 31662306a36Sopenharmony_ci TCR_PQEN=0x01, 31762306a36Sopenharmony_ci TCR_LB0=0x02, /* loopback[0] */ 31862306a36Sopenharmony_ci TCR_LB1=0x04, /* loopback[1] */ 31962306a36Sopenharmony_ci TCR_OFSET=0x08, 32062306a36Sopenharmony_ci TCR_RTGOPT=0x10, 32162306a36Sopenharmony_ci TCR_RTFT0=0x20, 32262306a36Sopenharmony_ci TCR_RTFT1=0x40, 32362306a36Sopenharmony_ci TCR_RTSF=0x80, 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* Bits in the CamCon (CAMC) register */ 32762306a36Sopenharmony_cienum camcon_bits { 32862306a36Sopenharmony_ci CAMC_CAMEN=0x01, 32962306a36Sopenharmony_ci CAMC_VCAMSL=0x02, 33062306a36Sopenharmony_ci CAMC_CAMWR=0x04, 33162306a36Sopenharmony_ci CAMC_CAMRD=0x08, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* Bits in the PCIBusConfig1 (BCR1) register */ 33562306a36Sopenharmony_cienum bcr1_bits { 33662306a36Sopenharmony_ci BCR1_POT0=0x01, 33762306a36Sopenharmony_ci BCR1_POT1=0x02, 33862306a36Sopenharmony_ci BCR1_POT2=0x04, 33962306a36Sopenharmony_ci BCR1_CTFT0=0x08, 34062306a36Sopenharmony_ci BCR1_CTFT1=0x10, 34162306a36Sopenharmony_ci BCR1_CTSF=0x20, 34262306a36Sopenharmony_ci BCR1_TXQNOBK=0x40, /* for VT6105 */ 34362306a36Sopenharmony_ci BCR1_VIDFR=0x80, /* for VT6105 */ 34462306a36Sopenharmony_ci BCR1_MED0=0x40, /* for VT6102 */ 34562306a36Sopenharmony_ci BCR1_MED1=0x80, /* for VT6102 */ 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* Registers we check that mmio and reg are the same. */ 34962306a36Sopenharmony_cistatic const int mmio_verify_registers[] = { 35062306a36Sopenharmony_ci RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD, 35162306a36Sopenharmony_ci 0 35262306a36Sopenharmony_ci}; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* Bits in the interrupt status/mask registers. */ 35562306a36Sopenharmony_cienum intr_status_bits { 35662306a36Sopenharmony_ci IntrRxDone = 0x0001, 35762306a36Sopenharmony_ci IntrTxDone = 0x0002, 35862306a36Sopenharmony_ci IntrRxErr = 0x0004, 35962306a36Sopenharmony_ci IntrTxError = 0x0008, 36062306a36Sopenharmony_ci IntrRxEmpty = 0x0020, 36162306a36Sopenharmony_ci IntrPCIErr = 0x0040, 36262306a36Sopenharmony_ci IntrStatsMax = 0x0080, 36362306a36Sopenharmony_ci IntrRxEarly = 0x0100, 36462306a36Sopenharmony_ci IntrTxUnderrun = 0x0210, 36562306a36Sopenharmony_ci IntrRxOverflow = 0x0400, 36662306a36Sopenharmony_ci IntrRxDropped = 0x0800, 36762306a36Sopenharmony_ci IntrRxNoBuf = 0x1000, 36862306a36Sopenharmony_ci IntrTxAborted = 0x2000, 36962306a36Sopenharmony_ci IntrLinkChange = 0x4000, 37062306a36Sopenharmony_ci IntrRxWakeUp = 0x8000, 37162306a36Sopenharmony_ci IntrTxDescRace = 0x080000, /* mapped from IntrStatus2 */ 37262306a36Sopenharmony_ci IntrNormalSummary = IntrRxDone | IntrTxDone, 37362306a36Sopenharmony_ci IntrTxErrSummary = IntrTxDescRace | IntrTxAborted | IntrTxError | 37462306a36Sopenharmony_ci IntrTxUnderrun, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */ 37862306a36Sopenharmony_cienum wol_bits { 37962306a36Sopenharmony_ci WOLucast = 0x10, 38062306a36Sopenharmony_ci WOLmagic = 0x20, 38162306a36Sopenharmony_ci WOLbmcast = 0x30, 38262306a36Sopenharmony_ci WOLlnkon = 0x40, 38362306a36Sopenharmony_ci WOLlnkoff = 0x80, 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/* The Rx and Tx buffer descriptors. */ 38762306a36Sopenharmony_cistruct rx_desc { 38862306a36Sopenharmony_ci __le32 rx_status; 38962306a36Sopenharmony_ci __le32 desc_length; /* Chain flag, Buffer/frame length */ 39062306a36Sopenharmony_ci __le32 addr; 39162306a36Sopenharmony_ci __le32 next_desc; 39262306a36Sopenharmony_ci}; 39362306a36Sopenharmony_cistruct tx_desc { 39462306a36Sopenharmony_ci __le32 tx_status; 39562306a36Sopenharmony_ci __le32 desc_length; /* Chain flag, Tx Config, Frame length */ 39662306a36Sopenharmony_ci __le32 addr; 39762306a36Sopenharmony_ci __le32 next_desc; 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */ 40162306a36Sopenharmony_ci#define TXDESC 0x00e08000 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cienum rx_status_bits { 40462306a36Sopenharmony_ci RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F 40562306a36Sopenharmony_ci}; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* Bits in *_desc.*_status */ 40862306a36Sopenharmony_cienum desc_status_bits { 40962306a36Sopenharmony_ci DescOwn=0x80000000 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/* Bits in *_desc.*_length */ 41362306a36Sopenharmony_cienum desc_length_bits { 41462306a36Sopenharmony_ci DescTag=0x00010000 41562306a36Sopenharmony_ci}; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Bits in ChipCmd. */ 41862306a36Sopenharmony_cienum chip_cmd_bits { 41962306a36Sopenharmony_ci CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08, 42062306a36Sopenharmony_ci CmdTxOn=0x10, Cmd1TxDemand=0x20, CmdRxDemand=0x40, 42162306a36Sopenharmony_ci Cmd1EarlyRx=0x01, Cmd1EarlyTx=0x02, Cmd1FDuplex=0x04, 42262306a36Sopenharmony_ci Cmd1NoTxPoll=0x08, Cmd1Reset=0x80, 42362306a36Sopenharmony_ci}; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistruct rhine_stats { 42662306a36Sopenharmony_ci u64 packets; 42762306a36Sopenharmony_ci u64 bytes; 42862306a36Sopenharmony_ci struct u64_stats_sync syncp; 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistruct rhine_private { 43262306a36Sopenharmony_ci /* Bit mask for configured VLAN ids */ 43362306a36Sopenharmony_ci unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Descriptor rings */ 43662306a36Sopenharmony_ci struct rx_desc *rx_ring; 43762306a36Sopenharmony_ci struct tx_desc *tx_ring; 43862306a36Sopenharmony_ci dma_addr_t rx_ring_dma; 43962306a36Sopenharmony_ci dma_addr_t tx_ring_dma; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* The addresses of receive-in-place skbuffs. */ 44262306a36Sopenharmony_ci struct sk_buff *rx_skbuff[RX_RING_SIZE]; 44362306a36Sopenharmony_ci dma_addr_t rx_skbuff_dma[RX_RING_SIZE]; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* The saved address of a sent-in-place packet/buffer, for later free(). */ 44662306a36Sopenharmony_ci struct sk_buff *tx_skbuff[TX_RING_SIZE]; 44762306a36Sopenharmony_ci dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Tx bounce buffers (Rhine-I only) */ 45062306a36Sopenharmony_ci unsigned char *tx_buf[TX_RING_SIZE]; 45162306a36Sopenharmony_ci unsigned char *tx_bufs; 45262306a36Sopenharmony_ci dma_addr_t tx_bufs_dma; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci int irq; 45562306a36Sopenharmony_ci long pioaddr; 45662306a36Sopenharmony_ci struct net_device *dev; 45762306a36Sopenharmony_ci struct napi_struct napi; 45862306a36Sopenharmony_ci spinlock_t lock; 45962306a36Sopenharmony_ci struct mutex task_lock; 46062306a36Sopenharmony_ci bool task_enable; 46162306a36Sopenharmony_ci struct work_struct slow_event_task; 46262306a36Sopenharmony_ci struct work_struct reset_task; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci u32 msg_enable; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Frequently used values: keep some adjacent for cache effect. */ 46762306a36Sopenharmony_ci u32 quirks; 46862306a36Sopenharmony_ci unsigned int cur_rx; 46962306a36Sopenharmony_ci unsigned int cur_tx, dirty_tx; 47062306a36Sopenharmony_ci unsigned int rx_buf_sz; /* Based on MTU+slack. */ 47162306a36Sopenharmony_ci struct rhine_stats rx_stats; 47262306a36Sopenharmony_ci struct rhine_stats tx_stats; 47362306a36Sopenharmony_ci u8 wolopts; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci u8 tx_thresh, rx_thresh; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci struct mii_if_info mii_if; 47862306a36Sopenharmony_ci void __iomem *base; 47962306a36Sopenharmony_ci}; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci#define BYTE_REG_BITS_ON(x, p) do { iowrite8((ioread8((p))|(x)), (p)); } while (0) 48262306a36Sopenharmony_ci#define WORD_REG_BITS_ON(x, p) do { iowrite16((ioread16((p))|(x)), (p)); } while (0) 48362306a36Sopenharmony_ci#define DWORD_REG_BITS_ON(x, p) do { iowrite32((ioread32((p))|(x)), (p)); } while (0) 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci#define BYTE_REG_BITS_IS_ON(x, p) (ioread8((p)) & (x)) 48662306a36Sopenharmony_ci#define WORD_REG_BITS_IS_ON(x, p) (ioread16((p)) & (x)) 48762306a36Sopenharmony_ci#define DWORD_REG_BITS_IS_ON(x, p) (ioread32((p)) & (x)) 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define BYTE_REG_BITS_OFF(x, p) do { iowrite8(ioread8((p)) & (~(x)), (p)); } while (0) 49062306a36Sopenharmony_ci#define WORD_REG_BITS_OFF(x, p) do { iowrite16(ioread16((p)) & (~(x)), (p)); } while (0) 49162306a36Sopenharmony_ci#define DWORD_REG_BITS_OFF(x, p) do { iowrite32(ioread32((p)) & (~(x)), (p)); } while (0) 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci#define BYTE_REG_BITS_SET(x, m, p) do { iowrite8((ioread8((p)) & (~(m)))|(x), (p)); } while (0) 49462306a36Sopenharmony_ci#define WORD_REG_BITS_SET(x, m, p) do { iowrite16((ioread16((p)) & (~(m)))|(x), (p)); } while (0) 49562306a36Sopenharmony_ci#define DWORD_REG_BITS_SET(x, m, p) do { iowrite32((ioread32((p)) & (~(m)))|(x), (p)); } while (0) 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location); 49962306a36Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value); 50062306a36Sopenharmony_cistatic int rhine_open(struct net_device *dev); 50162306a36Sopenharmony_cistatic void rhine_reset_task(struct work_struct *work); 50262306a36Sopenharmony_cistatic void rhine_slow_event_task(struct work_struct *work); 50362306a36Sopenharmony_cistatic void rhine_tx_timeout(struct net_device *dev, unsigned int txqueue); 50462306a36Sopenharmony_cistatic netdev_tx_t rhine_start_tx(struct sk_buff *skb, 50562306a36Sopenharmony_ci struct net_device *dev); 50662306a36Sopenharmony_cistatic irqreturn_t rhine_interrupt(int irq, void *dev_instance); 50762306a36Sopenharmony_cistatic void rhine_tx(struct net_device *dev); 50862306a36Sopenharmony_cistatic int rhine_rx(struct net_device *dev, int limit); 50962306a36Sopenharmony_cistatic void rhine_set_rx_mode(struct net_device *dev); 51062306a36Sopenharmony_cistatic void rhine_get_stats64(struct net_device *dev, 51162306a36Sopenharmony_ci struct rtnl_link_stats64 *stats); 51262306a36Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 51362306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops; 51462306a36Sopenharmony_cistatic int rhine_close(struct net_device *dev); 51562306a36Sopenharmony_cistatic int rhine_vlan_rx_add_vid(struct net_device *dev, 51662306a36Sopenharmony_ci __be16 proto, u16 vid); 51762306a36Sopenharmony_cistatic int rhine_vlan_rx_kill_vid(struct net_device *dev, 51862306a36Sopenharmony_ci __be16 proto, u16 vid); 51962306a36Sopenharmony_cistatic void rhine_restart_tx(struct net_device *dev); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool low) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 52462306a36Sopenharmony_ci int i; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci for (i = 0; i < 1024; i++) { 52762306a36Sopenharmony_ci bool has_mask_bits = !!(ioread8(ioaddr + reg) & mask); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (low ^ has_mask_bits) 53062306a36Sopenharmony_ci break; 53162306a36Sopenharmony_ci udelay(10); 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci if (i > 64) { 53462306a36Sopenharmony_ci netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle " 53562306a36Sopenharmony_ci "count: %04d\n", low ? "low" : "high", reg, mask, i); 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci rhine_wait_bit(rp, reg, mask, false); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci rhine_wait_bit(rp, reg, mask, true); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic u32 rhine_get_events(struct rhine_private *rp) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 55262306a36Sopenharmony_ci u32 intr_status; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci intr_status = ioread16(ioaddr + IntrStatus); 55562306a36Sopenharmony_ci /* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */ 55662306a36Sopenharmony_ci if (rp->quirks & rqStatusWBRace) 55762306a36Sopenharmony_ci intr_status |= ioread8(ioaddr + IntrStatus2) << 16; 55862306a36Sopenharmony_ci return intr_status; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void rhine_ack_events(struct rhine_private *rp, u32 mask) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (rp->quirks & rqStatusWBRace) 56662306a36Sopenharmony_ci iowrite8(mask >> 16, ioaddr + IntrStatus2); 56762306a36Sopenharmony_ci iowrite16(mask, ioaddr + IntrStatus); 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci/* 57162306a36Sopenharmony_ci * Get power related registers into sane state. 57262306a36Sopenharmony_ci * Notify user about past WOL event. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_cistatic void rhine_power_init(struct net_device *dev) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 57762306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 57862306a36Sopenharmony_ci u16 wolstat; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (rp->quirks & rqWOL) { 58162306a36Sopenharmony_ci /* Make sure chip is in power state D0 */ 58262306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + StickyHW) & 0xFC, ioaddr + StickyHW); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Disable "force PME-enable" */ 58562306a36Sopenharmony_ci iowrite8(0x80, ioaddr + WOLcgClr); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Clear power-event config bits (WOL) */ 58862306a36Sopenharmony_ci iowrite8(0xFF, ioaddr + WOLcrClr); 58962306a36Sopenharmony_ci /* More recent cards can manage two additional patterns */ 59062306a36Sopenharmony_ci if (rp->quirks & rq6patterns) 59162306a36Sopenharmony_ci iowrite8(0x03, ioaddr + WOLcrClr1); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* Save power-event status bits */ 59462306a36Sopenharmony_ci wolstat = ioread8(ioaddr + PwrcsrSet); 59562306a36Sopenharmony_ci if (rp->quirks & rq6patterns) 59662306a36Sopenharmony_ci wolstat |= (ioread8(ioaddr + PwrcsrSet1) & 0x03) << 8; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* Clear power-event status bits */ 59962306a36Sopenharmony_ci iowrite8(0xFF, ioaddr + PwrcsrClr); 60062306a36Sopenharmony_ci if (rp->quirks & rq6patterns) 60162306a36Sopenharmony_ci iowrite8(0x03, ioaddr + PwrcsrClr1); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (wolstat) { 60462306a36Sopenharmony_ci char *reason; 60562306a36Sopenharmony_ci switch (wolstat) { 60662306a36Sopenharmony_ci case WOLmagic: 60762306a36Sopenharmony_ci reason = "Magic packet"; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case WOLlnkon: 61062306a36Sopenharmony_ci reason = "Link went up"; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case WOLlnkoff: 61362306a36Sopenharmony_ci reason = "Link went down"; 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case WOLucast: 61662306a36Sopenharmony_ci reason = "Unicast packet"; 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case WOLbmcast: 61962306a36Sopenharmony_ci reason = "Multicast/broadcast packet"; 62062306a36Sopenharmony_ci break; 62162306a36Sopenharmony_ci default: 62262306a36Sopenharmony_ci reason = "Unknown"; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci netdev_info(dev, "Woke system up. Reason: %s\n", 62562306a36Sopenharmony_ci reason); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic void rhine_chip_reset(struct net_device *dev) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 63362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 63462306a36Sopenharmony_ci u8 cmd1; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci iowrite8(Cmd1Reset, ioaddr + ChipCmd1); 63762306a36Sopenharmony_ci IOSYNC; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) { 64062306a36Sopenharmony_ci netdev_info(dev, "Reset not complete yet. Trying harder.\n"); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Force reset */ 64362306a36Sopenharmony_ci if (rp->quirks & rqForceReset) 64462306a36Sopenharmony_ci iowrite8(0x40, ioaddr + MiscCmd); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Reset can take somewhat longer (rare) */ 64762306a36Sopenharmony_ci rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci cmd1 = ioread8(ioaddr + ChipCmd1); 65162306a36Sopenharmony_ci netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ? 65262306a36Sopenharmony_ci "failed" : "succeeded"); 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic void enable_mmio(long pioaddr, u32 quirks) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci int n; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (quirks & rqNeedEnMMIO) { 66062306a36Sopenharmony_ci if (quirks & rqRhineI) { 66162306a36Sopenharmony_ci /* More recent docs say that this bit is reserved */ 66262306a36Sopenharmony_ci n = inb(pioaddr + ConfigA) | 0x20; 66362306a36Sopenharmony_ci outb(n, pioaddr + ConfigA); 66462306a36Sopenharmony_ci } else { 66562306a36Sopenharmony_ci n = inb(pioaddr + ConfigD) | 0x80; 66662306a36Sopenharmony_ci outb(n, pioaddr + ConfigD); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic inline int verify_mmio(struct device *hwdev, 67262306a36Sopenharmony_ci long pioaddr, 67362306a36Sopenharmony_ci void __iomem *ioaddr, 67462306a36Sopenharmony_ci u32 quirks) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci if (quirks & rqNeedEnMMIO) { 67762306a36Sopenharmony_ci int i = 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Check that selected MMIO registers match the PIO ones */ 68062306a36Sopenharmony_ci while (mmio_verify_registers[i]) { 68162306a36Sopenharmony_ci int reg = mmio_verify_registers[i++]; 68262306a36Sopenharmony_ci unsigned char a = inb(pioaddr+reg); 68362306a36Sopenharmony_ci unsigned char b = readb(ioaddr+reg); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (a != b) { 68662306a36Sopenharmony_ci dev_err(hwdev, 68762306a36Sopenharmony_ci "MMIO do not match PIO [%02x] (%02x != %02x)\n", 68862306a36Sopenharmony_ci reg, a, b); 68962306a36Sopenharmony_ci return -EIO; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci/* 69762306a36Sopenharmony_ci * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM 69862306a36Sopenharmony_ci * (plus 0x6C for Rhine-I/II) 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_cistatic void rhine_reload_eeprom(long pioaddr, struct net_device *dev) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 70362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 70462306a36Sopenharmony_ci int i; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci outb(0x20, pioaddr + MACRegEEcsr); 70762306a36Sopenharmony_ci for (i = 0; i < 1024; i++) { 70862306a36Sopenharmony_ci if (!(inb(pioaddr + MACRegEEcsr) & 0x20)) 70962306a36Sopenharmony_ci break; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci if (i > 512) 71262306a36Sopenharmony_ci pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* 71562306a36Sopenharmony_ci * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable 71662306a36Sopenharmony_ci * MMIO. If reloading EEPROM was done first this could be avoided, but 71762306a36Sopenharmony_ci * it is not known if that still works with the "win98-reboot" problem. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci enable_mmio(pioaddr, rp->quirks); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Turn off EEPROM-controlled wake-up (magic packet) */ 72262306a36Sopenharmony_ci if (rp->quirks & rqWOL) 72362306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ConfigA) & 0xFC, ioaddr + ConfigA); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 72862306a36Sopenharmony_cistatic void rhine_poll(struct net_device *dev) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 73162306a36Sopenharmony_ci const int irq = rp->irq; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci disable_irq(irq); 73462306a36Sopenharmony_ci rhine_interrupt(irq, dev); 73562306a36Sopenharmony_ci enable_irq(irq); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci#endif 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic void rhine_kick_tx_threshold(struct rhine_private *rp) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci if (rp->tx_thresh < 0xe0) { 74262306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci rp->tx_thresh += 0x20; 74562306a36Sopenharmony_ci BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig); 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void rhine_tx_err(struct rhine_private *rp, u32 status) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct net_device *dev = rp->dev; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (status & IntrTxAborted) { 75462306a36Sopenharmony_ci netif_info(rp, tx_err, dev, 75562306a36Sopenharmony_ci "Abort %08x, frame dropped\n", status); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (status & IntrTxUnderrun) { 75962306a36Sopenharmony_ci rhine_kick_tx_threshold(rp); 76062306a36Sopenharmony_ci netif_info(rp, tx_err ,dev, "Transmitter underrun, " 76162306a36Sopenharmony_ci "Tx threshold now %02x\n", rp->tx_thresh); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (status & IntrTxDescRace) 76562306a36Sopenharmony_ci netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n"); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if ((status & IntrTxError) && 76862306a36Sopenharmony_ci (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) { 76962306a36Sopenharmony_ci rhine_kick_tx_threshold(rp); 77062306a36Sopenharmony_ci netif_info(rp, tx_err, dev, "Unspecified error. " 77162306a36Sopenharmony_ci "Tx threshold now %02x\n", rp->tx_thresh); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci rhine_restart_tx(dev); 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 78062306a36Sopenharmony_ci struct net_device_stats *stats = &rp->dev->stats; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci stats->rx_crc_errors += ioread16(ioaddr + RxCRCErrs); 78362306a36Sopenharmony_ci stats->rx_missed_errors += ioread16(ioaddr + RxMissed); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* 78662306a36Sopenharmony_ci * Clears the "tally counters" for CRC errors and missed frames(?). 78762306a36Sopenharmony_ci * It has been reported that some chips need a write of 0 to clear 78862306a36Sopenharmony_ci * these, for others the counters are set to 1 when written to and 78962306a36Sopenharmony_ci * instead cleared when read. So we clear them both ways ... 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_ci iowrite32(0, ioaddr + RxMissed); 79262306a36Sopenharmony_ci ioread16(ioaddr + RxCRCErrs); 79362306a36Sopenharmony_ci ioread16(ioaddr + RxMissed); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci#define RHINE_EVENT_NAPI_RX (IntrRxDone | \ 79762306a36Sopenharmony_ci IntrRxErr | \ 79862306a36Sopenharmony_ci IntrRxEmpty | \ 79962306a36Sopenharmony_ci IntrRxOverflow | \ 80062306a36Sopenharmony_ci IntrRxDropped | \ 80162306a36Sopenharmony_ci IntrRxNoBuf | \ 80262306a36Sopenharmony_ci IntrRxWakeUp) 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci#define RHINE_EVENT_NAPI_TX_ERR (IntrTxError | \ 80562306a36Sopenharmony_ci IntrTxAborted | \ 80662306a36Sopenharmony_ci IntrTxUnderrun | \ 80762306a36Sopenharmony_ci IntrTxDescRace) 80862306a36Sopenharmony_ci#define RHINE_EVENT_NAPI_TX (IntrTxDone | RHINE_EVENT_NAPI_TX_ERR) 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci#define RHINE_EVENT_NAPI (RHINE_EVENT_NAPI_RX | \ 81162306a36Sopenharmony_ci RHINE_EVENT_NAPI_TX | \ 81262306a36Sopenharmony_ci IntrStatsMax) 81362306a36Sopenharmony_ci#define RHINE_EVENT_SLOW (IntrPCIErr | IntrLinkChange) 81462306a36Sopenharmony_ci#define RHINE_EVENT (RHINE_EVENT_NAPI | RHINE_EVENT_SLOW) 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic int rhine_napipoll(struct napi_struct *napi, int budget) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct rhine_private *rp = container_of(napi, struct rhine_private, napi); 81962306a36Sopenharmony_ci struct net_device *dev = rp->dev; 82062306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 82162306a36Sopenharmony_ci u16 enable_mask = RHINE_EVENT & 0xffff; 82262306a36Sopenharmony_ci int work_done = 0; 82362306a36Sopenharmony_ci u32 status; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci status = rhine_get_events(rp); 82662306a36Sopenharmony_ci rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (status & RHINE_EVENT_NAPI_RX) 82962306a36Sopenharmony_ci work_done += rhine_rx(dev, budget); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (status & RHINE_EVENT_NAPI_TX) { 83262306a36Sopenharmony_ci if (status & RHINE_EVENT_NAPI_TX_ERR) { 83362306a36Sopenharmony_ci /* Avoid scavenging before Tx engine turned off */ 83462306a36Sopenharmony_ci rhine_wait_bit_low(rp, ChipCmd, CmdTxOn); 83562306a36Sopenharmony_ci if (ioread8(ioaddr + ChipCmd) & CmdTxOn) 83662306a36Sopenharmony_ci netif_warn(rp, tx_err, dev, "Tx still on\n"); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci rhine_tx(dev); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (status & RHINE_EVENT_NAPI_TX_ERR) 84262306a36Sopenharmony_ci rhine_tx_err(rp, status); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (status & IntrStatsMax) { 84662306a36Sopenharmony_ci spin_lock(&rp->lock); 84762306a36Sopenharmony_ci rhine_update_rx_crc_and_missed_errord(rp); 84862306a36Sopenharmony_ci spin_unlock(&rp->lock); 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (status & RHINE_EVENT_SLOW) { 85262306a36Sopenharmony_ci enable_mask &= ~RHINE_EVENT_SLOW; 85362306a36Sopenharmony_ci schedule_work(&rp->slow_event_task); 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (work_done < budget) { 85762306a36Sopenharmony_ci napi_complete_done(napi, work_done); 85862306a36Sopenharmony_ci iowrite16(enable_mask, ioaddr + IntrEnable); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci return work_done; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void rhine_hw_init(struct net_device *dev, long pioaddr) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* Reset the chip to erase previous misconfiguration. */ 86862306a36Sopenharmony_ci rhine_chip_reset(dev); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Rhine-I needs extra time to recuperate before EEPROM reload */ 87162306a36Sopenharmony_ci if (rp->quirks & rqRhineI) 87262306a36Sopenharmony_ci msleep(5); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* Reload EEPROM controlled bytes cleared by soft reset */ 87562306a36Sopenharmony_ci if (dev_is_pci(dev->dev.parent)) 87662306a36Sopenharmony_ci rhine_reload_eeprom(pioaddr, dev); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic const struct net_device_ops rhine_netdev_ops = { 88062306a36Sopenharmony_ci .ndo_open = rhine_open, 88162306a36Sopenharmony_ci .ndo_stop = rhine_close, 88262306a36Sopenharmony_ci .ndo_start_xmit = rhine_start_tx, 88362306a36Sopenharmony_ci .ndo_get_stats64 = rhine_get_stats64, 88462306a36Sopenharmony_ci .ndo_set_rx_mode = rhine_set_rx_mode, 88562306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 88662306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 88762306a36Sopenharmony_ci .ndo_eth_ioctl = netdev_ioctl, 88862306a36Sopenharmony_ci .ndo_tx_timeout = rhine_tx_timeout, 88962306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = rhine_vlan_rx_add_vid, 89062306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = rhine_vlan_rx_kill_vid, 89162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 89262306a36Sopenharmony_ci .ndo_poll_controller = rhine_poll, 89362306a36Sopenharmony_ci#endif 89462306a36Sopenharmony_ci}; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int rhine_init_one_common(struct device *hwdev, u32 quirks, 89762306a36Sopenharmony_ci long pioaddr, void __iomem *ioaddr, int irq) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct net_device *dev; 90062306a36Sopenharmony_ci struct rhine_private *rp; 90162306a36Sopenharmony_ci int i, rc, phy_id; 90262306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 90362306a36Sopenharmony_ci const char *name; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* this should always be supported */ 90662306a36Sopenharmony_ci rc = dma_set_mask(hwdev, DMA_BIT_MASK(32)); 90762306a36Sopenharmony_ci if (rc) { 90862306a36Sopenharmony_ci dev_err(hwdev, "32-bit DMA addresses not supported by the card!?\n"); 90962306a36Sopenharmony_ci goto err_out; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct rhine_private)); 91362306a36Sopenharmony_ci if (!dev) { 91462306a36Sopenharmony_ci rc = -ENOMEM; 91562306a36Sopenharmony_ci goto err_out; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, hwdev); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci rp = netdev_priv(dev); 92062306a36Sopenharmony_ci rp->dev = dev; 92162306a36Sopenharmony_ci rp->quirks = quirks; 92262306a36Sopenharmony_ci rp->pioaddr = pioaddr; 92362306a36Sopenharmony_ci rp->base = ioaddr; 92462306a36Sopenharmony_ci rp->irq = irq; 92562306a36Sopenharmony_ci rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci phy_id = rp->quirks & rqIntPHY ? 1 : 0; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci u64_stats_init(&rp->tx_stats.syncp); 93062306a36Sopenharmony_ci u64_stats_init(&rp->rx_stats.syncp); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* Get chip registers into a sane state */ 93362306a36Sopenharmony_ci rhine_power_init(dev); 93462306a36Sopenharmony_ci rhine_hw_init(dev, pioaddr); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci for (i = 0; i < 6; i++) 93762306a36Sopenharmony_ci addr[i] = ioread8(ioaddr + StationAddr + i); 93862306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 94162306a36Sopenharmony_ci /* Report it and use a random ethernet address instead */ 94262306a36Sopenharmony_ci netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr); 94362306a36Sopenharmony_ci eth_hw_addr_random(dev); 94462306a36Sopenharmony_ci netdev_info(dev, "Using random MAC address: %pM\n", 94562306a36Sopenharmony_ci dev->dev_addr); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci /* For Rhine-I/II, phy_id is loaded from EEPROM */ 94962306a36Sopenharmony_ci if (!phy_id) 95062306a36Sopenharmony_ci phy_id = ioread8(ioaddr + 0x6C); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci spin_lock_init(&rp->lock); 95362306a36Sopenharmony_ci mutex_init(&rp->task_lock); 95462306a36Sopenharmony_ci INIT_WORK(&rp->reset_task, rhine_reset_task); 95562306a36Sopenharmony_ci INIT_WORK(&rp->slow_event_task, rhine_slow_event_task); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci rp->mii_if.dev = dev; 95862306a36Sopenharmony_ci rp->mii_if.mdio_read = mdio_read; 95962306a36Sopenharmony_ci rp->mii_if.mdio_write = mdio_write; 96062306a36Sopenharmony_ci rp->mii_if.phy_id_mask = 0x1f; 96162306a36Sopenharmony_ci rp->mii_if.reg_num_mask = 0x1f; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* The chip-specific entries in the device structure. */ 96462306a36Sopenharmony_ci dev->netdev_ops = &rhine_netdev_ops; 96562306a36Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 96662306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci netif_napi_add(dev, &rp->napi, rhine_napipoll); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (rp->quirks & rqRhineI) 97162306a36Sopenharmony_ci dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (rp->quirks & rqMgmt) 97462306a36Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_TX | 97562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 97662306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* dev->name not defined before register_netdev()! */ 97962306a36Sopenharmony_ci rc = register_netdev(dev); 98062306a36Sopenharmony_ci if (rc) 98162306a36Sopenharmony_ci goto err_out_free_netdev; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (rp->quirks & rqRhineI) 98462306a36Sopenharmony_ci name = "Rhine"; 98562306a36Sopenharmony_ci else if (rp->quirks & rqStatusWBRace) 98662306a36Sopenharmony_ci name = "Rhine II"; 98762306a36Sopenharmony_ci else if (rp->quirks & rqMgmt) 98862306a36Sopenharmony_ci name = "Rhine III (Management Adapter)"; 98962306a36Sopenharmony_ci else 99062306a36Sopenharmony_ci name = "Rhine III"; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci netdev_info(dev, "VIA %s at %p, %pM, IRQ %d\n", 99362306a36Sopenharmony_ci name, ioaddr, dev->dev_addr, rp->irq); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci dev_set_drvdata(hwdev, dev); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci { 99862306a36Sopenharmony_ci u16 mii_cmd; 99962306a36Sopenharmony_ci int mii_status = mdio_read(dev, phy_id, 1); 100062306a36Sopenharmony_ci mii_cmd = mdio_read(dev, phy_id, MII_BMCR) & ~BMCR_ISOLATE; 100162306a36Sopenharmony_ci mdio_write(dev, phy_id, MII_BMCR, mii_cmd); 100262306a36Sopenharmony_ci if (mii_status != 0xffff && mii_status != 0x0000) { 100362306a36Sopenharmony_ci rp->mii_if.advertising = mdio_read(dev, phy_id, 4); 100462306a36Sopenharmony_ci netdev_info(dev, 100562306a36Sopenharmony_ci "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n", 100662306a36Sopenharmony_ci phy_id, 100762306a36Sopenharmony_ci mii_status, rp->mii_if.advertising, 100862306a36Sopenharmony_ci mdio_read(dev, phy_id, 5)); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* set IFF_RUNNING */ 101162306a36Sopenharmony_ci if (mii_status & BMSR_LSTATUS) 101262306a36Sopenharmony_ci netif_carrier_on(dev); 101362306a36Sopenharmony_ci else 101462306a36Sopenharmony_ci netif_carrier_off(dev); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci rp->mii_if.phy_id = phy_id; 101962306a36Sopenharmony_ci if (avoid_D3) 102062306a36Sopenharmony_ci netif_info(rp, probe, dev, "No D3 power state at shutdown\n"); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return 0; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cierr_out_free_netdev: 102562306a36Sopenharmony_ci free_netdev(dev); 102662306a36Sopenharmony_cierr_out: 102762306a36Sopenharmony_ci return rc; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic int rhine_init_one_pci(struct pci_dev *pdev, 103162306a36Sopenharmony_ci const struct pci_device_id *ent) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct device *hwdev = &pdev->dev; 103462306a36Sopenharmony_ci int rc; 103562306a36Sopenharmony_ci long pioaddr, memaddr; 103662306a36Sopenharmony_ci void __iomem *ioaddr; 103762306a36Sopenharmony_ci int io_size = pdev->revision < VTunknown0 ? 128 : 256; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci/* This driver was written to use PCI memory space. Some early versions 104062306a36Sopenharmony_ci * of the Rhine may only work correctly with I/O space accesses. 104162306a36Sopenharmony_ci * TODO: determine for which revisions this is true and assign the flag 104262306a36Sopenharmony_ci * in code as opposed to this Kconfig option (???) 104362306a36Sopenharmony_ci */ 104462306a36Sopenharmony_ci#ifdef CONFIG_VIA_RHINE_MMIO 104562306a36Sopenharmony_ci u32 quirks = rqNeedEnMMIO; 104662306a36Sopenharmony_ci#else 104762306a36Sopenharmony_ci u32 quirks = 0; 104862306a36Sopenharmony_ci#endif 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci rc = pci_enable_device(pdev); 105162306a36Sopenharmony_ci if (rc) 105262306a36Sopenharmony_ci goto err_out; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (pdev->revision < VTunknown0) { 105562306a36Sopenharmony_ci quirks |= rqRhineI; 105662306a36Sopenharmony_ci } else if (pdev->revision >= VT6102) { 105762306a36Sopenharmony_ci quirks |= rqWOL | rqForceReset; 105862306a36Sopenharmony_ci if (pdev->revision < VT6105) { 105962306a36Sopenharmony_ci quirks |= rqStatusWBRace; 106062306a36Sopenharmony_ci } else { 106162306a36Sopenharmony_ci quirks |= rqIntPHY; 106262306a36Sopenharmony_ci if (pdev->revision >= VT6105_B0) 106362306a36Sopenharmony_ci quirks |= rq6patterns; 106462306a36Sopenharmony_ci if (pdev->revision >= VT6105M) 106562306a36Sopenharmony_ci quirks |= rqMgmt; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* sanity check */ 107062306a36Sopenharmony_ci if ((pci_resource_len(pdev, 0) < io_size) || 107162306a36Sopenharmony_ci (pci_resource_len(pdev, 1) < io_size)) { 107262306a36Sopenharmony_ci rc = -EIO; 107362306a36Sopenharmony_ci dev_err(hwdev, "Insufficient PCI resources, aborting\n"); 107462306a36Sopenharmony_ci goto err_out_pci_disable; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci pioaddr = pci_resource_start(pdev, 0); 107862306a36Sopenharmony_ci memaddr = pci_resource_start(pdev, 1); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci pci_set_master(pdev); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci rc = pci_request_regions(pdev, DRV_NAME); 108362306a36Sopenharmony_ci if (rc) 108462306a36Sopenharmony_ci goto err_out_pci_disable; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ioaddr = pci_iomap(pdev, (quirks & rqNeedEnMMIO ? 1 : 0), io_size); 108762306a36Sopenharmony_ci if (!ioaddr) { 108862306a36Sopenharmony_ci rc = -EIO; 108962306a36Sopenharmony_ci dev_err(hwdev, 109062306a36Sopenharmony_ci "ioremap failed for device %s, region 0x%X @ 0x%lX\n", 109162306a36Sopenharmony_ci dev_name(hwdev), io_size, memaddr); 109262306a36Sopenharmony_ci goto err_out_free_res; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci enable_mmio(pioaddr, quirks); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci rc = verify_mmio(hwdev, pioaddr, ioaddr, quirks); 109862306a36Sopenharmony_ci if (rc) 109962306a36Sopenharmony_ci goto err_out_unmap; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci rc = rhine_init_one_common(&pdev->dev, quirks, 110262306a36Sopenharmony_ci pioaddr, ioaddr, pdev->irq); 110362306a36Sopenharmony_ci if (!rc) 110462306a36Sopenharmony_ci return 0; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cierr_out_unmap: 110762306a36Sopenharmony_ci pci_iounmap(pdev, ioaddr); 110862306a36Sopenharmony_cierr_out_free_res: 110962306a36Sopenharmony_ci pci_release_regions(pdev); 111062306a36Sopenharmony_cierr_out_pci_disable: 111162306a36Sopenharmony_ci pci_disable_device(pdev); 111262306a36Sopenharmony_cierr_out: 111362306a36Sopenharmony_ci return rc; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int rhine_init_one_platform(struct platform_device *pdev) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci const u32 *quirks; 111962306a36Sopenharmony_ci int irq; 112062306a36Sopenharmony_ci void __iomem *ioaddr; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci quirks = of_device_get_match_data(&pdev->dev); 112362306a36Sopenharmony_ci if (!quirks) 112462306a36Sopenharmony_ci return -EINVAL; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci ioaddr = devm_platform_ioremap_resource(pdev, 0); 112762306a36Sopenharmony_ci if (IS_ERR(ioaddr)) 112862306a36Sopenharmony_ci return PTR_ERR(ioaddr); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 113162306a36Sopenharmony_ci if (!irq) 113262306a36Sopenharmony_ci return -EINVAL; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci return rhine_init_one_common(&pdev->dev, *quirks, 113562306a36Sopenharmony_ci (long)ioaddr, ioaddr, irq); 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int alloc_ring(struct net_device* dev) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 114162306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 114262306a36Sopenharmony_ci void *ring; 114362306a36Sopenharmony_ci dma_addr_t ring_dma; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci ring = dma_alloc_coherent(hwdev, 114662306a36Sopenharmony_ci RX_RING_SIZE * sizeof(struct rx_desc) + 114762306a36Sopenharmony_ci TX_RING_SIZE * sizeof(struct tx_desc), 114862306a36Sopenharmony_ci &ring_dma, 114962306a36Sopenharmony_ci GFP_ATOMIC); 115062306a36Sopenharmony_ci if (!ring) { 115162306a36Sopenharmony_ci netdev_err(dev, "Could not allocate DMA memory\n"); 115262306a36Sopenharmony_ci return -ENOMEM; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci if (rp->quirks & rqRhineI) { 115562306a36Sopenharmony_ci rp->tx_bufs = dma_alloc_coherent(hwdev, 115662306a36Sopenharmony_ci PKT_BUF_SZ * TX_RING_SIZE, 115762306a36Sopenharmony_ci &rp->tx_bufs_dma, 115862306a36Sopenharmony_ci GFP_ATOMIC); 115962306a36Sopenharmony_ci if (rp->tx_bufs == NULL) { 116062306a36Sopenharmony_ci dma_free_coherent(hwdev, 116162306a36Sopenharmony_ci RX_RING_SIZE * sizeof(struct rx_desc) + 116262306a36Sopenharmony_ci TX_RING_SIZE * sizeof(struct tx_desc), 116362306a36Sopenharmony_ci ring, ring_dma); 116462306a36Sopenharmony_ci return -ENOMEM; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci rp->rx_ring = ring; 116962306a36Sopenharmony_ci rp->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc); 117062306a36Sopenharmony_ci rp->rx_ring_dma = ring_dma; 117162306a36Sopenharmony_ci rp->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return 0; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic void free_ring(struct net_device* dev) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 117962306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci dma_free_coherent(hwdev, 118262306a36Sopenharmony_ci RX_RING_SIZE * sizeof(struct rx_desc) + 118362306a36Sopenharmony_ci TX_RING_SIZE * sizeof(struct tx_desc), 118462306a36Sopenharmony_ci rp->rx_ring, rp->rx_ring_dma); 118562306a36Sopenharmony_ci rp->tx_ring = NULL; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (rp->tx_bufs) 118862306a36Sopenharmony_ci dma_free_coherent(hwdev, PKT_BUF_SZ * TX_RING_SIZE, 118962306a36Sopenharmony_ci rp->tx_bufs, rp->tx_bufs_dma); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci rp->tx_bufs = NULL; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistruct rhine_skb_dma { 119662306a36Sopenharmony_ci struct sk_buff *skb; 119762306a36Sopenharmony_ci dma_addr_t dma; 119862306a36Sopenharmony_ci}; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic inline int rhine_skb_dma_init(struct net_device *dev, 120162306a36Sopenharmony_ci struct rhine_skb_dma *sd) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 120462306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 120562306a36Sopenharmony_ci const int size = rp->rx_buf_sz; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci sd->skb = netdev_alloc_skb(dev, size); 120862306a36Sopenharmony_ci if (!sd->skb) 120962306a36Sopenharmony_ci return -ENOMEM; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci sd->dma = dma_map_single(hwdev, sd->skb->data, size, DMA_FROM_DEVICE); 121262306a36Sopenharmony_ci if (unlikely(dma_mapping_error(hwdev, sd->dma))) { 121362306a36Sopenharmony_ci netif_err(rp, drv, dev, "Rx DMA mapping failure\n"); 121462306a36Sopenharmony_ci dev_kfree_skb_any(sd->skb); 121562306a36Sopenharmony_ci return -EIO; 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci return 0; 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic void rhine_reset_rbufs(struct rhine_private *rp) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci int i; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci rp->cur_rx = 0; 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) 122862306a36Sopenharmony_ci rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn); 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic inline void rhine_skb_dma_nic_store(struct rhine_private *rp, 123262306a36Sopenharmony_ci struct rhine_skb_dma *sd, int entry) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci rp->rx_skbuff_dma[entry] = sd->dma; 123562306a36Sopenharmony_ci rp->rx_skbuff[entry] = sd->skb; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci rp->rx_ring[entry].addr = cpu_to_le32(sd->dma); 123862306a36Sopenharmony_ci dma_wmb(); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_cistatic void free_rbufs(struct net_device* dev); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic int alloc_rbufs(struct net_device *dev) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 124662306a36Sopenharmony_ci dma_addr_t next; 124762306a36Sopenharmony_ci int rc, i; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci rp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); 125062306a36Sopenharmony_ci next = rp->rx_ring_dma; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Init the ring entries */ 125362306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 125462306a36Sopenharmony_ci rp->rx_ring[i].rx_status = 0; 125562306a36Sopenharmony_ci rp->rx_ring[i].desc_length = cpu_to_le32(rp->rx_buf_sz); 125662306a36Sopenharmony_ci next += sizeof(struct rx_desc); 125762306a36Sopenharmony_ci rp->rx_ring[i].next_desc = cpu_to_le32(next); 125862306a36Sopenharmony_ci rp->rx_skbuff[i] = NULL; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci /* Mark the last entry as wrapping the ring. */ 126162306a36Sopenharmony_ci rp->rx_ring[i-1].next_desc = cpu_to_le32(rp->rx_ring_dma); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* Fill in the Rx buffers. Handle allocation failure gracefully. */ 126462306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 126562306a36Sopenharmony_ci struct rhine_skb_dma sd; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci rc = rhine_skb_dma_init(dev, &sd); 126862306a36Sopenharmony_ci if (rc < 0) { 126962306a36Sopenharmony_ci free_rbufs(dev); 127062306a36Sopenharmony_ci goto out; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci rhine_skb_dma_nic_store(rp, &sd, i); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci rhine_reset_rbufs(rp); 127762306a36Sopenharmony_ciout: 127862306a36Sopenharmony_ci return rc; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic void free_rbufs(struct net_device* dev) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 128462306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 128562306a36Sopenharmony_ci int i; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* Free all the skbuffs in the Rx queue. */ 128862306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 128962306a36Sopenharmony_ci rp->rx_ring[i].rx_status = 0; 129062306a36Sopenharmony_ci rp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ 129162306a36Sopenharmony_ci if (rp->rx_skbuff[i]) { 129262306a36Sopenharmony_ci dma_unmap_single(hwdev, 129362306a36Sopenharmony_ci rp->rx_skbuff_dma[i], 129462306a36Sopenharmony_ci rp->rx_buf_sz, DMA_FROM_DEVICE); 129562306a36Sopenharmony_ci dev_kfree_skb(rp->rx_skbuff[i]); 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci rp->rx_skbuff[i] = NULL; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic void alloc_tbufs(struct net_device* dev) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 130462306a36Sopenharmony_ci dma_addr_t next; 130562306a36Sopenharmony_ci int i; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci rp->dirty_tx = rp->cur_tx = 0; 130862306a36Sopenharmony_ci next = rp->tx_ring_dma; 130962306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 131062306a36Sopenharmony_ci rp->tx_skbuff[i] = NULL; 131162306a36Sopenharmony_ci rp->tx_ring[i].tx_status = 0; 131262306a36Sopenharmony_ci rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); 131362306a36Sopenharmony_ci next += sizeof(struct tx_desc); 131462306a36Sopenharmony_ci rp->tx_ring[i].next_desc = cpu_to_le32(next); 131562306a36Sopenharmony_ci if (rp->quirks & rqRhineI) 131662306a36Sopenharmony_ci rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci netdev_reset_queue(dev); 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic void free_tbufs(struct net_device* dev) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 132662306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 132762306a36Sopenharmony_ci int i; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 133062306a36Sopenharmony_ci rp->tx_ring[i].tx_status = 0; 133162306a36Sopenharmony_ci rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); 133262306a36Sopenharmony_ci rp->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ 133362306a36Sopenharmony_ci if (rp->tx_skbuff[i]) { 133462306a36Sopenharmony_ci if (rp->tx_skbuff_dma[i]) { 133562306a36Sopenharmony_ci dma_unmap_single(hwdev, 133662306a36Sopenharmony_ci rp->tx_skbuff_dma[i], 133762306a36Sopenharmony_ci rp->tx_skbuff[i]->len, 133862306a36Sopenharmony_ci DMA_TO_DEVICE); 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci dev_kfree_skb(rp->tx_skbuff[i]); 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci rp->tx_skbuff[i] = NULL; 134362306a36Sopenharmony_ci rp->tx_buf[i] = NULL; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic void rhine_check_media(struct net_device *dev, unsigned int init_media) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 135062306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (!rp->mii_if.force_media) 135362306a36Sopenharmony_ci mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (rp->mii_if.full_duplex) 135662306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex, 135762306a36Sopenharmony_ci ioaddr + ChipCmd1); 135862306a36Sopenharmony_ci else 135962306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, 136062306a36Sopenharmony_ci ioaddr + ChipCmd1); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci netif_info(rp, link, dev, "force_media %d, carrier %d\n", 136362306a36Sopenharmony_ci rp->mii_if.force_media, netif_carrier_ok(dev)); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/* Called after status of force_media possibly changed */ 136762306a36Sopenharmony_cistatic void rhine_set_carrier(struct mii_if_info *mii) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci struct net_device *dev = mii->dev; 137062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (mii->force_media) { 137362306a36Sopenharmony_ci /* autoneg is off: Link is always assumed to be up */ 137462306a36Sopenharmony_ci if (!netif_carrier_ok(dev)) 137562306a36Sopenharmony_ci netif_carrier_on(dev); 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci rhine_check_media(dev, 0); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci netif_info(rp, link, dev, "force_media %d, carrier %d\n", 138162306a36Sopenharmony_ci mii->force_media, netif_carrier_ok(dev)); 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci/** 138562306a36Sopenharmony_ci * rhine_set_cam - set CAM multicast filters 138662306a36Sopenharmony_ci * @ioaddr: register block of this Rhine 138762306a36Sopenharmony_ci * @idx: multicast CAM index [0..MCAM_SIZE-1] 138862306a36Sopenharmony_ci * @addr: multicast address (6 bytes) 138962306a36Sopenharmony_ci * 139062306a36Sopenharmony_ci * Load addresses into multicast filters. 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_cistatic void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci int i; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci iowrite8(CAMC_CAMEN, ioaddr + CamCon); 139762306a36Sopenharmony_ci wmb(); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* Paranoid -- idx out of range should never happen */ 140062306a36Sopenharmony_ci idx &= (MCAM_SIZE - 1); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci iowrite8((u8) idx, ioaddr + CamAddr); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci for (i = 0; i < 6; i++, addr++) 140562306a36Sopenharmony_ci iowrite8(*addr, ioaddr + MulticastFilter0 + i); 140662306a36Sopenharmony_ci udelay(10); 140762306a36Sopenharmony_ci wmb(); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon); 141062306a36Sopenharmony_ci udelay(10); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci iowrite8(0, ioaddr + CamCon); 141362306a36Sopenharmony_ci} 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci/** 141662306a36Sopenharmony_ci * rhine_set_vlan_cam - set CAM VLAN filters 141762306a36Sopenharmony_ci * @ioaddr: register block of this Rhine 141862306a36Sopenharmony_ci * @idx: VLAN CAM index [0..VCAM_SIZE-1] 141962306a36Sopenharmony_ci * @addr: VLAN ID (2 bytes) 142062306a36Sopenharmony_ci * 142162306a36Sopenharmony_ci * Load addresses into VLAN filters. 142262306a36Sopenharmony_ci */ 142362306a36Sopenharmony_cistatic void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr) 142462306a36Sopenharmony_ci{ 142562306a36Sopenharmony_ci iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon); 142662306a36Sopenharmony_ci wmb(); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* Paranoid -- idx out of range should never happen */ 142962306a36Sopenharmony_ci idx &= (VCAM_SIZE - 1); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci iowrite8((u8) idx, ioaddr + CamAddr); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci iowrite16(*((u16 *) addr), ioaddr + MulticastFilter0 + 6); 143462306a36Sopenharmony_ci udelay(10); 143562306a36Sopenharmony_ci wmb(); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon); 143862306a36Sopenharmony_ci udelay(10); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci iowrite8(0, ioaddr + CamCon); 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci/** 144462306a36Sopenharmony_ci * rhine_set_cam_mask - set multicast CAM mask 144562306a36Sopenharmony_ci * @ioaddr: register block of this Rhine 144662306a36Sopenharmony_ci * @mask: multicast CAM mask 144762306a36Sopenharmony_ci * 144862306a36Sopenharmony_ci * Mask sets multicast filters active/inactive. 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_cistatic void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci iowrite8(CAMC_CAMEN, ioaddr + CamCon); 145362306a36Sopenharmony_ci wmb(); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* write mask */ 145662306a36Sopenharmony_ci iowrite32(mask, ioaddr + CamMask); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* disable CAMEN */ 145962306a36Sopenharmony_ci iowrite8(0, ioaddr + CamCon); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci/** 146362306a36Sopenharmony_ci * rhine_set_vlan_cam_mask - set VLAN CAM mask 146462306a36Sopenharmony_ci * @ioaddr: register block of this Rhine 146562306a36Sopenharmony_ci * @mask: VLAN CAM mask 146662306a36Sopenharmony_ci * 146762306a36Sopenharmony_ci * Mask sets VLAN filters active/inactive. 146862306a36Sopenharmony_ci */ 146962306a36Sopenharmony_cistatic void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask) 147062306a36Sopenharmony_ci{ 147162306a36Sopenharmony_ci iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon); 147262306a36Sopenharmony_ci wmb(); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* write mask */ 147562306a36Sopenharmony_ci iowrite32(mask, ioaddr + CamMask); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci /* disable CAMEN */ 147862306a36Sopenharmony_ci iowrite8(0, ioaddr + CamCon); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci/** 148262306a36Sopenharmony_ci * rhine_init_cam_filter - initialize CAM filters 148362306a36Sopenharmony_ci * @dev: network device 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * Initialize (disable) hardware VLAN and multicast support on this 148662306a36Sopenharmony_ci * Rhine. 148762306a36Sopenharmony_ci */ 148862306a36Sopenharmony_cistatic void rhine_init_cam_filter(struct net_device *dev) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 149162306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* Disable all CAMs */ 149462306a36Sopenharmony_ci rhine_set_vlan_cam_mask(ioaddr, 0); 149562306a36Sopenharmony_ci rhine_set_cam_mask(ioaddr, 0); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci /* disable hardware VLAN support */ 149862306a36Sopenharmony_ci BYTE_REG_BITS_ON(TCR_PQEN, ioaddr + TxConfig); 149962306a36Sopenharmony_ci BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci/** 150362306a36Sopenharmony_ci * rhine_update_vcam - update VLAN CAM filters 150462306a36Sopenharmony_ci * @dev: rhine_private data of this Rhine 150562306a36Sopenharmony_ci * 150662306a36Sopenharmony_ci * Update VLAN CAM filters to match configuration change. 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_cistatic void rhine_update_vcam(struct net_device *dev) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 151162306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 151262306a36Sopenharmony_ci u16 vid; 151362306a36Sopenharmony_ci u32 vCAMmask = 0; /* 32 vCAMs (6105M and better) */ 151462306a36Sopenharmony_ci unsigned int i = 0; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci for_each_set_bit(vid, rp->active_vlans, VLAN_N_VID) { 151762306a36Sopenharmony_ci rhine_set_vlan_cam(ioaddr, i, (u8 *)&vid); 151862306a36Sopenharmony_ci vCAMmask |= 1 << i; 151962306a36Sopenharmony_ci if (++i >= VCAM_SIZE) 152062306a36Sopenharmony_ci break; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci rhine_set_vlan_cam_mask(ioaddr, vCAMmask); 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_cistatic int rhine_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci spin_lock_bh(&rp->lock); 153062306a36Sopenharmony_ci set_bit(vid, rp->active_vlans); 153162306a36Sopenharmony_ci rhine_update_vcam(dev); 153262306a36Sopenharmony_ci spin_unlock_bh(&rp->lock); 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int rhine_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci spin_lock_bh(&rp->lock); 154162306a36Sopenharmony_ci clear_bit(vid, rp->active_vlans); 154262306a36Sopenharmony_ci rhine_update_vcam(dev); 154362306a36Sopenharmony_ci spin_unlock_bh(&rp->lock); 154462306a36Sopenharmony_ci return 0; 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cistatic void init_registers(struct net_device *dev) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 155062306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 155162306a36Sopenharmony_ci int i; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci for (i = 0; i < 6; i++) 155462306a36Sopenharmony_ci iowrite8(dev->dev_addr[i], ioaddr + StationAddr + i); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci /* Initialize other registers. */ 155762306a36Sopenharmony_ci iowrite16(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */ 155862306a36Sopenharmony_ci /* Configure initial FIFO thresholds. */ 155962306a36Sopenharmony_ci iowrite8(0x20, ioaddr + TxConfig); 156062306a36Sopenharmony_ci rp->tx_thresh = 0x20; 156162306a36Sopenharmony_ci rp->rx_thresh = 0x60; /* Written in rhine_set_rx_mode(). */ 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci iowrite32(rp->rx_ring_dma, ioaddr + RxRingPtr); 156462306a36Sopenharmony_ci iowrite32(rp->tx_ring_dma, ioaddr + TxRingPtr); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci rhine_set_rx_mode(dev); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (rp->quirks & rqMgmt) 156962306a36Sopenharmony_ci rhine_init_cam_filter(dev); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci napi_enable(&rp->napi); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8), 157662306a36Sopenharmony_ci ioaddr + ChipCmd); 157762306a36Sopenharmony_ci rhine_check_media(dev, 1); 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/* Enable MII link status auto-polling (required for IntrLinkChange) */ 158162306a36Sopenharmony_cistatic void rhine_enable_linkmon(struct rhine_private *rp) 158262306a36Sopenharmony_ci{ 158362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci iowrite8(0, ioaddr + MIICmd); 158662306a36Sopenharmony_ci iowrite8(MII_BMSR, ioaddr + MIIRegAddr); 158762306a36Sopenharmony_ci iowrite8(0x80, ioaddr + MIICmd); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci rhine_wait_bit_high(rp, MIIRegAddr, 0x20); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr); 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci/* Disable MII link status auto-polling (required for MDIO access) */ 159562306a36Sopenharmony_cistatic void rhine_disable_linkmon(struct rhine_private *rp) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci iowrite8(0, ioaddr + MIICmd); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (rp->quirks & rqRhineI) { 160262306a36Sopenharmony_ci iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci /* Can be called from ISR. Evil. */ 160562306a36Sopenharmony_ci mdelay(1); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci /* 0x80 must be set immediately before turning it off */ 160862306a36Sopenharmony_ci iowrite8(0x80, ioaddr + MIICmd); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci rhine_wait_bit_high(rp, MIIRegAddr, 0x20); 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* Heh. Now clear 0x80 again. */ 161362306a36Sopenharmony_ci iowrite8(0, ioaddr + MIICmd); 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci else 161662306a36Sopenharmony_ci rhine_wait_bit_high(rp, MIIRegAddr, 0x80); 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci/* Read and write over the MII Management Data I/O (MDIO) interface. */ 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int regnum) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 162462306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 162562306a36Sopenharmony_ci int result; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci rhine_disable_linkmon(rp); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci /* rhine_disable_linkmon already cleared MIICmd */ 163062306a36Sopenharmony_ci iowrite8(phy_id, ioaddr + MIIPhyAddr); 163162306a36Sopenharmony_ci iowrite8(regnum, ioaddr + MIIRegAddr); 163262306a36Sopenharmony_ci iowrite8(0x40, ioaddr + MIICmd); /* Trigger read */ 163362306a36Sopenharmony_ci rhine_wait_bit_low(rp, MIICmd, 0x40); 163462306a36Sopenharmony_ci result = ioread16(ioaddr + MIIData); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci rhine_enable_linkmon(rp); 163762306a36Sopenharmony_ci return result; 163862306a36Sopenharmony_ci} 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int regnum, int value) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 164362306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci rhine_disable_linkmon(rp); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci /* rhine_disable_linkmon already cleared MIICmd */ 164862306a36Sopenharmony_ci iowrite8(phy_id, ioaddr + MIIPhyAddr); 164962306a36Sopenharmony_ci iowrite8(regnum, ioaddr + MIIRegAddr); 165062306a36Sopenharmony_ci iowrite16(value, ioaddr + MIIData); 165162306a36Sopenharmony_ci iowrite8(0x20, ioaddr + MIICmd); /* Trigger write */ 165262306a36Sopenharmony_ci rhine_wait_bit_low(rp, MIICmd, 0x20); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci rhine_enable_linkmon(rp); 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_cistatic void rhine_task_disable(struct rhine_private *rp) 165862306a36Sopenharmony_ci{ 165962306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 166062306a36Sopenharmony_ci rp->task_enable = false; 166162306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci cancel_work_sync(&rp->slow_event_task); 166462306a36Sopenharmony_ci cancel_work_sync(&rp->reset_task); 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic void rhine_task_enable(struct rhine_private *rp) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 167062306a36Sopenharmony_ci rp->task_enable = true; 167162306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 167262306a36Sopenharmony_ci} 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_cistatic int rhine_open(struct net_device *dev) 167562306a36Sopenharmony_ci{ 167662306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 167762306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 167862306a36Sopenharmony_ci int rc; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci rc = request_irq(rp->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev); 168162306a36Sopenharmony_ci if (rc) 168262306a36Sopenharmony_ci goto out; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->irq); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci rc = alloc_ring(dev); 168762306a36Sopenharmony_ci if (rc < 0) 168862306a36Sopenharmony_ci goto out_free_irq; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci rc = alloc_rbufs(dev); 169162306a36Sopenharmony_ci if (rc < 0) 169262306a36Sopenharmony_ci goto out_free_ring; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci alloc_tbufs(dev); 169562306a36Sopenharmony_ci enable_mmio(rp->pioaddr, rp->quirks); 169662306a36Sopenharmony_ci rhine_power_init(dev); 169762306a36Sopenharmony_ci rhine_chip_reset(dev); 169862306a36Sopenharmony_ci rhine_task_enable(rp); 169962306a36Sopenharmony_ci init_registers(dev); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n", 170262306a36Sopenharmony_ci __func__, ioread16(ioaddr + ChipCmd), 170362306a36Sopenharmony_ci mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci netif_start_queue(dev); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ciout: 170862306a36Sopenharmony_ci return rc; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ciout_free_ring: 171162306a36Sopenharmony_ci free_ring(dev); 171262306a36Sopenharmony_ciout_free_irq: 171362306a36Sopenharmony_ci free_irq(rp->irq, dev); 171462306a36Sopenharmony_ci goto out; 171562306a36Sopenharmony_ci} 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_cistatic void rhine_reset_task(struct work_struct *work) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci struct rhine_private *rp = container_of(work, struct rhine_private, 172062306a36Sopenharmony_ci reset_task); 172162306a36Sopenharmony_ci struct net_device *dev = rp->dev; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci if (!rp->task_enable) 172662306a36Sopenharmony_ci goto out_unlock; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci napi_disable(&rp->napi); 172962306a36Sopenharmony_ci netif_tx_disable(dev); 173062306a36Sopenharmony_ci spin_lock_bh(&rp->lock); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci /* clear all descriptors */ 173362306a36Sopenharmony_ci free_tbufs(dev); 173462306a36Sopenharmony_ci alloc_tbufs(dev); 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci rhine_reset_rbufs(rp); 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci /* Reinitialize the hardware. */ 173962306a36Sopenharmony_ci rhine_chip_reset(dev); 174062306a36Sopenharmony_ci init_registers(dev); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci spin_unlock_bh(&rp->lock); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 174562306a36Sopenharmony_ci dev->stats.tx_errors++; 174662306a36Sopenharmony_ci netif_wake_queue(dev); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ciout_unlock: 174962306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 175062306a36Sopenharmony_ci} 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_cistatic void rhine_tx_timeout(struct net_device *dev, unsigned int txqueue) 175362306a36Sopenharmony_ci{ 175462306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 175562306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n", 175862306a36Sopenharmony_ci ioread16(ioaddr + IntrStatus), 175962306a36Sopenharmony_ci mdio_read(dev, rp->mii_if.phy_id, MII_BMSR)); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci schedule_work(&rp->reset_task); 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic inline bool rhine_tx_queue_full(struct rhine_private *rp) 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci return (rp->cur_tx - rp->dirty_tx) >= TX_QUEUE_LEN; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic netdev_tx_t rhine_start_tx(struct sk_buff *skb, 177062306a36Sopenharmony_ci struct net_device *dev) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 177362306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 177462306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 177562306a36Sopenharmony_ci unsigned entry; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci /* Caution: the write order is important here, set the field 177862306a36Sopenharmony_ci with the "ownership" bits last. */ 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci /* Calculate the next Tx descriptor entry. */ 178162306a36Sopenharmony_ci entry = rp->cur_tx % TX_RING_SIZE; 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 178462306a36Sopenharmony_ci return NETDEV_TX_OK; 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci rp->tx_skbuff[entry] = skb; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci if ((rp->quirks & rqRhineI) && 178962306a36Sopenharmony_ci (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_PARTIAL)) { 179062306a36Sopenharmony_ci /* Must use alignment buffer. */ 179162306a36Sopenharmony_ci if (skb->len > PKT_BUF_SZ) { 179262306a36Sopenharmony_ci /* packet too long, drop it */ 179362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 179462306a36Sopenharmony_ci rp->tx_skbuff[entry] = NULL; 179562306a36Sopenharmony_ci dev->stats.tx_dropped++; 179662306a36Sopenharmony_ci return NETDEV_TX_OK; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci /* Padding is not copied and so must be redone. */ 180062306a36Sopenharmony_ci skb_copy_and_csum_dev(skb, rp->tx_buf[entry]); 180162306a36Sopenharmony_ci if (skb->len < ETH_ZLEN) 180262306a36Sopenharmony_ci memset(rp->tx_buf[entry] + skb->len, 0, 180362306a36Sopenharmony_ci ETH_ZLEN - skb->len); 180462306a36Sopenharmony_ci rp->tx_skbuff_dma[entry] = 0; 180562306a36Sopenharmony_ci rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_bufs_dma + 180662306a36Sopenharmony_ci (rp->tx_buf[entry] - 180762306a36Sopenharmony_ci rp->tx_bufs)); 180862306a36Sopenharmony_ci } else { 180962306a36Sopenharmony_ci rp->tx_skbuff_dma[entry] = 181062306a36Sopenharmony_ci dma_map_single(hwdev, skb->data, skb->len, 181162306a36Sopenharmony_ci DMA_TO_DEVICE); 181262306a36Sopenharmony_ci if (dma_mapping_error(hwdev, rp->tx_skbuff_dma[entry])) { 181362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 181462306a36Sopenharmony_ci rp->tx_skbuff_dma[entry] = 0; 181562306a36Sopenharmony_ci dev->stats.tx_dropped++; 181662306a36Sopenharmony_ci return NETDEV_TX_OK; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_skbuff_dma[entry]); 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci rp->tx_ring[entry].desc_length = 182262306a36Sopenharmony_ci cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci if (unlikely(skb_vlan_tag_present(skb))) { 182562306a36Sopenharmony_ci u16 vid_pcp = skb_vlan_tag_get(skb); 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci /* drop CFI/DEI bit, register needs VID and PCP */ 182862306a36Sopenharmony_ci vid_pcp = (vid_pcp & VLAN_VID_MASK) | 182962306a36Sopenharmony_ci ((vid_pcp & VLAN_PRIO_MASK) >> 1); 183062306a36Sopenharmony_ci rp->tx_ring[entry].tx_status = cpu_to_le32((vid_pcp) << 16); 183162306a36Sopenharmony_ci /* request tagging */ 183262306a36Sopenharmony_ci rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000); 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci else 183562306a36Sopenharmony_ci rp->tx_ring[entry].tx_status = 0; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci netdev_sent_queue(dev, skb->len); 183862306a36Sopenharmony_ci /* lock eth irq */ 183962306a36Sopenharmony_ci dma_wmb(); 184062306a36Sopenharmony_ci rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn); 184162306a36Sopenharmony_ci wmb(); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci rp->cur_tx++; 184462306a36Sopenharmony_ci /* 184562306a36Sopenharmony_ci * Nobody wants cur_tx write to rot for ages after the NIC will have 184662306a36Sopenharmony_ci * seen the transmit request, especially as the transmit completion 184762306a36Sopenharmony_ci * handler could miss it. 184862306a36Sopenharmony_ci */ 184962306a36Sopenharmony_ci smp_wmb(); 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* Non-x86 Todo: explicitly flush cache lines here. */ 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) 185462306a36Sopenharmony_ci /* Tx queues are bits 7-0 (first Tx queue: bit 7) */ 185562306a36Sopenharmony_ci BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci /* Wake the potentially-idle transmit channel */ 185862306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand, 185962306a36Sopenharmony_ci ioaddr + ChipCmd1); 186062306a36Sopenharmony_ci IOSYNC; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* dirty_tx may be pessimistically out-of-sync. See rhine_tx. */ 186362306a36Sopenharmony_ci if (rhine_tx_queue_full(rp)) { 186462306a36Sopenharmony_ci netif_stop_queue(dev); 186562306a36Sopenharmony_ci smp_rmb(); 186662306a36Sopenharmony_ci /* Rejuvenate. */ 186762306a36Sopenharmony_ci if (!rhine_tx_queue_full(rp)) 186862306a36Sopenharmony_ci netif_wake_queue(dev); 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n", 187262306a36Sopenharmony_ci rp->cur_tx - 1, entry); 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci return NETDEV_TX_OK; 187562306a36Sopenharmony_ci} 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_cistatic void rhine_irq_disable(struct rhine_private *rp) 187862306a36Sopenharmony_ci{ 187962306a36Sopenharmony_ci iowrite16(0x0000, rp->base + IntrEnable); 188062306a36Sopenharmony_ci} 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up 188362306a36Sopenharmony_ci after the Tx thread. */ 188462306a36Sopenharmony_cistatic irqreturn_t rhine_interrupt(int irq, void *dev_instance) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct net_device *dev = dev_instance; 188762306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 188862306a36Sopenharmony_ci u32 status; 188962306a36Sopenharmony_ci int handled = 0; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci status = rhine_get_events(rp); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status); 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci if (status & RHINE_EVENT) { 189662306a36Sopenharmony_ci handled = 1; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci rhine_irq_disable(rp); 189962306a36Sopenharmony_ci napi_schedule(&rp->napi); 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) { 190362306a36Sopenharmony_ci netif_err(rp, intr, dev, "Something Wicked happened! %08x\n", 190462306a36Sopenharmony_ci status); 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci return IRQ_RETVAL(handled); 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci/* This routine is logically part of the interrupt handler, but isolated 191162306a36Sopenharmony_ci for clarity. */ 191262306a36Sopenharmony_cistatic void rhine_tx(struct net_device *dev) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 191562306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 191662306a36Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 191762306a36Sopenharmony_ci unsigned int dirty_tx = rp->dirty_tx; 191862306a36Sopenharmony_ci unsigned int cur_tx; 191962306a36Sopenharmony_ci struct sk_buff *skb; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci /* 192262306a36Sopenharmony_ci * The race with rhine_start_tx does not matter here as long as the 192362306a36Sopenharmony_ci * driver enforces a value of cur_tx that was relevant when the 192462306a36Sopenharmony_ci * packet was scheduled to the network chipset. 192562306a36Sopenharmony_ci * Executive summary: smp_rmb() balances smp_wmb() in rhine_start_tx. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci smp_rmb(); 192862306a36Sopenharmony_ci cur_tx = rp->cur_tx; 192962306a36Sopenharmony_ci /* find and cleanup dirty tx descriptors */ 193062306a36Sopenharmony_ci while (dirty_tx != cur_tx) { 193162306a36Sopenharmony_ci unsigned int entry = dirty_tx % TX_RING_SIZE; 193262306a36Sopenharmony_ci u32 txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n", 193562306a36Sopenharmony_ci entry, txstatus); 193662306a36Sopenharmony_ci if (txstatus & DescOwn) 193762306a36Sopenharmony_ci break; 193862306a36Sopenharmony_ci skb = rp->tx_skbuff[entry]; 193962306a36Sopenharmony_ci if (txstatus & 0x8000) { 194062306a36Sopenharmony_ci netif_dbg(rp, tx_done, dev, 194162306a36Sopenharmony_ci "Transmit error, Tx status %08x\n", txstatus); 194262306a36Sopenharmony_ci dev->stats.tx_errors++; 194362306a36Sopenharmony_ci if (txstatus & 0x0400) 194462306a36Sopenharmony_ci dev->stats.tx_carrier_errors++; 194562306a36Sopenharmony_ci if (txstatus & 0x0200) 194662306a36Sopenharmony_ci dev->stats.tx_window_errors++; 194762306a36Sopenharmony_ci if (txstatus & 0x0100) 194862306a36Sopenharmony_ci dev->stats.tx_aborted_errors++; 194962306a36Sopenharmony_ci if (txstatus & 0x0080) 195062306a36Sopenharmony_ci dev->stats.tx_heartbeat_errors++; 195162306a36Sopenharmony_ci if (((rp->quirks & rqRhineI) && txstatus & 0x0002) || 195262306a36Sopenharmony_ci (txstatus & 0x0800) || (txstatus & 0x1000)) { 195362306a36Sopenharmony_ci dev->stats.tx_fifo_errors++; 195462306a36Sopenharmony_ci rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn); 195562306a36Sopenharmony_ci break; /* Keep the skb - we try again */ 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci /* Transmitter restarted in 'abnormal' handler. */ 195862306a36Sopenharmony_ci } else { 195962306a36Sopenharmony_ci if (rp->quirks & rqRhineI) 196062306a36Sopenharmony_ci dev->stats.collisions += (txstatus >> 3) & 0x0F; 196162306a36Sopenharmony_ci else 196262306a36Sopenharmony_ci dev->stats.collisions += txstatus & 0x0F; 196362306a36Sopenharmony_ci netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n", 196462306a36Sopenharmony_ci (txstatus >> 3) & 0xF, txstatus & 0xF); 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci u64_stats_update_begin(&rp->tx_stats.syncp); 196762306a36Sopenharmony_ci rp->tx_stats.bytes += skb->len; 196862306a36Sopenharmony_ci rp->tx_stats.packets++; 196962306a36Sopenharmony_ci u64_stats_update_end(&rp->tx_stats.syncp); 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci /* Free the original skb. */ 197262306a36Sopenharmony_ci if (rp->tx_skbuff_dma[entry]) { 197362306a36Sopenharmony_ci dma_unmap_single(hwdev, 197462306a36Sopenharmony_ci rp->tx_skbuff_dma[entry], 197562306a36Sopenharmony_ci skb->len, 197662306a36Sopenharmony_ci DMA_TO_DEVICE); 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci bytes_compl += skb->len; 197962306a36Sopenharmony_ci pkts_compl++; 198062306a36Sopenharmony_ci dev_consume_skb_any(skb); 198162306a36Sopenharmony_ci rp->tx_skbuff[entry] = NULL; 198262306a36Sopenharmony_ci dirty_tx++; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci rp->dirty_tx = dirty_tx; 198662306a36Sopenharmony_ci /* Pity we can't rely on the nearby BQL completion implicit barrier. */ 198762306a36Sopenharmony_ci smp_wmb(); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci netdev_completed_queue(dev, pkts_compl, bytes_compl); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci /* cur_tx may be optimistically out-of-sync. See rhine_start_tx. */ 199262306a36Sopenharmony_ci if (!rhine_tx_queue_full(rp) && netif_queue_stopped(dev)) { 199362306a36Sopenharmony_ci netif_wake_queue(dev); 199462306a36Sopenharmony_ci smp_rmb(); 199562306a36Sopenharmony_ci /* Rejuvenate. */ 199662306a36Sopenharmony_ci if (rhine_tx_queue_full(rp)) 199762306a36Sopenharmony_ci netif_stop_queue(dev); 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci/** 200262306a36Sopenharmony_ci * rhine_get_vlan_tci - extract TCI from Rx data buffer 200362306a36Sopenharmony_ci * @skb: pointer to sk_buff 200462306a36Sopenharmony_ci * @data_size: used data area of the buffer including CRC 200562306a36Sopenharmony_ci * 200662306a36Sopenharmony_ci * If hardware VLAN tag extraction is enabled and the chip indicates a 802.1Q 200762306a36Sopenharmony_ci * packet, the extracted 802.1Q header (2 bytes TPID + 2 bytes TCI) is 4-byte 200862306a36Sopenharmony_ci * aligned following the CRC. 200962306a36Sopenharmony_ci */ 201062306a36Sopenharmony_cistatic inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size) 201162306a36Sopenharmony_ci{ 201262306a36Sopenharmony_ci u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2; 201362306a36Sopenharmony_ci return be16_to_cpup((__be16 *)trailer); 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic inline void rhine_rx_vlan_tag(struct sk_buff *skb, struct rx_desc *desc, 201762306a36Sopenharmony_ci int data_size) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci dma_rmb(); 202062306a36Sopenharmony_ci if (unlikely(desc->desc_length & cpu_to_le32(DescTag))) { 202162306a36Sopenharmony_ci u16 vlan_tci; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci vlan_tci = rhine_get_vlan_tci(skb, data_size); 202462306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci} 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci/* Process up to limit frames from receive ring */ 202962306a36Sopenharmony_cistatic int rhine_rx(struct net_device *dev, int limit) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 203262306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 203362306a36Sopenharmony_ci int entry = rp->cur_rx % RX_RING_SIZE; 203462306a36Sopenharmony_ci int count; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__, 203762306a36Sopenharmony_ci entry, le32_to_cpu(rp->rx_ring[entry].rx_status)); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci /* If EOP is set on the next entry, it's a new packet. Send it up. */ 204062306a36Sopenharmony_ci for (count = 0; count < limit; ++count) { 204162306a36Sopenharmony_ci struct rx_desc *desc = rp->rx_ring + entry; 204262306a36Sopenharmony_ci u32 desc_status = le32_to_cpu(desc->rx_status); 204362306a36Sopenharmony_ci int data_size = desc_status >> 16; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci if (desc_status & DescOwn) 204662306a36Sopenharmony_ci break; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__, 204962306a36Sopenharmony_ci desc_status); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) { 205262306a36Sopenharmony_ci if ((desc_status & RxWholePkt) != RxWholePkt) { 205362306a36Sopenharmony_ci netdev_warn(dev, 205462306a36Sopenharmony_ci "Oversized Ethernet frame spanned multiple buffers, " 205562306a36Sopenharmony_ci "entry %#x length %d status %08x!\n", 205662306a36Sopenharmony_ci entry, data_size, 205762306a36Sopenharmony_ci desc_status); 205862306a36Sopenharmony_ci dev->stats.rx_length_errors++; 205962306a36Sopenharmony_ci } else if (desc_status & RxErr) { 206062306a36Sopenharmony_ci /* There was a error. */ 206162306a36Sopenharmony_ci netif_dbg(rp, rx_err, dev, 206262306a36Sopenharmony_ci "%s() Rx error %08x\n", __func__, 206362306a36Sopenharmony_ci desc_status); 206462306a36Sopenharmony_ci dev->stats.rx_errors++; 206562306a36Sopenharmony_ci if (desc_status & 0x0030) 206662306a36Sopenharmony_ci dev->stats.rx_length_errors++; 206762306a36Sopenharmony_ci if (desc_status & 0x0048) 206862306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 206962306a36Sopenharmony_ci if (desc_status & 0x0004) 207062306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 207162306a36Sopenharmony_ci if (desc_status & 0x0002) { 207262306a36Sopenharmony_ci /* this can also be updated outside the interrupt handler */ 207362306a36Sopenharmony_ci spin_lock(&rp->lock); 207462306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 207562306a36Sopenharmony_ci spin_unlock(&rp->lock); 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci } 207862306a36Sopenharmony_ci } else { 207962306a36Sopenharmony_ci /* Length should omit the CRC */ 208062306a36Sopenharmony_ci int pkt_len = data_size - 4; 208162306a36Sopenharmony_ci struct sk_buff *skb; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* Check if the packet is long enough to accept without 208462306a36Sopenharmony_ci copying to a minimally-sized skbuff. */ 208562306a36Sopenharmony_ci if (pkt_len < rx_copybreak) { 208662306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, pkt_len); 208762306a36Sopenharmony_ci if (unlikely(!skb)) 208862306a36Sopenharmony_ci goto drop; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci dma_sync_single_for_cpu(hwdev, 209162306a36Sopenharmony_ci rp->rx_skbuff_dma[entry], 209262306a36Sopenharmony_ci rp->rx_buf_sz, 209362306a36Sopenharmony_ci DMA_FROM_DEVICE); 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci skb_copy_to_linear_data(skb, 209662306a36Sopenharmony_ci rp->rx_skbuff[entry]->data, 209762306a36Sopenharmony_ci pkt_len); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci dma_sync_single_for_device(hwdev, 210062306a36Sopenharmony_ci rp->rx_skbuff_dma[entry], 210162306a36Sopenharmony_ci rp->rx_buf_sz, 210262306a36Sopenharmony_ci DMA_FROM_DEVICE); 210362306a36Sopenharmony_ci } else { 210462306a36Sopenharmony_ci struct rhine_skb_dma sd; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci if (unlikely(rhine_skb_dma_init(dev, &sd) < 0)) 210762306a36Sopenharmony_ci goto drop; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci skb = rp->rx_skbuff[entry]; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci dma_unmap_single(hwdev, 211262306a36Sopenharmony_ci rp->rx_skbuff_dma[entry], 211362306a36Sopenharmony_ci rp->rx_buf_sz, 211462306a36Sopenharmony_ci DMA_FROM_DEVICE); 211562306a36Sopenharmony_ci rhine_skb_dma_nic_store(rp, &sd, entry); 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci skb_put(skb, pkt_len); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci rhine_rx_vlan_tag(skb, desc, data_size); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci netif_receive_skb(skb); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci u64_stats_update_begin(&rp->rx_stats.syncp); 212762306a36Sopenharmony_ci rp->rx_stats.bytes += pkt_len; 212862306a36Sopenharmony_ci rp->rx_stats.packets++; 212962306a36Sopenharmony_ci u64_stats_update_end(&rp->rx_stats.syncp); 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_cigive_descriptor_to_nic: 213262306a36Sopenharmony_ci desc->rx_status = cpu_to_le32(DescOwn); 213362306a36Sopenharmony_ci entry = (++rp->cur_rx) % RX_RING_SIZE; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_ci return count; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cidrop: 213962306a36Sopenharmony_ci dev->stats.rx_dropped++; 214062306a36Sopenharmony_ci goto give_descriptor_to_nic; 214162306a36Sopenharmony_ci} 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_cistatic void rhine_restart_tx(struct net_device *dev) { 214462306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 214562306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 214662306a36Sopenharmony_ci int entry = rp->dirty_tx % TX_RING_SIZE; 214762306a36Sopenharmony_ci u32 intr_status; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci /* 215062306a36Sopenharmony_ci * If new errors occurred, we need to sort them out before doing Tx. 215162306a36Sopenharmony_ci * In that case the ISR will be back here RSN anyway. 215262306a36Sopenharmony_ci */ 215362306a36Sopenharmony_ci intr_status = rhine_get_events(rp); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci if ((intr_status & IntrTxErrSummary) == 0) { 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci /* We know better than the chip where it should continue. */ 215862306a36Sopenharmony_ci iowrite32(rp->tx_ring_dma + entry * sizeof(struct tx_desc), 215962306a36Sopenharmony_ci ioaddr + TxRingPtr); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ChipCmd) | CmdTxOn, 216262306a36Sopenharmony_ci ioaddr + ChipCmd); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci if (rp->tx_ring[entry].desc_length & cpu_to_le32(0x020000)) 216562306a36Sopenharmony_ci /* Tx queues are bits 7-0 (first Tx queue: bit 7) */ 216662306a36Sopenharmony_ci BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand, 216962306a36Sopenharmony_ci ioaddr + ChipCmd1); 217062306a36Sopenharmony_ci IOSYNC; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci else { 217362306a36Sopenharmony_ci /* This should never happen */ 217462306a36Sopenharmony_ci netif_warn(rp, tx_err, dev, "another error occurred %08x\n", 217562306a36Sopenharmony_ci intr_status); 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci} 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_cistatic void rhine_slow_event_task(struct work_struct *work) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct rhine_private *rp = 218362306a36Sopenharmony_ci container_of(work, struct rhine_private, slow_event_task); 218462306a36Sopenharmony_ci struct net_device *dev = rp->dev; 218562306a36Sopenharmony_ci u32 intr_status; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci if (!rp->task_enable) 219062306a36Sopenharmony_ci goto out_unlock; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci intr_status = rhine_get_events(rp); 219362306a36Sopenharmony_ci rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW); 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (intr_status & IntrLinkChange) 219662306a36Sopenharmony_ci rhine_check_media(dev, 0); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (intr_status & IntrPCIErr) 219962306a36Sopenharmony_ci netif_warn(rp, hw, dev, "PCI error\n"); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ciout_unlock: 220462306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 220562306a36Sopenharmony_ci} 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_cistatic void 220862306a36Sopenharmony_cirhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 220962306a36Sopenharmony_ci{ 221062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 221162306a36Sopenharmony_ci unsigned int start; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci spin_lock_bh(&rp->lock); 221462306a36Sopenharmony_ci rhine_update_rx_crc_and_missed_errord(rp); 221562306a36Sopenharmony_ci spin_unlock_bh(&rp->lock); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci do { 222062306a36Sopenharmony_ci start = u64_stats_fetch_begin(&rp->rx_stats.syncp); 222162306a36Sopenharmony_ci stats->rx_packets = rp->rx_stats.packets; 222262306a36Sopenharmony_ci stats->rx_bytes = rp->rx_stats.bytes; 222362306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&rp->rx_stats.syncp, start)); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci do { 222662306a36Sopenharmony_ci start = u64_stats_fetch_begin(&rp->tx_stats.syncp); 222762306a36Sopenharmony_ci stats->tx_packets = rp->tx_stats.packets; 222862306a36Sopenharmony_ci stats->tx_bytes = rp->tx_stats.bytes; 222962306a36Sopenharmony_ci } while (u64_stats_fetch_retry(&rp->tx_stats.syncp, start)); 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic void rhine_set_rx_mode(struct net_device *dev) 223362306a36Sopenharmony_ci{ 223462306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 223562306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 223662306a36Sopenharmony_ci u32 mc_filter[2]; /* Multicast hash filter */ 223762306a36Sopenharmony_ci u8 rx_mode = 0x0C; /* Note: 0x02=accept runt, 0x01=accept errs */ 223862306a36Sopenharmony_ci struct netdev_hw_addr *ha; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 224162306a36Sopenharmony_ci rx_mode = 0x1C; 224262306a36Sopenharmony_ci iowrite32(0xffffffff, ioaddr + MulticastFilter0); 224362306a36Sopenharmony_ci iowrite32(0xffffffff, ioaddr + MulticastFilter1); 224462306a36Sopenharmony_ci } else if ((netdev_mc_count(dev) > multicast_filter_limit) || 224562306a36Sopenharmony_ci (dev->flags & IFF_ALLMULTI)) { 224662306a36Sopenharmony_ci /* Too many to match, or accept all multicasts. */ 224762306a36Sopenharmony_ci iowrite32(0xffffffff, ioaddr + MulticastFilter0); 224862306a36Sopenharmony_ci iowrite32(0xffffffff, ioaddr + MulticastFilter1); 224962306a36Sopenharmony_ci } else if (rp->quirks & rqMgmt) { 225062306a36Sopenharmony_ci int i = 0; 225162306a36Sopenharmony_ci u32 mCAMmask = 0; /* 32 mCAMs (6105M and better) */ 225262306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 225362306a36Sopenharmony_ci if (i == MCAM_SIZE) 225462306a36Sopenharmony_ci break; 225562306a36Sopenharmony_ci rhine_set_cam(ioaddr, i, ha->addr); 225662306a36Sopenharmony_ci mCAMmask |= 1 << i; 225762306a36Sopenharmony_ci i++; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci rhine_set_cam_mask(ioaddr, mCAMmask); 226062306a36Sopenharmony_ci } else { 226162306a36Sopenharmony_ci memset(mc_filter, 0, sizeof(mc_filter)); 226262306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 226362306a36Sopenharmony_ci int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci iowrite32(mc_filter[0], ioaddr + MulticastFilter0); 226862306a36Sopenharmony_ci iowrite32(mc_filter[1], ioaddr + MulticastFilter1); 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci /* enable/disable VLAN receive filtering */ 227162306a36Sopenharmony_ci if (rp->quirks & rqMgmt) { 227262306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 227362306a36Sopenharmony_ci BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1); 227462306a36Sopenharmony_ci else 227562306a36Sopenharmony_ci BYTE_REG_BITS_ON(BCR1_VIDFR, ioaddr + PCIBusConfig1); 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci BYTE_REG_BITS_ON(rx_mode, ioaddr + RxConfig); 227862306a36Sopenharmony_ci} 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 228162306a36Sopenharmony_ci{ 228262306a36Sopenharmony_ci struct device *hwdev = dev->dev.parent; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 228562306a36Sopenharmony_ci strscpy(info->bus_info, dev_name(hwdev), sizeof(info->bus_info)); 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_cistatic int netdev_get_link_ksettings(struct net_device *dev, 228962306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 229462306a36Sopenharmony_ci mii_ethtool_get_link_ksettings(&rp->mii_if, cmd); 229562306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci return 0; 229862306a36Sopenharmony_ci} 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_cistatic int netdev_set_link_ksettings(struct net_device *dev, 230162306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 230262306a36Sopenharmony_ci{ 230362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 230462306a36Sopenharmony_ci int rc; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 230762306a36Sopenharmony_ci rc = mii_ethtool_set_link_ksettings(&rp->mii_if, cmd); 230862306a36Sopenharmony_ci rhine_set_carrier(&rp->mii_if); 230962306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci return rc; 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cistatic int netdev_nway_reset(struct net_device *dev) 231562306a36Sopenharmony_ci{ 231662306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci return mii_nway_restart(&rp->mii_if); 231962306a36Sopenharmony_ci} 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_cistatic u32 netdev_get_link(struct net_device *dev) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci return mii_link_ok(&rp->mii_if); 232662306a36Sopenharmony_ci} 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_cistatic u32 netdev_get_msglevel(struct net_device *dev) 232962306a36Sopenharmony_ci{ 233062306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci return rp->msg_enable; 233362306a36Sopenharmony_ci} 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_cistatic void netdev_set_msglevel(struct net_device *dev, u32 value) 233662306a36Sopenharmony_ci{ 233762306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci rp->msg_enable = value; 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_cistatic void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci if (!(rp->quirks & rqWOL)) 234762306a36Sopenharmony_ci return; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci spin_lock_irq(&rp->lock); 235062306a36Sopenharmony_ci wol->supported = WAKE_PHY | WAKE_MAGIC | 235162306a36Sopenharmony_ci WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ 235262306a36Sopenharmony_ci wol->wolopts = rp->wolopts; 235362306a36Sopenharmony_ci spin_unlock_irq(&rp->lock); 235462306a36Sopenharmony_ci} 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_cistatic int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 235762306a36Sopenharmony_ci{ 235862306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 235962306a36Sopenharmony_ci u32 support = WAKE_PHY | WAKE_MAGIC | 236062306a36Sopenharmony_ci WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; /* Untested */ 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci if (!(rp->quirks & rqWOL)) 236362306a36Sopenharmony_ci return -EINVAL; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci if (wol->wolopts & ~support) 236662306a36Sopenharmony_ci return -EINVAL; 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci spin_lock_irq(&rp->lock); 236962306a36Sopenharmony_ci rp->wolopts = wol->wolopts; 237062306a36Sopenharmony_ci spin_unlock_irq(&rp->lock); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci return 0; 237362306a36Sopenharmony_ci} 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 237662306a36Sopenharmony_ci .get_drvinfo = netdev_get_drvinfo, 237762306a36Sopenharmony_ci .nway_reset = netdev_nway_reset, 237862306a36Sopenharmony_ci .get_link = netdev_get_link, 237962306a36Sopenharmony_ci .get_msglevel = netdev_get_msglevel, 238062306a36Sopenharmony_ci .set_msglevel = netdev_set_msglevel, 238162306a36Sopenharmony_ci .get_wol = rhine_get_wol, 238262306a36Sopenharmony_ci .set_wol = rhine_set_wol, 238362306a36Sopenharmony_ci .get_link_ksettings = netdev_get_link_ksettings, 238462306a36Sopenharmony_ci .set_link_ksettings = netdev_set_link_ksettings, 238562306a36Sopenharmony_ci}; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 238862306a36Sopenharmony_ci{ 238962306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 239062306a36Sopenharmony_ci int rc; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (!netif_running(dev)) 239362306a36Sopenharmony_ci return -EINVAL; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci mutex_lock(&rp->task_lock); 239662306a36Sopenharmony_ci rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL); 239762306a36Sopenharmony_ci rhine_set_carrier(&rp->mii_if); 239862306a36Sopenharmony_ci mutex_unlock(&rp->task_lock); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci return rc; 240162306a36Sopenharmony_ci} 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_cistatic int rhine_close(struct net_device *dev) 240462306a36Sopenharmony_ci{ 240562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 240662306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci rhine_task_disable(rp); 240962306a36Sopenharmony_ci napi_disable(&rp->napi); 241062306a36Sopenharmony_ci netif_stop_queue(dev); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n", 241362306a36Sopenharmony_ci ioread16(ioaddr + ChipCmd)); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci /* Switch to loopback mode to avoid hardware races. */ 241662306a36Sopenharmony_ci iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig); 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci rhine_irq_disable(rp); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci /* Stop the chip's Tx and Rx processes. */ 242162306a36Sopenharmony_ci iowrite16(CmdStop, ioaddr + ChipCmd); 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci free_irq(rp->irq, dev); 242462306a36Sopenharmony_ci free_rbufs(dev); 242562306a36Sopenharmony_ci free_tbufs(dev); 242662306a36Sopenharmony_ci free_ring(dev); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci return 0; 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic void rhine_remove_one_pci(struct pci_dev *pdev) 243362306a36Sopenharmony_ci{ 243462306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 243562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci unregister_netdev(dev); 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci pci_iounmap(pdev, rp->base); 244062306a36Sopenharmony_ci pci_release_regions(pdev); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci free_netdev(dev); 244362306a36Sopenharmony_ci pci_disable_device(pdev); 244462306a36Sopenharmony_ci} 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_cistatic int rhine_remove_one_platform(struct platform_device *pdev) 244762306a36Sopenharmony_ci{ 244862306a36Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 244962306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci unregister_netdev(dev); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci iounmap(rp->base); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci free_netdev(dev); 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci return 0; 245862306a36Sopenharmony_ci} 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_cistatic void rhine_shutdown_pci(struct pci_dev *pdev) 246162306a36Sopenharmony_ci{ 246262306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 246362306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 246462306a36Sopenharmony_ci void __iomem *ioaddr = rp->base; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (!(rp->quirks & rqWOL)) 246762306a36Sopenharmony_ci return; /* Nothing to do for non-WOL adapters */ 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci rhine_power_init(dev); 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci /* Make sure we use pattern 0, 1 and not 4, 5 */ 247262306a36Sopenharmony_ci if (rp->quirks & rq6patterns) 247362306a36Sopenharmony_ci iowrite8(0x04, ioaddr + WOLcgClr); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci spin_lock(&rp->lock); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci if (rp->wolopts & WAKE_MAGIC) { 247862306a36Sopenharmony_ci iowrite8(WOLmagic, ioaddr + WOLcrSet); 247962306a36Sopenharmony_ci /* 248062306a36Sopenharmony_ci * Turn EEPROM-controlled wake-up back on -- some hardware may 248162306a36Sopenharmony_ci * not cooperate otherwise. 248262306a36Sopenharmony_ci */ 248362306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + ConfigA) | 0x03, ioaddr + ConfigA); 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST)) 248762306a36Sopenharmony_ci iowrite8(WOLbmcast, ioaddr + WOLcgSet); 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci if (rp->wolopts & WAKE_PHY) 249062306a36Sopenharmony_ci iowrite8(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci if (rp->wolopts & WAKE_UCAST) 249362306a36Sopenharmony_ci iowrite8(WOLucast, ioaddr + WOLcrSet); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci if (rp->wolopts) { 249662306a36Sopenharmony_ci /* Enable legacy WOL (for old motherboards) */ 249762306a36Sopenharmony_ci iowrite8(0x01, ioaddr + PwcfgSet); 249862306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW); 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci spin_unlock(&rp->lock); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF && !avoid_D3) { 250462306a36Sopenharmony_ci iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci pci_wake_from_d3(pdev, true); 250762306a36Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 251262306a36Sopenharmony_cistatic int rhine_suspend(struct device *device) 251362306a36Sopenharmony_ci{ 251462306a36Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 251562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (!netif_running(dev)) 251862306a36Sopenharmony_ci return 0; 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci rhine_task_disable(rp); 252162306a36Sopenharmony_ci rhine_irq_disable(rp); 252262306a36Sopenharmony_ci napi_disable(&rp->napi); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci netif_device_detach(dev); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (dev_is_pci(device)) 252762306a36Sopenharmony_ci rhine_shutdown_pci(to_pci_dev(device)); 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci return 0; 253062306a36Sopenharmony_ci} 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_cistatic int rhine_resume(struct device *device) 253362306a36Sopenharmony_ci{ 253462306a36Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 253562306a36Sopenharmony_ci struct rhine_private *rp = netdev_priv(dev); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (!netif_running(dev)) 253862306a36Sopenharmony_ci return 0; 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci enable_mmio(rp->pioaddr, rp->quirks); 254162306a36Sopenharmony_ci rhine_power_init(dev); 254262306a36Sopenharmony_ci free_tbufs(dev); 254362306a36Sopenharmony_ci alloc_tbufs(dev); 254462306a36Sopenharmony_ci rhine_reset_rbufs(rp); 254562306a36Sopenharmony_ci rhine_task_enable(rp); 254662306a36Sopenharmony_ci spin_lock_bh(&rp->lock); 254762306a36Sopenharmony_ci init_registers(dev); 254862306a36Sopenharmony_ci spin_unlock_bh(&rp->lock); 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci netif_device_attach(dev); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci return 0; 255362306a36Sopenharmony_ci} 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume); 255662306a36Sopenharmony_ci#define RHINE_PM_OPS (&rhine_pm_ops) 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci#else 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci#define RHINE_PM_OPS NULL 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci#endif /* !CONFIG_PM_SLEEP */ 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_cistatic struct pci_driver rhine_driver_pci = { 256562306a36Sopenharmony_ci .name = DRV_NAME, 256662306a36Sopenharmony_ci .id_table = rhine_pci_tbl, 256762306a36Sopenharmony_ci .probe = rhine_init_one_pci, 256862306a36Sopenharmony_ci .remove = rhine_remove_one_pci, 256962306a36Sopenharmony_ci .shutdown = rhine_shutdown_pci, 257062306a36Sopenharmony_ci .driver.pm = RHINE_PM_OPS, 257162306a36Sopenharmony_ci}; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic struct platform_driver rhine_driver_platform = { 257462306a36Sopenharmony_ci .probe = rhine_init_one_platform, 257562306a36Sopenharmony_ci .remove = rhine_remove_one_platform, 257662306a36Sopenharmony_ci .driver = { 257762306a36Sopenharmony_ci .name = DRV_NAME, 257862306a36Sopenharmony_ci .of_match_table = rhine_of_tbl, 257962306a36Sopenharmony_ci .pm = RHINE_PM_OPS, 258062306a36Sopenharmony_ci } 258162306a36Sopenharmony_ci}; 258262306a36Sopenharmony_ci 258362306a36Sopenharmony_cistatic const struct dmi_system_id rhine_dmi_table[] __initconst = { 258462306a36Sopenharmony_ci { 258562306a36Sopenharmony_ci .ident = "EPIA-M", 258662306a36Sopenharmony_ci .matches = { 258762306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."), 258862306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"), 258962306a36Sopenharmony_ci }, 259062306a36Sopenharmony_ci }, 259162306a36Sopenharmony_ci { 259262306a36Sopenharmony_ci .ident = "KV7", 259362306a36Sopenharmony_ci .matches = { 259462306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), 259562306a36Sopenharmony_ci DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"), 259662306a36Sopenharmony_ci }, 259762306a36Sopenharmony_ci }, 259862306a36Sopenharmony_ci { NULL } 259962306a36Sopenharmony_ci}; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_cistatic int __init rhine_init(void) 260262306a36Sopenharmony_ci{ 260362306a36Sopenharmony_ci int ret_pci, ret_platform; 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci/* when a module, this is printed whether or not devices are found in probe */ 260662306a36Sopenharmony_ci if (dmi_check_system(rhine_dmi_table)) { 260762306a36Sopenharmony_ci /* these BIOSes fail at PXE boot if chip is in D3 */ 260862306a36Sopenharmony_ci avoid_D3 = true; 260962306a36Sopenharmony_ci pr_warn("Broken BIOS detected, avoid_D3 enabled\n"); 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci else if (avoid_D3) 261262306a36Sopenharmony_ci pr_info("avoid_D3 set\n"); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci ret_pci = pci_register_driver(&rhine_driver_pci); 261562306a36Sopenharmony_ci ret_platform = platform_driver_register(&rhine_driver_platform); 261662306a36Sopenharmony_ci if ((ret_pci < 0) && (ret_platform < 0)) 261762306a36Sopenharmony_ci return ret_pci; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci return 0; 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_cistatic void __exit rhine_cleanup(void) 262462306a36Sopenharmony_ci{ 262562306a36Sopenharmony_ci platform_driver_unregister(&rhine_driver_platform); 262662306a36Sopenharmony_ci pci_unregister_driver(&rhine_driver_pci); 262762306a36Sopenharmony_ci} 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_cimodule_init(rhine_init); 263162306a36Sopenharmony_cimodule_exit(rhine_cleanup); 2632