18c2ecf20Sopenharmony_ci/* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci	Written 1998-2001 by Donald Becker.
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci	Current Maintainer: Kevin Brace <kevinbrace@bracecomputerlab.com>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci	This software may be used and distributed according to the terms of
88c2ecf20Sopenharmony_ci	the GNU General Public License (GPL), incorporated herein by reference.
98c2ecf20Sopenharmony_ci	Drivers based on or derived from this code fall under the GPL and must
108c2ecf20Sopenharmony_ci	retain the authorship, copyright and license notice.  This file is not
118c2ecf20Sopenharmony_ci	a complete program and may only be used when the entire operating
128c2ecf20Sopenharmony_ci	system is licensed under the GPL.
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	This driver is designed for the VIA VT86C100A Rhine-I.
158c2ecf20Sopenharmony_ci	It also works with the Rhine-II (6102) and Rhine-III (6105/6105L/6105LOM
168c2ecf20Sopenharmony_ci	and management NIC 6105M).
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	The author may be reached as becker@scyld.com, or C/O
198c2ecf20Sopenharmony_ci	Scyld Computing Corporation
208c2ecf20Sopenharmony_ci	410 Severn Ave., Suite 210
218c2ecf20Sopenharmony_ci	Annapolis MD 21403
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	This driver contains some changes from the original Donald Becker
258c2ecf20Sopenharmony_ci	version. He may or may not be interested in bug reports on this
268c2ecf20Sopenharmony_ci	code. You can find his versions at:
278c2ecf20Sopenharmony_ci	http://www.scyld.com/network/via-rhine.html
288c2ecf20Sopenharmony_ci	[link no longer provides useful info -jgarzik]
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci*/
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define DRV_NAME	"via-rhine"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#include <linux/types.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* A few user-configurable values.
398c2ecf20Sopenharmony_ci   These may be modified when a driver module is loaded. */
408c2ecf20Sopenharmony_cistatic int debug = 0;
418c2ecf20Sopenharmony_ci#define RHINE_MSG_DEFAULT \
428c2ecf20Sopenharmony_ci        (0x0000)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
458c2ecf20Sopenharmony_ci   Setting to > 1518 effectively disables this feature. */
468c2ecf20Sopenharmony_ci#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \
478c2ecf20Sopenharmony_ci	defined(CONFIG_SPARC) || defined(__ia64__) ||		   \
488c2ecf20Sopenharmony_ci	defined(__sh__) || defined(__mips__)
498c2ecf20Sopenharmony_cistatic int rx_copybreak = 1518;
508c2ecf20Sopenharmony_ci#else
518c2ecf20Sopenharmony_cistatic int rx_copybreak;
528c2ecf20Sopenharmony_ci#endif
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Work-around for broken BIOSes: they are unable to get the chip back out of
558c2ecf20Sopenharmony_ci   power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */
568c2ecf20Sopenharmony_cistatic bool avoid_D3;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * In case you are looking for 'options[]' or 'full_duplex[]', they
608c2ecf20Sopenharmony_ci * are gone. Use ethtool(8) instead.
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
648c2ecf20Sopenharmony_ci   The Rhine has a 64 element 8390-like hash table. */
658c2ecf20Sopenharmony_cistatic const int multicast_filter_limit = 32;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* Operational parameters that are set at compile time. */
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* Keep the ring sizes a power of two for compile efficiency.
718c2ecf20Sopenharmony_ci * The compiler will convert <unsigned>'%'<2^N> into a bit mask.
728c2ecf20Sopenharmony_ci * Making the Tx ring too large decreases the effectiveness of channel
738c2ecf20Sopenharmony_ci * bonding and packet priority.
748c2ecf20Sopenharmony_ci * With BQL support, we can increase TX ring safely.
758c2ecf20Sopenharmony_ci * There are no ill effects from too-large receive rings.
768c2ecf20Sopenharmony_ci */
778c2ecf20Sopenharmony_ci#define TX_RING_SIZE	64
788c2ecf20Sopenharmony_ci#define TX_QUEUE_LEN	(TX_RING_SIZE - 6)	/* Limit ring entries actually used. */
798c2ecf20Sopenharmony_ci#define RX_RING_SIZE	64
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* Operational parameters that usually are not changed. */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */
848c2ecf20Sopenharmony_ci#define TX_TIMEOUT	(2*HZ)
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#define PKT_BUF_SZ	1536	/* Size of each temporary Rx buffer.*/
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#include <linux/module.h>
898c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
908c2ecf20Sopenharmony_ci#include <linux/kernel.h>
918c2ecf20Sopenharmony_ci#include <linux/string.h>
928c2ecf20Sopenharmony_ci#include <linux/timer.h>
938c2ecf20Sopenharmony_ci#include <linux/errno.h>
948c2ecf20Sopenharmony_ci#include <linux/ioport.h>
958c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
968c2ecf20Sopenharmony_ci#include <linux/pci.h>
978c2ecf20Sopenharmony_ci#include <linux/of_device.h>
988c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
998c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
1008c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
1018c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
1028c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
1038c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
1048c2ecf20Sopenharmony_ci#include <linux/init.h>
1058c2ecf20Sopenharmony_ci#include <linux/delay.h>
1068c2ecf20Sopenharmony_ci#include <linux/mii.h>
1078c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
1088c2ecf20Sopenharmony_ci#include <linux/crc32.h>
1098c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
1108c2ecf20Sopenharmony_ci#include <linux/bitops.h>
1118c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
1128c2ecf20Sopenharmony_ci#include <asm/processor.h>	/* Processor type for cache alignment. */
1138c2ecf20Sopenharmony_ci#include <asm/io.h>
1148c2ecf20Sopenharmony_ci#include <asm/irq.h>
1158c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
1168c2ecf20Sopenharmony_ci#include <linux/dmi.h>
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Donald Becker <becker@scyld.com>");
1198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
1208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cimodule_param(debug, int, 0);
1238c2ecf20Sopenharmony_cimodule_param(rx_copybreak, int, 0);
1248c2ecf20Sopenharmony_cimodule_param(avoid_D3, bool, 0);
1258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "VIA Rhine debug message flags");
1268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
1278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#define MCAM_SIZE	32
1308c2ecf20Sopenharmony_ci#define VCAM_SIZE	32
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/*
1338c2ecf20Sopenharmony_ci		Theory of Operation
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ciI. Board Compatibility
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciThis driver is designed for the VIA 86c100A Rhine-II PCI Fast Ethernet
1388c2ecf20Sopenharmony_cicontroller.
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ciII. Board-specific settings
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciBoards with this chip are functional only in a bus-master PCI slot.
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciMany operational settings are loaded from the EEPROM to the Config word at
1458c2ecf20Sopenharmony_cioffset 0x78. For most of these settings, this driver assumes that they are
1468c2ecf20Sopenharmony_cicorrect.
1478c2ecf20Sopenharmony_ciIf this driver is compiled to use PCI memory space operations the EEPROM
1488c2ecf20Sopenharmony_cimust be configured to enable memory ops.
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ciIII. Driver operation
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ciIIIa. Ring buffers
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciThis driver uses two statically allocated fixed-size descriptor lists
1558c2ecf20Sopenharmony_ciformed into rings by a branch from the final descriptor to the beginning of
1568c2ecf20Sopenharmony_cithe list. The ring sizes are set at compile time by RX/TX_RING_SIZE.
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ciIIIb/c. Transmit/Receive Structure
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ciThis driver attempts to use a zero-copy receive and transmit scheme.
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciAlas, all data buffers are required to start on a 32 bit boundary, so
1638c2ecf20Sopenharmony_cithe driver must often copy transmit packets into bounce buffers.
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciThe driver allocates full frame size skbuffs for the Rx ring buffers at
1668c2ecf20Sopenharmony_ciopen() time and passes the skb->data field to the chip as receive data
1678c2ecf20Sopenharmony_cibuffers. When an incoming frame is less than RX_COPYBREAK bytes long,
1688c2ecf20Sopenharmony_cia fresh skbuff is allocated and the frame is copied to the new skbuff.
1698c2ecf20Sopenharmony_ciWhen the incoming frame is larger, the skbuff is passed directly up the
1708c2ecf20Sopenharmony_ciprotocol stack. Buffers consumed this way are replaced by newly allocated
1718c2ecf20Sopenharmony_ciskbuffs in the last phase of rhine_rx().
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ciThe RX_COPYBREAK value is chosen to trade-off the memory wasted by
1748c2ecf20Sopenharmony_ciusing a full-sized skbuff for small frames vs. the copying costs of larger
1758c2ecf20Sopenharmony_ciframes. New boards are typically used in generously configured machines
1768c2ecf20Sopenharmony_ciand the underfilled buffers have negligible impact compared to the benefit of
1778c2ecf20Sopenharmony_cia single allocation size, so the default value of zero results in never
1788c2ecf20Sopenharmony_cicopying packets. When copying is done, the cost is usually mitigated by using
1798c2ecf20Sopenharmony_cia combined copy/checksum routine. Copying also preloads the cache, which is
1808c2ecf20Sopenharmony_cimost useful with small frames.
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciSince the VIA chips are only able to transfer data to buffers on 32 bit
1838c2ecf20Sopenharmony_ciboundaries, the IP header at offset 14 in an ethernet frame isn't
1848c2ecf20Sopenharmony_cilongword aligned for further processing. Copying these unaligned buffers
1858c2ecf20Sopenharmony_cihas the beneficial effect of 16-byte aligning the IP header.
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ciIIId. Synchronization
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciThe driver runs as two independent, single-threaded flows of control. One
1908c2ecf20Sopenharmony_ciis the send-packet routine, which enforces single-threaded use by the
1918c2ecf20Sopenharmony_cinetdev_priv(dev)->lock spinlock. The other thread is the interrupt handler,
1928c2ecf20Sopenharmony_ciwhich is single threaded by the hardware and interrupt handling software.
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciThe send packet thread has partial control over the Tx ring. It locks the
1958c2ecf20Sopenharmony_cinetdev_priv(dev)->lock whenever it's queuing a Tx packet. If the next slot in
1968c2ecf20Sopenharmony_cithe ring is not available it stops the transmit queue by
1978c2ecf20Sopenharmony_cicalling netif_stop_queue.
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ciThe interrupt handler has exclusive control over the Rx ring and records stats
2008c2ecf20Sopenharmony_cifrom the Tx ring. After reaping the stats, it marks the Tx queue entry as
2018c2ecf20Sopenharmony_ciempty by incrementing the dirty_tx mark. If at least half of the entries in
2028c2ecf20Sopenharmony_cithe Rx ring are available the transmit queue is woken up if it was stopped.
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ciIV. Notes
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciIVb. References
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ciPreliminary VT86C100A manual from http://www.via.com.tw/
2098c2ecf20Sopenharmony_cihttp://www.scyld.com/expert/100mbps.html
2108c2ecf20Sopenharmony_cihttp://www.scyld.com/expert/NWay.html
2118c2ecf20Sopenharmony_ciftp://ftp.via.com.tw/public/lan/Products/NIC/VT86C100A/Datasheet/VT86C100A03.pdf
2128c2ecf20Sopenharmony_ciftp://ftp.via.com.tw/public/lan/Products/NIC/VT6102/Datasheet/VT6102_021.PDF
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciIVc. Errata
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciThe VT86C100A manual is not reliable information.
2188c2ecf20Sopenharmony_ciThe 3043 chip does not handle unaligned transmit or receive buffers, resulting
2198c2ecf20Sopenharmony_ciin significant performance degradation for bounce buffer copies on transmit
2208c2ecf20Sopenharmony_ciand unaligned IP headers on receive.
2218c2ecf20Sopenharmony_ciThe chip does not pad to minimum transmit length.
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci*/
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci/* This table drives the PCI probe routines. It's mostly boilerplate in all
2278c2ecf20Sopenharmony_ci   of the drivers, and will likely be provided by some future kernel.
2288c2ecf20Sopenharmony_ci   Note the matching code -- the first table entry matchs all 56** cards but
2298c2ecf20Sopenharmony_ci   second only the 1234 card.
2308c2ecf20Sopenharmony_ci*/
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cienum rhine_revs {
2338c2ecf20Sopenharmony_ci	VT86C100A	= 0x00,
2348c2ecf20Sopenharmony_ci	VTunknown0	= 0x20,
2358c2ecf20Sopenharmony_ci	VT6102		= 0x40,
2368c2ecf20Sopenharmony_ci	VT8231		= 0x50,	/* Integrated MAC */
2378c2ecf20Sopenharmony_ci	VT8233		= 0x60,	/* Integrated MAC */
2388c2ecf20Sopenharmony_ci	VT8235		= 0x74,	/* Integrated MAC */
2398c2ecf20Sopenharmony_ci	VT8237		= 0x78,	/* Integrated MAC */
2408c2ecf20Sopenharmony_ci	VT8251		= 0x7C,	/* Integrated MAC */
2418c2ecf20Sopenharmony_ci	VT6105		= 0x80,
2428c2ecf20Sopenharmony_ci	VT6105_B0	= 0x83,
2438c2ecf20Sopenharmony_ci	VT6105L		= 0x8A,
2448c2ecf20Sopenharmony_ci	VT6107		= 0x8C,
2458c2ecf20Sopenharmony_ci	VTunknown2	= 0x8E,
2468c2ecf20Sopenharmony_ci	VT6105M		= 0x90,	/* Management adapter */
2478c2ecf20Sopenharmony_ci};
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cienum rhine_quirks {
2508c2ecf20Sopenharmony_ci	rqWOL		= 0x0001,	/* Wake-On-LAN support */
2518c2ecf20Sopenharmony_ci	rqForceReset	= 0x0002,
2528c2ecf20Sopenharmony_ci	rq6patterns	= 0x0040,	/* 6 instead of 4 patterns for WOL */
2538c2ecf20Sopenharmony_ci	rqStatusWBRace	= 0x0080,	/* Tx Status Writeback Error possible */
2548c2ecf20Sopenharmony_ci	rqRhineI	= 0x0100,	/* See comment below */
2558c2ecf20Sopenharmony_ci	rqIntPHY	= 0x0200,	/* Integrated PHY */
2568c2ecf20Sopenharmony_ci	rqMgmt		= 0x0400,	/* Management adapter */
2578c2ecf20Sopenharmony_ci	rqNeedEnMMIO	= 0x0800,	/* Whether the core needs to be
2588c2ecf20Sopenharmony_ci					 * switched from PIO mode to MMIO
2598c2ecf20Sopenharmony_ci					 * (only applies to PCI)
2608c2ecf20Sopenharmony_ci					 */
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci/*
2638c2ecf20Sopenharmony_ci * rqRhineI: VT86C100A (aka Rhine-I) uses different bits to enable
2648c2ecf20Sopenharmony_ci * MMIO as well as for the collision counter and the Tx FIFO underflow
2658c2ecf20Sopenharmony_ci * indicator. In addition, Tx and Rx buffers need to 4 byte aligned.
2668c2ecf20Sopenharmony_ci */
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/* Beware of PCI posted writes */
2698c2ecf20Sopenharmony_ci#define IOSYNC	do { ioread8(ioaddr + StationAddr); } while (0)
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic const struct pci_device_id rhine_pci_tbl[] = {
2728c2ecf20Sopenharmony_ci	{ 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, },	/* VT86C100A */
2738c2ecf20Sopenharmony_ci	{ 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, },	/* VT6102 */
2748c2ecf20Sopenharmony_ci	{ 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, },	/* 6105{,L,LOM} */
2758c2ecf20Sopenharmony_ci	{ 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, },	/* VT6105M */
2768c2ecf20Sopenharmony_ci	{ }	/* terminate list */
2778c2ecf20Sopenharmony_ci};
2788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/* OpenFirmware identifiers for platform-bus devices
2818c2ecf20Sopenharmony_ci * The .data field is currently only used to store quirks
2828c2ecf20Sopenharmony_ci */
2838c2ecf20Sopenharmony_cistatic u32 vt8500_quirks = rqWOL | rqForceReset | rq6patterns;
2848c2ecf20Sopenharmony_cistatic const struct of_device_id rhine_of_tbl[] = {
2858c2ecf20Sopenharmony_ci	{ .compatible = "via,vt8500-rhine", .data = &vt8500_quirks },
2868c2ecf20Sopenharmony_ci	{ }	/* terminate list */
2878c2ecf20Sopenharmony_ci};
2888c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rhine_of_tbl);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* Offsets to the device registers. */
2918c2ecf20Sopenharmony_cienum register_offsets {
2928c2ecf20Sopenharmony_ci	StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
2938c2ecf20Sopenharmony_ci	ChipCmd1=0x09, TQWake=0x0A,
2948c2ecf20Sopenharmony_ci	IntrStatus=0x0C, IntrEnable=0x0E,
2958c2ecf20Sopenharmony_ci	MulticastFilter0=0x10, MulticastFilter1=0x14,
2968c2ecf20Sopenharmony_ci	RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
2978c2ecf20Sopenharmony_ci	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, PCIBusConfig1=0x6F,
2988c2ecf20Sopenharmony_ci	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
2998c2ecf20Sopenharmony_ci	ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
3008c2ecf20Sopenharmony_ci	RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
3018c2ecf20Sopenharmony_ci	StickyHW=0x83, IntrStatus2=0x84,
3028c2ecf20Sopenharmony_ci	CamMask=0x88, CamCon=0x92, CamAddr=0x93,
3038c2ecf20Sopenharmony_ci	WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4,
3048c2ecf20Sopenharmony_ci	WOLcrClr1=0xA6, WOLcgClr=0xA7,
3058c2ecf20Sopenharmony_ci	PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
3068c2ecf20Sopenharmony_ci};
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* Bits in ConfigD */
3098c2ecf20Sopenharmony_cienum backoff_bits {
3108c2ecf20Sopenharmony_ci	BackOptional=0x01, BackModify=0x02,
3118c2ecf20Sopenharmony_ci	BackCaptureEffect=0x04, BackRandom=0x08
3128c2ecf20Sopenharmony_ci};
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/* Bits in the TxConfig (TCR) register */
3158c2ecf20Sopenharmony_cienum tcr_bits {
3168c2ecf20Sopenharmony_ci	TCR_PQEN=0x01,
3178c2ecf20Sopenharmony_ci	TCR_LB0=0x02,		/* loopback[0] */
3188c2ecf20Sopenharmony_ci	TCR_LB1=0x04,		/* loopback[1] */
3198c2ecf20Sopenharmony_ci	TCR_OFSET=0x08,
3208c2ecf20Sopenharmony_ci	TCR_RTGOPT=0x10,
3218c2ecf20Sopenharmony_ci	TCR_RTFT0=0x20,
3228c2ecf20Sopenharmony_ci	TCR_RTFT1=0x40,
3238c2ecf20Sopenharmony_ci	TCR_RTSF=0x80,
3248c2ecf20Sopenharmony_ci};
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/* Bits in the CamCon (CAMC) register */
3278c2ecf20Sopenharmony_cienum camcon_bits {
3288c2ecf20Sopenharmony_ci	CAMC_CAMEN=0x01,
3298c2ecf20Sopenharmony_ci	CAMC_VCAMSL=0x02,
3308c2ecf20Sopenharmony_ci	CAMC_CAMWR=0x04,
3318c2ecf20Sopenharmony_ci	CAMC_CAMRD=0x08,
3328c2ecf20Sopenharmony_ci};
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/* Bits in the PCIBusConfig1 (BCR1) register */
3358c2ecf20Sopenharmony_cienum bcr1_bits {
3368c2ecf20Sopenharmony_ci	BCR1_POT0=0x01,
3378c2ecf20Sopenharmony_ci	BCR1_POT1=0x02,
3388c2ecf20Sopenharmony_ci	BCR1_POT2=0x04,
3398c2ecf20Sopenharmony_ci	BCR1_CTFT0=0x08,
3408c2ecf20Sopenharmony_ci	BCR1_CTFT1=0x10,
3418c2ecf20Sopenharmony_ci	BCR1_CTSF=0x20,
3428c2ecf20Sopenharmony_ci	BCR1_TXQNOBK=0x40,	/* for VT6105 */
3438c2ecf20Sopenharmony_ci	BCR1_VIDFR=0x80,	/* for VT6105 */
3448c2ecf20Sopenharmony_ci	BCR1_MED0=0x40,		/* for VT6102 */
3458c2ecf20Sopenharmony_ci	BCR1_MED1=0x80,		/* for VT6102 */
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci/* Registers we check that mmio and reg are the same. */
3498c2ecf20Sopenharmony_cistatic const int mmio_verify_registers[] = {
3508c2ecf20Sopenharmony_ci	RxConfig, TxConfig, IntrEnable, ConfigA, ConfigB, ConfigC, ConfigD,
3518c2ecf20Sopenharmony_ci	0
3528c2ecf20Sopenharmony_ci};
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci/* Bits in the interrupt status/mask registers. */
3558c2ecf20Sopenharmony_cienum intr_status_bits {
3568c2ecf20Sopenharmony_ci	IntrRxDone	= 0x0001,
3578c2ecf20Sopenharmony_ci	IntrTxDone	= 0x0002,
3588c2ecf20Sopenharmony_ci	IntrRxErr	= 0x0004,
3598c2ecf20Sopenharmony_ci	IntrTxError	= 0x0008,
3608c2ecf20Sopenharmony_ci	IntrRxEmpty	= 0x0020,
3618c2ecf20Sopenharmony_ci	IntrPCIErr	= 0x0040,
3628c2ecf20Sopenharmony_ci	IntrStatsMax	= 0x0080,
3638c2ecf20Sopenharmony_ci	IntrRxEarly	= 0x0100,
3648c2ecf20Sopenharmony_ci	IntrTxUnderrun	= 0x0210,
3658c2ecf20Sopenharmony_ci	IntrRxOverflow	= 0x0400,
3668c2ecf20Sopenharmony_ci	IntrRxDropped	= 0x0800,
3678c2ecf20Sopenharmony_ci	IntrRxNoBuf	= 0x1000,
3688c2ecf20Sopenharmony_ci	IntrTxAborted	= 0x2000,
3698c2ecf20Sopenharmony_ci	IntrLinkChange	= 0x4000,
3708c2ecf20Sopenharmony_ci	IntrRxWakeUp	= 0x8000,
3718c2ecf20Sopenharmony_ci	IntrTxDescRace		= 0x080000,	/* mapped from IntrStatus2 */
3728c2ecf20Sopenharmony_ci	IntrNormalSummary	= IntrRxDone | IntrTxDone,
3738c2ecf20Sopenharmony_ci	IntrTxErrSummary	= IntrTxDescRace | IntrTxAborted | IntrTxError |
3748c2ecf20Sopenharmony_ci				  IntrTxUnderrun,
3758c2ecf20Sopenharmony_ci};
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci/* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */
3788c2ecf20Sopenharmony_cienum wol_bits {
3798c2ecf20Sopenharmony_ci	WOLucast	= 0x10,
3808c2ecf20Sopenharmony_ci	WOLmagic	= 0x20,
3818c2ecf20Sopenharmony_ci	WOLbmcast	= 0x30,
3828c2ecf20Sopenharmony_ci	WOLlnkon	= 0x40,
3838c2ecf20Sopenharmony_ci	WOLlnkoff	= 0x80,
3848c2ecf20Sopenharmony_ci};
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/* The Rx and Tx buffer descriptors. */
3878c2ecf20Sopenharmony_cistruct rx_desc {
3888c2ecf20Sopenharmony_ci	__le32 rx_status;
3898c2ecf20Sopenharmony_ci	__le32 desc_length; /* Chain flag, Buffer/frame length */
3908c2ecf20Sopenharmony_ci	__le32 addr;
3918c2ecf20Sopenharmony_ci	__le32 next_desc;
3928c2ecf20Sopenharmony_ci};
3938c2ecf20Sopenharmony_cistruct tx_desc {
3948c2ecf20Sopenharmony_ci	__le32 tx_status;
3958c2ecf20Sopenharmony_ci	__le32 desc_length; /* Chain flag, Tx Config, Frame length */
3968c2ecf20Sopenharmony_ci	__le32 addr;
3978c2ecf20Sopenharmony_ci	__le32 next_desc;
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
4018c2ecf20Sopenharmony_ci#define TXDESC		0x00e08000
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cienum rx_status_bits {
4048c2ecf20Sopenharmony_ci	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
4058c2ecf20Sopenharmony_ci};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci/* Bits in *_desc.*_status */
4088c2ecf20Sopenharmony_cienum desc_status_bits {
4098c2ecf20Sopenharmony_ci	DescOwn=0x80000000
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci/* Bits in *_desc.*_length */
4138c2ecf20Sopenharmony_cienum desc_length_bits {
4148c2ecf20Sopenharmony_ci	DescTag=0x00010000
4158c2ecf20Sopenharmony_ci};
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/* Bits in ChipCmd. */
4188c2ecf20Sopenharmony_cienum chip_cmd_bits {
4198c2ecf20Sopenharmony_ci	CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08,
4208c2ecf20Sopenharmony_ci	CmdTxOn=0x10, Cmd1TxDemand=0x20, CmdRxDemand=0x40,
4218c2ecf20Sopenharmony_ci	Cmd1EarlyRx=0x01, Cmd1EarlyTx=0x02, Cmd1FDuplex=0x04,
4228c2ecf20Sopenharmony_ci	Cmd1NoTxPoll=0x08, Cmd1Reset=0x80,
4238c2ecf20Sopenharmony_ci};
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistruct rhine_stats {
4268c2ecf20Sopenharmony_ci	u64		packets;
4278c2ecf20Sopenharmony_ci	u64		bytes;
4288c2ecf20Sopenharmony_ci	struct u64_stats_sync syncp;
4298c2ecf20Sopenharmony_ci};
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistruct rhine_private {
4328c2ecf20Sopenharmony_ci	/* Bit mask for configured VLAN ids */
4338c2ecf20Sopenharmony_ci	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* Descriptor rings */
4368c2ecf20Sopenharmony_ci	struct rx_desc *rx_ring;
4378c2ecf20Sopenharmony_ci	struct tx_desc *tx_ring;
4388c2ecf20Sopenharmony_ci	dma_addr_t rx_ring_dma;
4398c2ecf20Sopenharmony_ci	dma_addr_t tx_ring_dma;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* The addresses of receive-in-place skbuffs. */
4428c2ecf20Sopenharmony_ci	struct sk_buff *rx_skbuff[RX_RING_SIZE];
4438c2ecf20Sopenharmony_ci	dma_addr_t rx_skbuff_dma[RX_RING_SIZE];
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* The saved address of a sent-in-place packet/buffer, for later free(). */
4468c2ecf20Sopenharmony_ci	struct sk_buff *tx_skbuff[TX_RING_SIZE];
4478c2ecf20Sopenharmony_ci	dma_addr_t tx_skbuff_dma[TX_RING_SIZE];
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* Tx bounce buffers (Rhine-I only) */
4508c2ecf20Sopenharmony_ci	unsigned char *tx_buf[TX_RING_SIZE];
4518c2ecf20Sopenharmony_ci	unsigned char *tx_bufs;
4528c2ecf20Sopenharmony_ci	dma_addr_t tx_bufs_dma;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	int irq;
4558c2ecf20Sopenharmony_ci	long pioaddr;
4568c2ecf20Sopenharmony_ci	struct net_device *dev;
4578c2ecf20Sopenharmony_ci	struct napi_struct napi;
4588c2ecf20Sopenharmony_ci	spinlock_t lock;
4598c2ecf20Sopenharmony_ci	struct mutex task_lock;
4608c2ecf20Sopenharmony_ci	bool task_enable;
4618c2ecf20Sopenharmony_ci	struct work_struct slow_event_task;
4628c2ecf20Sopenharmony_ci	struct work_struct reset_task;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	u32 msg_enable;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* Frequently used values: keep some adjacent for cache effect. */
4678c2ecf20Sopenharmony_ci	u32 quirks;
4688c2ecf20Sopenharmony_ci	unsigned int cur_rx;
4698c2ecf20Sopenharmony_ci	unsigned int cur_tx, dirty_tx;
4708c2ecf20Sopenharmony_ci	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
4718c2ecf20Sopenharmony_ci	struct rhine_stats rx_stats;
4728c2ecf20Sopenharmony_ci	struct rhine_stats tx_stats;
4738c2ecf20Sopenharmony_ci	u8 wolopts;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	u8 tx_thresh, rx_thresh;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	struct mii_if_info mii_if;
4788c2ecf20Sopenharmony_ci	void __iomem *base;
4798c2ecf20Sopenharmony_ci};
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci#define BYTE_REG_BITS_ON(x, p)      do { iowrite8((ioread8((p))|(x)), (p)); } while (0)
4828c2ecf20Sopenharmony_ci#define WORD_REG_BITS_ON(x, p)      do { iowrite16((ioread16((p))|(x)), (p)); } while (0)
4838c2ecf20Sopenharmony_ci#define DWORD_REG_BITS_ON(x, p)     do { iowrite32((ioread32((p))|(x)), (p)); } while (0)
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci#define BYTE_REG_BITS_IS_ON(x, p)   (ioread8((p)) & (x))
4868c2ecf20Sopenharmony_ci#define WORD_REG_BITS_IS_ON(x, p)   (ioread16((p)) & (x))
4878c2ecf20Sopenharmony_ci#define DWORD_REG_BITS_IS_ON(x, p)  (ioread32((p)) & (x))
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci#define BYTE_REG_BITS_OFF(x, p)     do { iowrite8(ioread8((p)) & (~(x)), (p)); } while (0)
4908c2ecf20Sopenharmony_ci#define WORD_REG_BITS_OFF(x, p)     do { iowrite16(ioread16((p)) & (~(x)), (p)); } while (0)
4918c2ecf20Sopenharmony_ci#define DWORD_REG_BITS_OFF(x, p)    do { iowrite32(ioread32((p)) & (~(x)), (p)); } while (0)
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci#define BYTE_REG_BITS_SET(x, m, p)   do { iowrite8((ioread8((p)) & (~(m)))|(x), (p)); } while (0)
4948c2ecf20Sopenharmony_ci#define WORD_REG_BITS_SET(x, m, p)   do { iowrite16((ioread16((p)) & (~(m)))|(x), (p)); } while (0)
4958c2ecf20Sopenharmony_ci#define DWORD_REG_BITS_SET(x, m, p)  do { iowrite32((ioread32((p)) & (~(m)))|(x), (p)); } while (0)
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_cistatic int  mdio_read(struct net_device *dev, int phy_id, int location);
4998c2ecf20Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value);
5008c2ecf20Sopenharmony_cistatic int  rhine_open(struct net_device *dev);
5018c2ecf20Sopenharmony_cistatic void rhine_reset_task(struct work_struct *work);
5028c2ecf20Sopenharmony_cistatic void rhine_slow_event_task(struct work_struct *work);
5038c2ecf20Sopenharmony_cistatic void rhine_tx_timeout(struct net_device *dev, unsigned int txqueue);
5048c2ecf20Sopenharmony_cistatic netdev_tx_t rhine_start_tx(struct sk_buff *skb,
5058c2ecf20Sopenharmony_ci				  struct net_device *dev);
5068c2ecf20Sopenharmony_cistatic irqreturn_t rhine_interrupt(int irq, void *dev_instance);
5078c2ecf20Sopenharmony_cistatic void rhine_tx(struct net_device *dev);
5088c2ecf20Sopenharmony_cistatic int rhine_rx(struct net_device *dev, int limit);
5098c2ecf20Sopenharmony_cistatic void rhine_set_rx_mode(struct net_device *dev);
5108c2ecf20Sopenharmony_cistatic void rhine_get_stats64(struct net_device *dev,
5118c2ecf20Sopenharmony_ci			      struct rtnl_link_stats64 *stats);
5128c2ecf20Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
5138c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops;
5148c2ecf20Sopenharmony_cistatic int  rhine_close(struct net_device *dev);
5158c2ecf20Sopenharmony_cistatic int rhine_vlan_rx_add_vid(struct net_device *dev,
5168c2ecf20Sopenharmony_ci				 __be16 proto, u16 vid);
5178c2ecf20Sopenharmony_cistatic int rhine_vlan_rx_kill_vid(struct net_device *dev,
5188c2ecf20Sopenharmony_ci				  __be16 proto, u16 vid);
5198c2ecf20Sopenharmony_cistatic void rhine_restart_tx(struct net_device *dev);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool low)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
5248c2ecf20Sopenharmony_ci	int i;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	for (i = 0; i < 1024; i++) {
5278c2ecf20Sopenharmony_ci		bool has_mask_bits = !!(ioread8(ioaddr + reg) & mask);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		if (low ^ has_mask_bits)
5308c2ecf20Sopenharmony_ci			break;
5318c2ecf20Sopenharmony_ci		udelay(10);
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci	if (i > 64) {
5348c2ecf20Sopenharmony_ci		netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle "
5358c2ecf20Sopenharmony_ci			  "count: %04d\n", low ? "low" : "high", reg, mask, i);
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	rhine_wait_bit(rp, reg, mask, false);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	rhine_wait_bit(rp, reg, mask, true);
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic u32 rhine_get_events(struct rhine_private *rp)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
5528c2ecf20Sopenharmony_ci	u32 intr_status;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	intr_status = ioread16(ioaddr + IntrStatus);
5558c2ecf20Sopenharmony_ci	/* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
5568c2ecf20Sopenharmony_ci	if (rp->quirks & rqStatusWBRace)
5578c2ecf20Sopenharmony_ci		intr_status |= ioread8(ioaddr + IntrStatus2) << 16;
5588c2ecf20Sopenharmony_ci	return intr_status;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic void rhine_ack_events(struct rhine_private *rp, u32 mask)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (rp->quirks & rqStatusWBRace)
5668c2ecf20Sopenharmony_ci		iowrite8(mask >> 16, ioaddr + IntrStatus2);
5678c2ecf20Sopenharmony_ci	iowrite16(mask, ioaddr + IntrStatus);
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci/*
5718c2ecf20Sopenharmony_ci * Get power related registers into sane state.
5728c2ecf20Sopenharmony_ci * Notify user about past WOL event.
5738c2ecf20Sopenharmony_ci */
5748c2ecf20Sopenharmony_cistatic void rhine_power_init(struct net_device *dev)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
5778c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
5788c2ecf20Sopenharmony_ci	u16 wolstat;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (rp->quirks & rqWOL) {
5818c2ecf20Sopenharmony_ci		/* Make sure chip is in power state D0 */
5828c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + StickyHW) & 0xFC, ioaddr + StickyHW);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		/* Disable "force PME-enable" */
5858c2ecf20Sopenharmony_ci		iowrite8(0x80, ioaddr + WOLcgClr);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		/* Clear power-event config bits (WOL) */
5888c2ecf20Sopenharmony_ci		iowrite8(0xFF, ioaddr + WOLcrClr);
5898c2ecf20Sopenharmony_ci		/* More recent cards can manage two additional patterns */
5908c2ecf20Sopenharmony_ci		if (rp->quirks & rq6patterns)
5918c2ecf20Sopenharmony_ci			iowrite8(0x03, ioaddr + WOLcrClr1);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		/* Save power-event status bits */
5948c2ecf20Sopenharmony_ci		wolstat = ioread8(ioaddr + PwrcsrSet);
5958c2ecf20Sopenharmony_ci		if (rp->quirks & rq6patterns)
5968c2ecf20Sopenharmony_ci			wolstat |= (ioread8(ioaddr + PwrcsrSet1) & 0x03) << 8;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		/* Clear power-event status bits */
5998c2ecf20Sopenharmony_ci		iowrite8(0xFF, ioaddr + PwrcsrClr);
6008c2ecf20Sopenharmony_ci		if (rp->quirks & rq6patterns)
6018c2ecf20Sopenharmony_ci			iowrite8(0x03, ioaddr + PwrcsrClr1);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		if (wolstat) {
6048c2ecf20Sopenharmony_ci			char *reason;
6058c2ecf20Sopenharmony_ci			switch (wolstat) {
6068c2ecf20Sopenharmony_ci			case WOLmagic:
6078c2ecf20Sopenharmony_ci				reason = "Magic packet";
6088c2ecf20Sopenharmony_ci				break;
6098c2ecf20Sopenharmony_ci			case WOLlnkon:
6108c2ecf20Sopenharmony_ci				reason = "Link went up";
6118c2ecf20Sopenharmony_ci				break;
6128c2ecf20Sopenharmony_ci			case WOLlnkoff:
6138c2ecf20Sopenharmony_ci				reason = "Link went down";
6148c2ecf20Sopenharmony_ci				break;
6158c2ecf20Sopenharmony_ci			case WOLucast:
6168c2ecf20Sopenharmony_ci				reason = "Unicast packet";
6178c2ecf20Sopenharmony_ci				break;
6188c2ecf20Sopenharmony_ci			case WOLbmcast:
6198c2ecf20Sopenharmony_ci				reason = "Multicast/broadcast packet";
6208c2ecf20Sopenharmony_ci				break;
6218c2ecf20Sopenharmony_ci			default:
6228c2ecf20Sopenharmony_ci				reason = "Unknown";
6238c2ecf20Sopenharmony_ci			}
6248c2ecf20Sopenharmony_ci			netdev_info(dev, "Woke system up. Reason: %s\n",
6258c2ecf20Sopenharmony_ci				    reason);
6268c2ecf20Sopenharmony_ci		}
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic void rhine_chip_reset(struct net_device *dev)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
6338c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
6348c2ecf20Sopenharmony_ci	u8 cmd1;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	iowrite8(Cmd1Reset, ioaddr + ChipCmd1);
6378c2ecf20Sopenharmony_ci	IOSYNC;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) {
6408c2ecf20Sopenharmony_ci		netdev_info(dev, "Reset not complete yet. Trying harder.\n");
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		/* Force reset */
6438c2ecf20Sopenharmony_ci		if (rp->quirks & rqForceReset)
6448c2ecf20Sopenharmony_ci			iowrite8(0x40, ioaddr + MiscCmd);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci		/* Reset can take somewhat longer (rare) */
6478c2ecf20Sopenharmony_ci		rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset);
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	cmd1 = ioread8(ioaddr + ChipCmd1);
6518c2ecf20Sopenharmony_ci	netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ?
6528c2ecf20Sopenharmony_ci		   "failed" : "succeeded");
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic void enable_mmio(long pioaddr, u32 quirks)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	int n;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	if (quirks & rqNeedEnMMIO) {
6608c2ecf20Sopenharmony_ci		if (quirks & rqRhineI) {
6618c2ecf20Sopenharmony_ci			/* More recent docs say that this bit is reserved */
6628c2ecf20Sopenharmony_ci			n = inb(pioaddr + ConfigA) | 0x20;
6638c2ecf20Sopenharmony_ci			outb(n, pioaddr + ConfigA);
6648c2ecf20Sopenharmony_ci		} else {
6658c2ecf20Sopenharmony_ci			n = inb(pioaddr + ConfigD) | 0x80;
6668c2ecf20Sopenharmony_ci			outb(n, pioaddr + ConfigD);
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic inline int verify_mmio(struct device *hwdev,
6728c2ecf20Sopenharmony_ci			      long pioaddr,
6738c2ecf20Sopenharmony_ci			      void __iomem *ioaddr,
6748c2ecf20Sopenharmony_ci			      u32 quirks)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	if (quirks & rqNeedEnMMIO) {
6778c2ecf20Sopenharmony_ci		int i = 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		/* Check that selected MMIO registers match the PIO ones */
6808c2ecf20Sopenharmony_ci		while (mmio_verify_registers[i]) {
6818c2ecf20Sopenharmony_ci			int reg = mmio_verify_registers[i++];
6828c2ecf20Sopenharmony_ci			unsigned char a = inb(pioaddr+reg);
6838c2ecf20Sopenharmony_ci			unsigned char b = readb(ioaddr+reg);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci			if (a != b) {
6868c2ecf20Sopenharmony_ci				dev_err(hwdev,
6878c2ecf20Sopenharmony_ci					"MMIO do not match PIO [%02x] (%02x != %02x)\n",
6888c2ecf20Sopenharmony_ci					reg, a, b);
6898c2ecf20Sopenharmony_ci				return -EIO;
6908c2ecf20Sopenharmony_ci			}
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci	}
6938c2ecf20Sopenharmony_ci	return 0;
6948c2ecf20Sopenharmony_ci}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci/*
6978c2ecf20Sopenharmony_ci * Loads bytes 0x00-0x05, 0x6E-0x6F, 0x78-0x7B from EEPROM
6988c2ecf20Sopenharmony_ci * (plus 0x6C for Rhine-I/II)
6998c2ecf20Sopenharmony_ci */
7008c2ecf20Sopenharmony_cistatic void rhine_reload_eeprom(long pioaddr, struct net_device *dev)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
7038c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
7048c2ecf20Sopenharmony_ci	int i;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	outb(0x20, pioaddr + MACRegEEcsr);
7078c2ecf20Sopenharmony_ci	for (i = 0; i < 1024; i++) {
7088c2ecf20Sopenharmony_ci		if (!(inb(pioaddr + MACRegEEcsr) & 0x20))
7098c2ecf20Sopenharmony_ci			break;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci	if (i > 512)
7128c2ecf20Sopenharmony_ci		pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	/*
7158c2ecf20Sopenharmony_ci	 * Reloading from EEPROM overwrites ConfigA-D, so we must re-enable
7168c2ecf20Sopenharmony_ci	 * MMIO. If reloading EEPROM was done first this could be avoided, but
7178c2ecf20Sopenharmony_ci	 * it is not known if that still works with the "win98-reboot" problem.
7188c2ecf20Sopenharmony_ci	 */
7198c2ecf20Sopenharmony_ci	enable_mmio(pioaddr, rp->quirks);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	/* Turn off EEPROM-controlled wake-up (magic packet) */
7228c2ecf20Sopenharmony_ci	if (rp->quirks & rqWOL)
7238c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + ConfigA) & 0xFC, ioaddr + ConfigA);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
7288c2ecf20Sopenharmony_cistatic void rhine_poll(struct net_device *dev)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
7318c2ecf20Sopenharmony_ci	const int irq = rp->irq;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	disable_irq(irq);
7348c2ecf20Sopenharmony_ci	rhine_interrupt(irq, dev);
7358c2ecf20Sopenharmony_ci	enable_irq(irq);
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci#endif
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic void rhine_kick_tx_threshold(struct rhine_private *rp)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	if (rp->tx_thresh < 0xe0) {
7428c2ecf20Sopenharmony_ci		void __iomem *ioaddr = rp->base;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci		rp->tx_thresh += 0x20;
7458c2ecf20Sopenharmony_ci		BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig);
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic void rhine_tx_err(struct rhine_private *rp, u32 status)
7508c2ecf20Sopenharmony_ci{
7518c2ecf20Sopenharmony_ci	struct net_device *dev = rp->dev;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (status & IntrTxAborted) {
7548c2ecf20Sopenharmony_ci		netif_info(rp, tx_err, dev,
7558c2ecf20Sopenharmony_ci			   "Abort %08x, frame dropped\n", status);
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (status & IntrTxUnderrun) {
7598c2ecf20Sopenharmony_ci		rhine_kick_tx_threshold(rp);
7608c2ecf20Sopenharmony_ci		netif_info(rp, tx_err ,dev, "Transmitter underrun, "
7618c2ecf20Sopenharmony_ci			   "Tx threshold now %02x\n", rp->tx_thresh);
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (status & IntrTxDescRace)
7658c2ecf20Sopenharmony_ci		netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n");
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if ((status & IntrTxError) &&
7688c2ecf20Sopenharmony_ci	    (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) {
7698c2ecf20Sopenharmony_ci		rhine_kick_tx_threshold(rp);
7708c2ecf20Sopenharmony_ci		netif_info(rp, tx_err, dev, "Unspecified error. "
7718c2ecf20Sopenharmony_ci			   "Tx threshold now %02x\n", rp->tx_thresh);
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	rhine_restart_tx(dev);
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
7808c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &rp->dev->stats;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	stats->rx_crc_errors    += ioread16(ioaddr + RxCRCErrs);
7838c2ecf20Sopenharmony_ci	stats->rx_missed_errors += ioread16(ioaddr + RxMissed);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	/*
7868c2ecf20Sopenharmony_ci	 * Clears the "tally counters" for CRC errors and missed frames(?).
7878c2ecf20Sopenharmony_ci	 * It has been reported that some chips need a write of 0 to clear
7888c2ecf20Sopenharmony_ci	 * these, for others the counters are set to 1 when written to and
7898c2ecf20Sopenharmony_ci	 * instead cleared when read. So we clear them both ways ...
7908c2ecf20Sopenharmony_ci	 */
7918c2ecf20Sopenharmony_ci	iowrite32(0, ioaddr + RxMissed);
7928c2ecf20Sopenharmony_ci	ioread16(ioaddr + RxCRCErrs);
7938c2ecf20Sopenharmony_ci	ioread16(ioaddr + RxMissed);
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci#define RHINE_EVENT_NAPI_RX	(IntrRxDone | \
7978c2ecf20Sopenharmony_ci				 IntrRxErr | \
7988c2ecf20Sopenharmony_ci				 IntrRxEmpty | \
7998c2ecf20Sopenharmony_ci				 IntrRxOverflow	| \
8008c2ecf20Sopenharmony_ci				 IntrRxDropped | \
8018c2ecf20Sopenharmony_ci				 IntrRxNoBuf | \
8028c2ecf20Sopenharmony_ci				 IntrRxWakeUp)
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci#define RHINE_EVENT_NAPI_TX_ERR	(IntrTxError | \
8058c2ecf20Sopenharmony_ci				 IntrTxAborted | \
8068c2ecf20Sopenharmony_ci				 IntrTxUnderrun | \
8078c2ecf20Sopenharmony_ci				 IntrTxDescRace)
8088c2ecf20Sopenharmony_ci#define RHINE_EVENT_NAPI_TX	(IntrTxDone | RHINE_EVENT_NAPI_TX_ERR)
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci#define RHINE_EVENT_NAPI	(RHINE_EVENT_NAPI_RX | \
8118c2ecf20Sopenharmony_ci				 RHINE_EVENT_NAPI_TX | \
8128c2ecf20Sopenharmony_ci				 IntrStatsMax)
8138c2ecf20Sopenharmony_ci#define RHINE_EVENT_SLOW	(IntrPCIErr | IntrLinkChange)
8148c2ecf20Sopenharmony_ci#define RHINE_EVENT		(RHINE_EVENT_NAPI | RHINE_EVENT_SLOW)
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic int rhine_napipoll(struct napi_struct *napi, int budget)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
8198c2ecf20Sopenharmony_ci	struct net_device *dev = rp->dev;
8208c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
8218c2ecf20Sopenharmony_ci	u16 enable_mask = RHINE_EVENT & 0xffff;
8228c2ecf20Sopenharmony_ci	int work_done = 0;
8238c2ecf20Sopenharmony_ci	u32 status;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	status = rhine_get_events(rp);
8268c2ecf20Sopenharmony_ci	rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (status & RHINE_EVENT_NAPI_RX)
8298c2ecf20Sopenharmony_ci		work_done += rhine_rx(dev, budget);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if (status & RHINE_EVENT_NAPI_TX) {
8328c2ecf20Sopenharmony_ci		if (status & RHINE_EVENT_NAPI_TX_ERR) {
8338c2ecf20Sopenharmony_ci			/* Avoid scavenging before Tx engine turned off */
8348c2ecf20Sopenharmony_ci			rhine_wait_bit_low(rp, ChipCmd, CmdTxOn);
8358c2ecf20Sopenharmony_ci			if (ioread8(ioaddr + ChipCmd) & CmdTxOn)
8368c2ecf20Sopenharmony_ci				netif_warn(rp, tx_err, dev, "Tx still on\n");
8378c2ecf20Sopenharmony_ci		}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		rhine_tx(dev);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		if (status & RHINE_EVENT_NAPI_TX_ERR)
8428c2ecf20Sopenharmony_ci			rhine_tx_err(rp, status);
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	if (status & IntrStatsMax) {
8468c2ecf20Sopenharmony_ci		spin_lock(&rp->lock);
8478c2ecf20Sopenharmony_ci		rhine_update_rx_crc_and_missed_errord(rp);
8488c2ecf20Sopenharmony_ci		spin_unlock(&rp->lock);
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (status & RHINE_EVENT_SLOW) {
8528c2ecf20Sopenharmony_ci		enable_mask &= ~RHINE_EVENT_SLOW;
8538c2ecf20Sopenharmony_ci		schedule_work(&rp->slow_event_task);
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	if (work_done < budget) {
8578c2ecf20Sopenharmony_ci		napi_complete_done(napi, work_done);
8588c2ecf20Sopenharmony_ci		iowrite16(enable_mask, ioaddr + IntrEnable);
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci	return work_done;
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic void rhine_hw_init(struct net_device *dev, long pioaddr)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* Reset the chip to erase previous misconfiguration. */
8688c2ecf20Sopenharmony_ci	rhine_chip_reset(dev);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* Rhine-I needs extra time to recuperate before EEPROM reload */
8718c2ecf20Sopenharmony_ci	if (rp->quirks & rqRhineI)
8728c2ecf20Sopenharmony_ci		msleep(5);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* Reload EEPROM controlled bytes cleared by soft reset */
8758c2ecf20Sopenharmony_ci	if (dev_is_pci(dev->dev.parent))
8768c2ecf20Sopenharmony_ci		rhine_reload_eeprom(pioaddr, dev);
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic const struct net_device_ops rhine_netdev_ops = {
8808c2ecf20Sopenharmony_ci	.ndo_open		 = rhine_open,
8818c2ecf20Sopenharmony_ci	.ndo_stop		 = rhine_close,
8828c2ecf20Sopenharmony_ci	.ndo_start_xmit		 = rhine_start_tx,
8838c2ecf20Sopenharmony_ci	.ndo_get_stats64	 = rhine_get_stats64,
8848c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	 = rhine_set_rx_mode,
8858c2ecf20Sopenharmony_ci	.ndo_validate_addr	 = eth_validate_addr,
8868c2ecf20Sopenharmony_ci	.ndo_set_mac_address 	 = eth_mac_addr,
8878c2ecf20Sopenharmony_ci	.ndo_do_ioctl		 = netdev_ioctl,
8888c2ecf20Sopenharmony_ci	.ndo_tx_timeout 	 = rhine_tx_timeout,
8898c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid	 = rhine_vlan_rx_add_vid,
8908c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid	 = rhine_vlan_rx_kill_vid,
8918c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
8928c2ecf20Sopenharmony_ci	.ndo_poll_controller	 = rhine_poll,
8938c2ecf20Sopenharmony_ci#endif
8948c2ecf20Sopenharmony_ci};
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_cistatic int rhine_init_one_common(struct device *hwdev, u32 quirks,
8978c2ecf20Sopenharmony_ci				 long pioaddr, void __iomem *ioaddr, int irq)
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	struct net_device *dev;
9008c2ecf20Sopenharmony_ci	struct rhine_private *rp;
9018c2ecf20Sopenharmony_ci	int i, rc, phy_id;
9028c2ecf20Sopenharmony_ci	const char *name;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* this should always be supported */
9058c2ecf20Sopenharmony_ci	rc = dma_set_mask(hwdev, DMA_BIT_MASK(32));
9068c2ecf20Sopenharmony_ci	if (rc) {
9078c2ecf20Sopenharmony_ci		dev_err(hwdev, "32-bit DMA addresses not supported by the card!?\n");
9088c2ecf20Sopenharmony_ci		goto err_out;
9098c2ecf20Sopenharmony_ci	}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	dev = alloc_etherdev(sizeof(struct rhine_private));
9128c2ecf20Sopenharmony_ci	if (!dev) {
9138c2ecf20Sopenharmony_ci		rc = -ENOMEM;
9148c2ecf20Sopenharmony_ci		goto err_out;
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, hwdev);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	rp = netdev_priv(dev);
9198c2ecf20Sopenharmony_ci	rp->dev = dev;
9208c2ecf20Sopenharmony_ci	rp->quirks = quirks;
9218c2ecf20Sopenharmony_ci	rp->pioaddr = pioaddr;
9228c2ecf20Sopenharmony_ci	rp->base = ioaddr;
9238c2ecf20Sopenharmony_ci	rp->irq = irq;
9248c2ecf20Sopenharmony_ci	rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	phy_id = rp->quirks & rqIntPHY ? 1 : 0;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	u64_stats_init(&rp->tx_stats.syncp);
9298c2ecf20Sopenharmony_ci	u64_stats_init(&rp->rx_stats.syncp);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	/* Get chip registers into a sane state */
9328c2ecf20Sopenharmony_ci	rhine_power_init(dev);
9338c2ecf20Sopenharmony_ci	rhine_hw_init(dev, pioaddr);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
9368c2ecf20Sopenharmony_ci		dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(dev->dev_addr)) {
9398c2ecf20Sopenharmony_ci		/* Report it and use a random ethernet address instead */
9408c2ecf20Sopenharmony_ci		netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr);
9418c2ecf20Sopenharmony_ci		eth_hw_addr_random(dev);
9428c2ecf20Sopenharmony_ci		netdev_info(dev, "Using random MAC address: %pM\n",
9438c2ecf20Sopenharmony_ci			    dev->dev_addr);
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	/* For Rhine-I/II, phy_id is loaded from EEPROM */
9478c2ecf20Sopenharmony_ci	if (!phy_id)
9488c2ecf20Sopenharmony_ci		phy_id = ioread8(ioaddr + 0x6C);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	spin_lock_init(&rp->lock);
9518c2ecf20Sopenharmony_ci	mutex_init(&rp->task_lock);
9528c2ecf20Sopenharmony_ci	INIT_WORK(&rp->reset_task, rhine_reset_task);
9538c2ecf20Sopenharmony_ci	INIT_WORK(&rp->slow_event_task, rhine_slow_event_task);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	rp->mii_if.dev = dev;
9568c2ecf20Sopenharmony_ci	rp->mii_if.mdio_read = mdio_read;
9578c2ecf20Sopenharmony_ci	rp->mii_if.mdio_write = mdio_write;
9588c2ecf20Sopenharmony_ci	rp->mii_if.phy_id_mask = 0x1f;
9598c2ecf20Sopenharmony_ci	rp->mii_if.reg_num_mask = 0x1f;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	/* The chip-specific entries in the device structure. */
9628c2ecf20Sopenharmony_ci	dev->netdev_ops = &rhine_netdev_ops;
9638c2ecf20Sopenharmony_ci	dev->ethtool_ops = &netdev_ethtool_ops;
9648c2ecf20Sopenharmony_ci	dev->watchdog_timeo = TX_TIMEOUT;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (rp->quirks & rqRhineI)
9698c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (rp->quirks & rqMgmt)
9728c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
9738c2ecf20Sopenharmony_ci				 NETIF_F_HW_VLAN_CTAG_RX |
9748c2ecf20Sopenharmony_ci				 NETIF_F_HW_VLAN_CTAG_FILTER;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/* dev->name not defined before register_netdev()! */
9778c2ecf20Sopenharmony_ci	rc = register_netdev(dev);
9788c2ecf20Sopenharmony_ci	if (rc)
9798c2ecf20Sopenharmony_ci		goto err_out_free_netdev;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (rp->quirks & rqRhineI)
9828c2ecf20Sopenharmony_ci		name = "Rhine";
9838c2ecf20Sopenharmony_ci	else if (rp->quirks & rqStatusWBRace)
9848c2ecf20Sopenharmony_ci		name = "Rhine II";
9858c2ecf20Sopenharmony_ci	else if (rp->quirks & rqMgmt)
9868c2ecf20Sopenharmony_ci		name = "Rhine III (Management Adapter)";
9878c2ecf20Sopenharmony_ci	else
9888c2ecf20Sopenharmony_ci		name = "Rhine III";
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	netdev_info(dev, "VIA %s at %p, %pM, IRQ %d\n",
9918c2ecf20Sopenharmony_ci		    name, ioaddr, dev->dev_addr, rp->irq);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	dev_set_drvdata(hwdev, dev);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	{
9968c2ecf20Sopenharmony_ci		u16 mii_cmd;
9978c2ecf20Sopenharmony_ci		int mii_status = mdio_read(dev, phy_id, 1);
9988c2ecf20Sopenharmony_ci		mii_cmd = mdio_read(dev, phy_id, MII_BMCR) & ~BMCR_ISOLATE;
9998c2ecf20Sopenharmony_ci		mdio_write(dev, phy_id, MII_BMCR, mii_cmd);
10008c2ecf20Sopenharmony_ci		if (mii_status != 0xffff && mii_status != 0x0000) {
10018c2ecf20Sopenharmony_ci			rp->mii_if.advertising = mdio_read(dev, phy_id, 4);
10028c2ecf20Sopenharmony_ci			netdev_info(dev,
10038c2ecf20Sopenharmony_ci				    "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n",
10048c2ecf20Sopenharmony_ci				    phy_id,
10058c2ecf20Sopenharmony_ci				    mii_status, rp->mii_if.advertising,
10068c2ecf20Sopenharmony_ci				    mdio_read(dev, phy_id, 5));
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci			/* set IFF_RUNNING */
10098c2ecf20Sopenharmony_ci			if (mii_status & BMSR_LSTATUS)
10108c2ecf20Sopenharmony_ci				netif_carrier_on(dev);
10118c2ecf20Sopenharmony_ci			else
10128c2ecf20Sopenharmony_ci				netif_carrier_off(dev);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci		}
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci	rp->mii_if.phy_id = phy_id;
10178c2ecf20Sopenharmony_ci	if (avoid_D3)
10188c2ecf20Sopenharmony_ci		netif_info(rp, probe, dev, "No D3 power state at shutdown\n");
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return 0;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cierr_out_free_netdev:
10238c2ecf20Sopenharmony_ci	free_netdev(dev);
10248c2ecf20Sopenharmony_cierr_out:
10258c2ecf20Sopenharmony_ci	return rc;
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_cistatic int rhine_init_one_pci(struct pci_dev *pdev,
10298c2ecf20Sopenharmony_ci			      const struct pci_device_id *ent)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	struct device *hwdev = &pdev->dev;
10328c2ecf20Sopenharmony_ci	int rc;
10338c2ecf20Sopenharmony_ci	long pioaddr, memaddr;
10348c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
10358c2ecf20Sopenharmony_ci	int io_size = pdev->revision < VTunknown0 ? 128 : 256;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci/* This driver was written to use PCI memory space. Some early versions
10388c2ecf20Sopenharmony_ci * of the Rhine may only work correctly with I/O space accesses.
10398c2ecf20Sopenharmony_ci * TODO: determine for which revisions this is true and assign the flag
10408c2ecf20Sopenharmony_ci *	 in code as opposed to this Kconfig option (???)
10418c2ecf20Sopenharmony_ci */
10428c2ecf20Sopenharmony_ci#ifdef CONFIG_VIA_RHINE_MMIO
10438c2ecf20Sopenharmony_ci	u32 quirks = rqNeedEnMMIO;
10448c2ecf20Sopenharmony_ci#else
10458c2ecf20Sopenharmony_ci	u32 quirks = 0;
10468c2ecf20Sopenharmony_ci#endif
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	rc = pci_enable_device(pdev);
10498c2ecf20Sopenharmony_ci	if (rc)
10508c2ecf20Sopenharmony_ci		goto err_out;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (pdev->revision < VTunknown0) {
10538c2ecf20Sopenharmony_ci		quirks |= rqRhineI;
10548c2ecf20Sopenharmony_ci	} else if (pdev->revision >= VT6102) {
10558c2ecf20Sopenharmony_ci		quirks |= rqWOL | rqForceReset;
10568c2ecf20Sopenharmony_ci		if (pdev->revision < VT6105) {
10578c2ecf20Sopenharmony_ci			quirks |= rqStatusWBRace;
10588c2ecf20Sopenharmony_ci		} else {
10598c2ecf20Sopenharmony_ci			quirks |= rqIntPHY;
10608c2ecf20Sopenharmony_ci			if (pdev->revision >= VT6105_B0)
10618c2ecf20Sopenharmony_ci				quirks |= rq6patterns;
10628c2ecf20Sopenharmony_ci			if (pdev->revision >= VT6105M)
10638c2ecf20Sopenharmony_ci				quirks |= rqMgmt;
10648c2ecf20Sopenharmony_ci		}
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	/* sanity check */
10688c2ecf20Sopenharmony_ci	if ((pci_resource_len(pdev, 0) < io_size) ||
10698c2ecf20Sopenharmony_ci	    (pci_resource_len(pdev, 1) < io_size)) {
10708c2ecf20Sopenharmony_ci		rc = -EIO;
10718c2ecf20Sopenharmony_ci		dev_err(hwdev, "Insufficient PCI resources, aborting\n");
10728c2ecf20Sopenharmony_ci		goto err_out_pci_disable;
10738c2ecf20Sopenharmony_ci	}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	pioaddr = pci_resource_start(pdev, 0);
10768c2ecf20Sopenharmony_ci	memaddr = pci_resource_start(pdev, 1);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	pci_set_master(pdev);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	rc = pci_request_regions(pdev, DRV_NAME);
10818c2ecf20Sopenharmony_ci	if (rc)
10828c2ecf20Sopenharmony_ci		goto err_out_pci_disable;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	ioaddr = pci_iomap(pdev, (quirks & rqNeedEnMMIO ? 1 : 0), io_size);
10858c2ecf20Sopenharmony_ci	if (!ioaddr) {
10868c2ecf20Sopenharmony_ci		rc = -EIO;
10878c2ecf20Sopenharmony_ci		dev_err(hwdev,
10888c2ecf20Sopenharmony_ci			"ioremap failed for device %s, region 0x%X @ 0x%lX\n",
10898c2ecf20Sopenharmony_ci			dev_name(hwdev), io_size, memaddr);
10908c2ecf20Sopenharmony_ci		goto err_out_free_res;
10918c2ecf20Sopenharmony_ci	}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	enable_mmio(pioaddr, quirks);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	rc = verify_mmio(hwdev, pioaddr, ioaddr, quirks);
10968c2ecf20Sopenharmony_ci	if (rc)
10978c2ecf20Sopenharmony_ci		goto err_out_unmap;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	rc = rhine_init_one_common(&pdev->dev, quirks,
11008c2ecf20Sopenharmony_ci				   pioaddr, ioaddr, pdev->irq);
11018c2ecf20Sopenharmony_ci	if (!rc)
11028c2ecf20Sopenharmony_ci		return 0;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_cierr_out_unmap:
11058c2ecf20Sopenharmony_ci	pci_iounmap(pdev, ioaddr);
11068c2ecf20Sopenharmony_cierr_out_free_res:
11078c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
11088c2ecf20Sopenharmony_cierr_out_pci_disable:
11098c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
11108c2ecf20Sopenharmony_cierr_out:
11118c2ecf20Sopenharmony_ci	return rc;
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_cistatic int rhine_init_one_platform(struct platform_device *pdev)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	const struct of_device_id *match;
11178c2ecf20Sopenharmony_ci	const u32 *quirks;
11188c2ecf20Sopenharmony_ci	int irq;
11198c2ecf20Sopenharmony_ci	void __iomem *ioaddr;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	match = of_match_device(rhine_of_tbl, &pdev->dev);
11228c2ecf20Sopenharmony_ci	if (!match)
11238c2ecf20Sopenharmony_ci		return -EINVAL;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	ioaddr = devm_platform_ioremap_resource(pdev, 0);
11268c2ecf20Sopenharmony_ci	if (IS_ERR(ioaddr))
11278c2ecf20Sopenharmony_ci		return PTR_ERR(ioaddr);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
11308c2ecf20Sopenharmony_ci	if (!irq)
11318c2ecf20Sopenharmony_ci		return -EINVAL;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	quirks = match->data;
11348c2ecf20Sopenharmony_ci	if (!quirks)
11358c2ecf20Sopenharmony_ci		return -EINVAL;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	return rhine_init_one_common(&pdev->dev, *quirks,
11388c2ecf20Sopenharmony_ci				     (long)ioaddr, ioaddr, irq);
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cistatic int alloc_ring(struct net_device* dev)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
11448c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
11458c2ecf20Sopenharmony_ci	void *ring;
11468c2ecf20Sopenharmony_ci	dma_addr_t ring_dma;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	ring = dma_alloc_coherent(hwdev,
11498c2ecf20Sopenharmony_ci				  RX_RING_SIZE * sizeof(struct rx_desc) +
11508c2ecf20Sopenharmony_ci				  TX_RING_SIZE * sizeof(struct tx_desc),
11518c2ecf20Sopenharmony_ci				  &ring_dma,
11528c2ecf20Sopenharmony_ci				  GFP_ATOMIC);
11538c2ecf20Sopenharmony_ci	if (!ring) {
11548c2ecf20Sopenharmony_ci		netdev_err(dev, "Could not allocate DMA memory\n");
11558c2ecf20Sopenharmony_ci		return -ENOMEM;
11568c2ecf20Sopenharmony_ci	}
11578c2ecf20Sopenharmony_ci	if (rp->quirks & rqRhineI) {
11588c2ecf20Sopenharmony_ci		rp->tx_bufs = dma_alloc_coherent(hwdev,
11598c2ecf20Sopenharmony_ci						 PKT_BUF_SZ * TX_RING_SIZE,
11608c2ecf20Sopenharmony_ci						 &rp->tx_bufs_dma,
11618c2ecf20Sopenharmony_ci						 GFP_ATOMIC);
11628c2ecf20Sopenharmony_ci		if (rp->tx_bufs == NULL) {
11638c2ecf20Sopenharmony_ci			dma_free_coherent(hwdev,
11648c2ecf20Sopenharmony_ci					  RX_RING_SIZE * sizeof(struct rx_desc) +
11658c2ecf20Sopenharmony_ci					  TX_RING_SIZE * sizeof(struct tx_desc),
11668c2ecf20Sopenharmony_ci					  ring, ring_dma);
11678c2ecf20Sopenharmony_ci			return -ENOMEM;
11688c2ecf20Sopenharmony_ci		}
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	rp->rx_ring = ring;
11728c2ecf20Sopenharmony_ci	rp->tx_ring = ring + RX_RING_SIZE * sizeof(struct rx_desc);
11738c2ecf20Sopenharmony_ci	rp->rx_ring_dma = ring_dma;
11748c2ecf20Sopenharmony_ci	rp->tx_ring_dma = ring_dma + RX_RING_SIZE * sizeof(struct rx_desc);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	return 0;
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic void free_ring(struct net_device* dev)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
11828c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	dma_free_coherent(hwdev,
11858c2ecf20Sopenharmony_ci			  RX_RING_SIZE * sizeof(struct rx_desc) +
11868c2ecf20Sopenharmony_ci			  TX_RING_SIZE * sizeof(struct tx_desc),
11878c2ecf20Sopenharmony_ci			  rp->rx_ring, rp->rx_ring_dma);
11888c2ecf20Sopenharmony_ci	rp->tx_ring = NULL;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (rp->tx_bufs)
11918c2ecf20Sopenharmony_ci		dma_free_coherent(hwdev, PKT_BUF_SZ * TX_RING_SIZE,
11928c2ecf20Sopenharmony_ci				  rp->tx_bufs, rp->tx_bufs_dma);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	rp->tx_bufs = NULL;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistruct rhine_skb_dma {
11998c2ecf20Sopenharmony_ci	struct sk_buff *skb;
12008c2ecf20Sopenharmony_ci	dma_addr_t dma;
12018c2ecf20Sopenharmony_ci};
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic inline int rhine_skb_dma_init(struct net_device *dev,
12048c2ecf20Sopenharmony_ci				     struct rhine_skb_dma *sd)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
12078c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
12088c2ecf20Sopenharmony_ci	const int size = rp->rx_buf_sz;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	sd->skb = netdev_alloc_skb(dev, size);
12118c2ecf20Sopenharmony_ci	if (!sd->skb)
12128c2ecf20Sopenharmony_ci		return -ENOMEM;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	sd->dma = dma_map_single(hwdev, sd->skb->data, size, DMA_FROM_DEVICE);
12158c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(hwdev, sd->dma))) {
12168c2ecf20Sopenharmony_ci		netif_err(rp, drv, dev, "Rx DMA mapping failure\n");
12178c2ecf20Sopenharmony_ci		dev_kfree_skb_any(sd->skb);
12188c2ecf20Sopenharmony_ci		return -EIO;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	return 0;
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_cistatic void rhine_reset_rbufs(struct rhine_private *rp)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	int i;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	rp->cur_rx = 0;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_SIZE; i++)
12318c2ecf20Sopenharmony_ci		rp->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
12328c2ecf20Sopenharmony_ci}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_cistatic inline void rhine_skb_dma_nic_store(struct rhine_private *rp,
12358c2ecf20Sopenharmony_ci					   struct rhine_skb_dma *sd, int entry)
12368c2ecf20Sopenharmony_ci{
12378c2ecf20Sopenharmony_ci	rp->rx_skbuff_dma[entry] = sd->dma;
12388c2ecf20Sopenharmony_ci	rp->rx_skbuff[entry] = sd->skb;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	rp->rx_ring[entry].addr = cpu_to_le32(sd->dma);
12418c2ecf20Sopenharmony_ci	dma_wmb();
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cistatic void free_rbufs(struct net_device* dev);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_cistatic int alloc_rbufs(struct net_device *dev)
12478c2ecf20Sopenharmony_ci{
12488c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
12498c2ecf20Sopenharmony_ci	dma_addr_t next;
12508c2ecf20Sopenharmony_ci	int rc, i;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	rp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
12538c2ecf20Sopenharmony_ci	next = rp->rx_ring_dma;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	/* Init the ring entries */
12568c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_SIZE; i++) {
12578c2ecf20Sopenharmony_ci		rp->rx_ring[i].rx_status = 0;
12588c2ecf20Sopenharmony_ci		rp->rx_ring[i].desc_length = cpu_to_le32(rp->rx_buf_sz);
12598c2ecf20Sopenharmony_ci		next += sizeof(struct rx_desc);
12608c2ecf20Sopenharmony_ci		rp->rx_ring[i].next_desc = cpu_to_le32(next);
12618c2ecf20Sopenharmony_ci		rp->rx_skbuff[i] = NULL;
12628c2ecf20Sopenharmony_ci	}
12638c2ecf20Sopenharmony_ci	/* Mark the last entry as wrapping the ring. */
12648c2ecf20Sopenharmony_ci	rp->rx_ring[i-1].next_desc = cpu_to_le32(rp->rx_ring_dma);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
12678c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_SIZE; i++) {
12688c2ecf20Sopenharmony_ci		struct rhine_skb_dma sd;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		rc = rhine_skb_dma_init(dev, &sd);
12718c2ecf20Sopenharmony_ci		if (rc < 0) {
12728c2ecf20Sopenharmony_ci			free_rbufs(dev);
12738c2ecf20Sopenharmony_ci			goto out;
12748c2ecf20Sopenharmony_ci		}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci		rhine_skb_dma_nic_store(rp, &sd, i);
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	rhine_reset_rbufs(rp);
12808c2ecf20Sopenharmony_ciout:
12818c2ecf20Sopenharmony_ci	return rc;
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic void free_rbufs(struct net_device* dev)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
12878c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
12888c2ecf20Sopenharmony_ci	int i;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	/* Free all the skbuffs in the Rx queue. */
12918c2ecf20Sopenharmony_ci	for (i = 0; i < RX_RING_SIZE; i++) {
12928c2ecf20Sopenharmony_ci		rp->rx_ring[i].rx_status = 0;
12938c2ecf20Sopenharmony_ci		rp->rx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
12948c2ecf20Sopenharmony_ci		if (rp->rx_skbuff[i]) {
12958c2ecf20Sopenharmony_ci			dma_unmap_single(hwdev,
12968c2ecf20Sopenharmony_ci					 rp->rx_skbuff_dma[i],
12978c2ecf20Sopenharmony_ci					 rp->rx_buf_sz, DMA_FROM_DEVICE);
12988c2ecf20Sopenharmony_ci			dev_kfree_skb(rp->rx_skbuff[i]);
12998c2ecf20Sopenharmony_ci		}
13008c2ecf20Sopenharmony_ci		rp->rx_skbuff[i] = NULL;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_cistatic void alloc_tbufs(struct net_device* dev)
13058c2ecf20Sopenharmony_ci{
13068c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
13078c2ecf20Sopenharmony_ci	dma_addr_t next;
13088c2ecf20Sopenharmony_ci	int i;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	rp->dirty_tx = rp->cur_tx = 0;
13118c2ecf20Sopenharmony_ci	next = rp->tx_ring_dma;
13128c2ecf20Sopenharmony_ci	for (i = 0; i < TX_RING_SIZE; i++) {
13138c2ecf20Sopenharmony_ci		rp->tx_skbuff[i] = NULL;
13148c2ecf20Sopenharmony_ci		rp->tx_ring[i].tx_status = 0;
13158c2ecf20Sopenharmony_ci		rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
13168c2ecf20Sopenharmony_ci		next += sizeof(struct tx_desc);
13178c2ecf20Sopenharmony_ci		rp->tx_ring[i].next_desc = cpu_to_le32(next);
13188c2ecf20Sopenharmony_ci		if (rp->quirks & rqRhineI)
13198c2ecf20Sopenharmony_ci			rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ];
13208c2ecf20Sopenharmony_ci	}
13218c2ecf20Sopenharmony_ci	rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	netdev_reset_queue(dev);
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic void free_tbufs(struct net_device* dev)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
13298c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
13308c2ecf20Sopenharmony_ci	int i;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	for (i = 0; i < TX_RING_SIZE; i++) {
13338c2ecf20Sopenharmony_ci		rp->tx_ring[i].tx_status = 0;
13348c2ecf20Sopenharmony_ci		rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC);
13358c2ecf20Sopenharmony_ci		rp->tx_ring[i].addr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
13368c2ecf20Sopenharmony_ci		if (rp->tx_skbuff[i]) {
13378c2ecf20Sopenharmony_ci			if (rp->tx_skbuff_dma[i]) {
13388c2ecf20Sopenharmony_ci				dma_unmap_single(hwdev,
13398c2ecf20Sopenharmony_ci						 rp->tx_skbuff_dma[i],
13408c2ecf20Sopenharmony_ci						 rp->tx_skbuff[i]->len,
13418c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
13428c2ecf20Sopenharmony_ci			}
13438c2ecf20Sopenharmony_ci			dev_kfree_skb(rp->tx_skbuff[i]);
13448c2ecf20Sopenharmony_ci		}
13458c2ecf20Sopenharmony_ci		rp->tx_skbuff[i] = NULL;
13468c2ecf20Sopenharmony_ci		rp->tx_buf[i] = NULL;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_cistatic void rhine_check_media(struct net_device *dev, unsigned int init_media)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
13538c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (!rp->mii_if.force_media)
13568c2ecf20Sopenharmony_ci		mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (rp->mii_if.full_duplex)
13598c2ecf20Sopenharmony_ci	    iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex,
13608c2ecf20Sopenharmony_ci		   ioaddr + ChipCmd1);
13618c2ecf20Sopenharmony_ci	else
13628c2ecf20Sopenharmony_ci	    iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
13638c2ecf20Sopenharmony_ci		   ioaddr + ChipCmd1);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	netif_info(rp, link, dev, "force_media %d, carrier %d\n",
13668c2ecf20Sopenharmony_ci		   rp->mii_if.force_media, netif_carrier_ok(dev));
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci/* Called after status of force_media possibly changed */
13708c2ecf20Sopenharmony_cistatic void rhine_set_carrier(struct mii_if_info *mii)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct net_device *dev = mii->dev;
13738c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	if (mii->force_media) {
13768c2ecf20Sopenharmony_ci		/* autoneg is off: Link is always assumed to be up */
13778c2ecf20Sopenharmony_ci		if (!netif_carrier_ok(dev))
13788c2ecf20Sopenharmony_ci			netif_carrier_on(dev);
13798c2ecf20Sopenharmony_ci	}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	rhine_check_media(dev, 0);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	netif_info(rp, link, dev, "force_media %d, carrier %d\n",
13848c2ecf20Sopenharmony_ci		   mii->force_media, netif_carrier_ok(dev));
13858c2ecf20Sopenharmony_ci}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci/**
13888c2ecf20Sopenharmony_ci * rhine_set_cam - set CAM multicast filters
13898c2ecf20Sopenharmony_ci * @ioaddr: register block of this Rhine
13908c2ecf20Sopenharmony_ci * @idx: multicast CAM index [0..MCAM_SIZE-1]
13918c2ecf20Sopenharmony_ci * @addr: multicast address (6 bytes)
13928c2ecf20Sopenharmony_ci *
13938c2ecf20Sopenharmony_ci * Load addresses into multicast filters.
13948c2ecf20Sopenharmony_ci */
13958c2ecf20Sopenharmony_cistatic void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	int i;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMEN, ioaddr + CamCon);
14008c2ecf20Sopenharmony_ci	wmb();
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* Paranoid -- idx out of range should never happen */
14038c2ecf20Sopenharmony_ci	idx &= (MCAM_SIZE - 1);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	iowrite8((u8) idx, ioaddr + CamAddr);
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++, addr++)
14088c2ecf20Sopenharmony_ci		iowrite8(*addr, ioaddr + MulticastFilter0 + i);
14098c2ecf20Sopenharmony_ci	udelay(10);
14108c2ecf20Sopenharmony_ci	wmb();
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
14138c2ecf20Sopenharmony_ci	udelay(10);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + CamCon);
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci/**
14198c2ecf20Sopenharmony_ci * rhine_set_vlan_cam - set CAM VLAN filters
14208c2ecf20Sopenharmony_ci * @ioaddr: register block of this Rhine
14218c2ecf20Sopenharmony_ci * @idx: VLAN CAM index [0..VCAM_SIZE-1]
14228c2ecf20Sopenharmony_ci * @addr: VLAN ID (2 bytes)
14238c2ecf20Sopenharmony_ci *
14248c2ecf20Sopenharmony_ci * Load addresses into VLAN filters.
14258c2ecf20Sopenharmony_ci */
14268c2ecf20Sopenharmony_cistatic void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
14298c2ecf20Sopenharmony_ci	wmb();
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	/* Paranoid -- idx out of range should never happen */
14328c2ecf20Sopenharmony_ci	idx &= (VCAM_SIZE - 1);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	iowrite8((u8) idx, ioaddr + CamAddr);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	iowrite16(*((u16 *) addr), ioaddr + MulticastFilter0 + 6);
14378c2ecf20Sopenharmony_ci	udelay(10);
14388c2ecf20Sopenharmony_ci	wmb();
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
14418c2ecf20Sopenharmony_ci	udelay(10);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + CamCon);
14448c2ecf20Sopenharmony_ci}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci/**
14478c2ecf20Sopenharmony_ci * rhine_set_cam_mask - set multicast CAM mask
14488c2ecf20Sopenharmony_ci * @ioaddr: register block of this Rhine
14498c2ecf20Sopenharmony_ci * @mask: multicast CAM mask
14508c2ecf20Sopenharmony_ci *
14518c2ecf20Sopenharmony_ci * Mask sets multicast filters active/inactive.
14528c2ecf20Sopenharmony_ci */
14538c2ecf20Sopenharmony_cistatic void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask)
14548c2ecf20Sopenharmony_ci{
14558c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMEN, ioaddr + CamCon);
14568c2ecf20Sopenharmony_ci	wmb();
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	/* write mask */
14598c2ecf20Sopenharmony_ci	iowrite32(mask, ioaddr + CamMask);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* disable CAMEN */
14628c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + CamCon);
14638c2ecf20Sopenharmony_ci}
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci/**
14668c2ecf20Sopenharmony_ci * rhine_set_vlan_cam_mask - set VLAN CAM mask
14678c2ecf20Sopenharmony_ci * @ioaddr: register block of this Rhine
14688c2ecf20Sopenharmony_ci * @mask: VLAN CAM mask
14698c2ecf20Sopenharmony_ci *
14708c2ecf20Sopenharmony_ci * Mask sets VLAN filters active/inactive.
14718c2ecf20Sopenharmony_ci */
14728c2ecf20Sopenharmony_cistatic void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask)
14738c2ecf20Sopenharmony_ci{
14748c2ecf20Sopenharmony_ci	iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
14758c2ecf20Sopenharmony_ci	wmb();
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	/* write mask */
14788c2ecf20Sopenharmony_ci	iowrite32(mask, ioaddr + CamMask);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	/* disable CAMEN */
14818c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + CamCon);
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci/**
14858c2ecf20Sopenharmony_ci * rhine_init_cam_filter - initialize CAM filters
14868c2ecf20Sopenharmony_ci * @dev: network device
14878c2ecf20Sopenharmony_ci *
14888c2ecf20Sopenharmony_ci * Initialize (disable) hardware VLAN and multicast support on this
14898c2ecf20Sopenharmony_ci * Rhine.
14908c2ecf20Sopenharmony_ci */
14918c2ecf20Sopenharmony_cistatic void rhine_init_cam_filter(struct net_device *dev)
14928c2ecf20Sopenharmony_ci{
14938c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
14948c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/* Disable all CAMs */
14978c2ecf20Sopenharmony_ci	rhine_set_vlan_cam_mask(ioaddr, 0);
14988c2ecf20Sopenharmony_ci	rhine_set_cam_mask(ioaddr, 0);
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	/* disable hardware VLAN support */
15018c2ecf20Sopenharmony_ci	BYTE_REG_BITS_ON(TCR_PQEN, ioaddr + TxConfig);
15028c2ecf20Sopenharmony_ci	BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci/**
15068c2ecf20Sopenharmony_ci * rhine_update_vcam - update VLAN CAM filters
15078c2ecf20Sopenharmony_ci * @dev: rhine_private data of this Rhine
15088c2ecf20Sopenharmony_ci *
15098c2ecf20Sopenharmony_ci * Update VLAN CAM filters to match configuration change.
15108c2ecf20Sopenharmony_ci */
15118c2ecf20Sopenharmony_cistatic void rhine_update_vcam(struct net_device *dev)
15128c2ecf20Sopenharmony_ci{
15138c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
15148c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
15158c2ecf20Sopenharmony_ci	u16 vid;
15168c2ecf20Sopenharmony_ci	u32 vCAMmask = 0;	/* 32 vCAMs (6105M and better) */
15178c2ecf20Sopenharmony_ci	unsigned int i = 0;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	for_each_set_bit(vid, rp->active_vlans, VLAN_N_VID) {
15208c2ecf20Sopenharmony_ci		rhine_set_vlan_cam(ioaddr, i, (u8 *)&vid);
15218c2ecf20Sopenharmony_ci		vCAMmask |= 1 << i;
15228c2ecf20Sopenharmony_ci		if (++i >= VCAM_SIZE)
15238c2ecf20Sopenharmony_ci			break;
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci	rhine_set_vlan_cam_mask(ioaddr, vCAMmask);
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_cistatic int rhine_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
15298c2ecf20Sopenharmony_ci{
15308c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	spin_lock_bh(&rp->lock);
15338c2ecf20Sopenharmony_ci	set_bit(vid, rp->active_vlans);
15348c2ecf20Sopenharmony_ci	rhine_update_vcam(dev);
15358c2ecf20Sopenharmony_ci	spin_unlock_bh(&rp->lock);
15368c2ecf20Sopenharmony_ci	return 0;
15378c2ecf20Sopenharmony_ci}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_cistatic int rhine_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
15408c2ecf20Sopenharmony_ci{
15418c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	spin_lock_bh(&rp->lock);
15448c2ecf20Sopenharmony_ci	clear_bit(vid, rp->active_vlans);
15458c2ecf20Sopenharmony_ci	rhine_update_vcam(dev);
15468c2ecf20Sopenharmony_ci	spin_unlock_bh(&rp->lock);
15478c2ecf20Sopenharmony_ci	return 0;
15488c2ecf20Sopenharmony_ci}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_cistatic void init_registers(struct net_device *dev)
15518c2ecf20Sopenharmony_ci{
15528c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
15538c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
15548c2ecf20Sopenharmony_ci	int i;
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
15578c2ecf20Sopenharmony_ci		iowrite8(dev->dev_addr[i], ioaddr + StationAddr + i);
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	/* Initialize other registers. */
15608c2ecf20Sopenharmony_ci	iowrite16(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
15618c2ecf20Sopenharmony_ci	/* Configure initial FIFO thresholds. */
15628c2ecf20Sopenharmony_ci	iowrite8(0x20, ioaddr + TxConfig);
15638c2ecf20Sopenharmony_ci	rp->tx_thresh = 0x20;
15648c2ecf20Sopenharmony_ci	rp->rx_thresh = 0x60;		/* Written in rhine_set_rx_mode(). */
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	iowrite32(rp->rx_ring_dma, ioaddr + RxRingPtr);
15678c2ecf20Sopenharmony_ci	iowrite32(rp->tx_ring_dma, ioaddr + TxRingPtr);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	rhine_set_rx_mode(dev);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	if (rp->quirks & rqMgmt)
15728c2ecf20Sopenharmony_ci		rhine_init_cam_filter(dev);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	napi_enable(&rp->napi);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci	iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8),
15798c2ecf20Sopenharmony_ci	       ioaddr + ChipCmd);
15808c2ecf20Sopenharmony_ci	rhine_check_media(dev, 1);
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/* Enable MII link status auto-polling (required for IntrLinkChange) */
15848c2ecf20Sopenharmony_cistatic void rhine_enable_linkmon(struct rhine_private *rp)
15858c2ecf20Sopenharmony_ci{
15868c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + MIICmd);
15898c2ecf20Sopenharmony_ci	iowrite8(MII_BMSR, ioaddr + MIIRegAddr);
15908c2ecf20Sopenharmony_ci	iowrite8(0x80, ioaddr + MIICmd);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr);
15958c2ecf20Sopenharmony_ci}
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci/* Disable MII link status auto-polling (required for MDIO access) */
15988c2ecf20Sopenharmony_cistatic void rhine_disable_linkmon(struct rhine_private *rp)
15998c2ecf20Sopenharmony_ci{
16008c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	iowrite8(0, ioaddr + MIICmd);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	if (rp->quirks & rqRhineI) {
16058c2ecf20Sopenharmony_ci		iowrite8(0x01, ioaddr + MIIRegAddr);	// MII_BMSR
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci		/* Can be called from ISR. Evil. */
16088c2ecf20Sopenharmony_ci		mdelay(1);
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci		/* 0x80 must be set immediately before turning it off */
16118c2ecf20Sopenharmony_ci		iowrite8(0x80, ioaddr + MIICmd);
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci		rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci		/* Heh. Now clear 0x80 again. */
16168c2ecf20Sopenharmony_ci		iowrite8(0, ioaddr + MIICmd);
16178c2ecf20Sopenharmony_ci	}
16188c2ecf20Sopenharmony_ci	else
16198c2ecf20Sopenharmony_ci		rhine_wait_bit_high(rp, MIIRegAddr, 0x80);
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci/* Read and write over the MII Management Data I/O (MDIO) interface. */
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int regnum)
16258c2ecf20Sopenharmony_ci{
16268c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
16278c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
16288c2ecf20Sopenharmony_ci	int result;
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	rhine_disable_linkmon(rp);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	/* rhine_disable_linkmon already cleared MIICmd */
16338c2ecf20Sopenharmony_ci	iowrite8(phy_id, ioaddr + MIIPhyAddr);
16348c2ecf20Sopenharmony_ci	iowrite8(regnum, ioaddr + MIIRegAddr);
16358c2ecf20Sopenharmony_ci	iowrite8(0x40, ioaddr + MIICmd);		/* Trigger read */
16368c2ecf20Sopenharmony_ci	rhine_wait_bit_low(rp, MIICmd, 0x40);
16378c2ecf20Sopenharmony_ci	result = ioread16(ioaddr + MIIData);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	rhine_enable_linkmon(rp);
16408c2ecf20Sopenharmony_ci	return result;
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
16448c2ecf20Sopenharmony_ci{
16458c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
16468c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	rhine_disable_linkmon(rp);
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ci	/* rhine_disable_linkmon already cleared MIICmd */
16518c2ecf20Sopenharmony_ci	iowrite8(phy_id, ioaddr + MIIPhyAddr);
16528c2ecf20Sopenharmony_ci	iowrite8(regnum, ioaddr + MIIRegAddr);
16538c2ecf20Sopenharmony_ci	iowrite16(value, ioaddr + MIIData);
16548c2ecf20Sopenharmony_ci	iowrite8(0x20, ioaddr + MIICmd);		/* Trigger write */
16558c2ecf20Sopenharmony_ci	rhine_wait_bit_low(rp, MIICmd, 0x20);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	rhine_enable_linkmon(rp);
16588c2ecf20Sopenharmony_ci}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_cistatic void rhine_task_disable(struct rhine_private *rp)
16618c2ecf20Sopenharmony_ci{
16628c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
16638c2ecf20Sopenharmony_ci	rp->task_enable = false;
16648c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	cancel_work_sync(&rp->slow_event_task);
16678c2ecf20Sopenharmony_ci	cancel_work_sync(&rp->reset_task);
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_cistatic void rhine_task_enable(struct rhine_private *rp)
16718c2ecf20Sopenharmony_ci{
16728c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
16738c2ecf20Sopenharmony_ci	rp->task_enable = true;
16748c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
16758c2ecf20Sopenharmony_ci}
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_cistatic int rhine_open(struct net_device *dev)
16788c2ecf20Sopenharmony_ci{
16798c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
16808c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
16818c2ecf20Sopenharmony_ci	int rc;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	rc = request_irq(rp->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev);
16848c2ecf20Sopenharmony_ci	if (rc)
16858c2ecf20Sopenharmony_ci		goto out;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->irq);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci	rc = alloc_ring(dev);
16908c2ecf20Sopenharmony_ci	if (rc < 0)
16918c2ecf20Sopenharmony_ci		goto out_free_irq;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	rc = alloc_rbufs(dev);
16948c2ecf20Sopenharmony_ci	if (rc < 0)
16958c2ecf20Sopenharmony_ci		goto out_free_ring;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	alloc_tbufs(dev);
16988c2ecf20Sopenharmony_ci	enable_mmio(rp->pioaddr, rp->quirks);
16998c2ecf20Sopenharmony_ci	rhine_power_init(dev);
17008c2ecf20Sopenharmony_ci	rhine_chip_reset(dev);
17018c2ecf20Sopenharmony_ci	rhine_task_enable(rp);
17028c2ecf20Sopenharmony_ci	init_registers(dev);
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n",
17058c2ecf20Sopenharmony_ci		  __func__, ioread16(ioaddr + ChipCmd),
17068c2ecf20Sopenharmony_ci		  mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	netif_start_queue(dev);
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ciout:
17118c2ecf20Sopenharmony_ci	return rc;
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ciout_free_ring:
17148c2ecf20Sopenharmony_ci	free_ring(dev);
17158c2ecf20Sopenharmony_ciout_free_irq:
17168c2ecf20Sopenharmony_ci	free_irq(rp->irq, dev);
17178c2ecf20Sopenharmony_ci	goto out;
17188c2ecf20Sopenharmony_ci}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_cistatic void rhine_reset_task(struct work_struct *work)
17218c2ecf20Sopenharmony_ci{
17228c2ecf20Sopenharmony_ci	struct rhine_private *rp = container_of(work, struct rhine_private,
17238c2ecf20Sopenharmony_ci						reset_task);
17248c2ecf20Sopenharmony_ci	struct net_device *dev = rp->dev;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	if (!rp->task_enable)
17298c2ecf20Sopenharmony_ci		goto out_unlock;
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	napi_disable(&rp->napi);
17328c2ecf20Sopenharmony_ci	netif_tx_disable(dev);
17338c2ecf20Sopenharmony_ci	spin_lock_bh(&rp->lock);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	/* clear all descriptors */
17368c2ecf20Sopenharmony_ci	free_tbufs(dev);
17378c2ecf20Sopenharmony_ci	alloc_tbufs(dev);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	rhine_reset_rbufs(rp);
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	/* Reinitialize the hardware. */
17428c2ecf20Sopenharmony_ci	rhine_chip_reset(dev);
17438c2ecf20Sopenharmony_ci	init_registers(dev);
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	spin_unlock_bh(&rp->lock);
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	netif_trans_update(dev); /* prevent tx timeout */
17488c2ecf20Sopenharmony_ci	dev->stats.tx_errors++;
17498c2ecf20Sopenharmony_ci	netif_wake_queue(dev);
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ciout_unlock:
17528c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
17538c2ecf20Sopenharmony_ci}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_cistatic void rhine_tx_timeout(struct net_device *dev, unsigned int txqueue)
17568c2ecf20Sopenharmony_ci{
17578c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
17588c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n",
17618c2ecf20Sopenharmony_ci		    ioread16(ioaddr + IntrStatus),
17628c2ecf20Sopenharmony_ci		    mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	schedule_work(&rp->reset_task);
17658c2ecf20Sopenharmony_ci}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_cistatic inline bool rhine_tx_queue_full(struct rhine_private *rp)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	return (rp->cur_tx - rp->dirty_tx) >= TX_QUEUE_LEN;
17708c2ecf20Sopenharmony_ci}
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_cistatic netdev_tx_t rhine_start_tx(struct sk_buff *skb,
17738c2ecf20Sopenharmony_ci				  struct net_device *dev)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
17768c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
17778c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
17788c2ecf20Sopenharmony_ci	unsigned entry;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	/* Caution: the write order is important here, set the field
17818c2ecf20Sopenharmony_ci	   with the "ownership" bits last. */
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	/* Calculate the next Tx descriptor entry. */
17848c2ecf20Sopenharmony_ci	entry = rp->cur_tx % TX_RING_SIZE;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	if (skb_padto(skb, ETH_ZLEN))
17878c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	rp->tx_skbuff[entry] = skb;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	if ((rp->quirks & rqRhineI) &&
17928c2ecf20Sopenharmony_ci	    (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_PARTIAL)) {
17938c2ecf20Sopenharmony_ci		/* Must use alignment buffer. */
17948c2ecf20Sopenharmony_ci		if (skb->len > PKT_BUF_SZ) {
17958c2ecf20Sopenharmony_ci			/* packet too long, drop it */
17968c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
17978c2ecf20Sopenharmony_ci			rp->tx_skbuff[entry] = NULL;
17988c2ecf20Sopenharmony_ci			dev->stats.tx_dropped++;
17998c2ecf20Sopenharmony_ci			return NETDEV_TX_OK;
18008c2ecf20Sopenharmony_ci		}
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		/* Padding is not copied and so must be redone. */
18038c2ecf20Sopenharmony_ci		skb_copy_and_csum_dev(skb, rp->tx_buf[entry]);
18048c2ecf20Sopenharmony_ci		if (skb->len < ETH_ZLEN)
18058c2ecf20Sopenharmony_ci			memset(rp->tx_buf[entry] + skb->len, 0,
18068c2ecf20Sopenharmony_ci			       ETH_ZLEN - skb->len);
18078c2ecf20Sopenharmony_ci		rp->tx_skbuff_dma[entry] = 0;
18088c2ecf20Sopenharmony_ci		rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_bufs_dma +
18098c2ecf20Sopenharmony_ci						      (rp->tx_buf[entry] -
18108c2ecf20Sopenharmony_ci						       rp->tx_bufs));
18118c2ecf20Sopenharmony_ci	} else {
18128c2ecf20Sopenharmony_ci		rp->tx_skbuff_dma[entry] =
18138c2ecf20Sopenharmony_ci			dma_map_single(hwdev, skb->data, skb->len,
18148c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
18158c2ecf20Sopenharmony_ci		if (dma_mapping_error(hwdev, rp->tx_skbuff_dma[entry])) {
18168c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
18178c2ecf20Sopenharmony_ci			rp->tx_skbuff_dma[entry] = 0;
18188c2ecf20Sopenharmony_ci			dev->stats.tx_dropped++;
18198c2ecf20Sopenharmony_ci			return NETDEV_TX_OK;
18208c2ecf20Sopenharmony_ci		}
18218c2ecf20Sopenharmony_ci		rp->tx_ring[entry].addr = cpu_to_le32(rp->tx_skbuff_dma[entry]);
18228c2ecf20Sopenharmony_ci	}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	rp->tx_ring[entry].desc_length =
18258c2ecf20Sopenharmony_ci		cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	if (unlikely(skb_vlan_tag_present(skb))) {
18288c2ecf20Sopenharmony_ci		u16 vid_pcp = skb_vlan_tag_get(skb);
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		/* drop CFI/DEI bit, register needs VID and PCP */
18318c2ecf20Sopenharmony_ci		vid_pcp = (vid_pcp & VLAN_VID_MASK) |
18328c2ecf20Sopenharmony_ci			  ((vid_pcp & VLAN_PRIO_MASK) >> 1);
18338c2ecf20Sopenharmony_ci		rp->tx_ring[entry].tx_status = cpu_to_le32((vid_pcp) << 16);
18348c2ecf20Sopenharmony_ci		/* request tagging */
18358c2ecf20Sopenharmony_ci		rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci	else
18388c2ecf20Sopenharmony_ci		rp->tx_ring[entry].tx_status = 0;
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci	netdev_sent_queue(dev, skb->len);
18418c2ecf20Sopenharmony_ci	/* lock eth irq */
18428c2ecf20Sopenharmony_ci	dma_wmb();
18438c2ecf20Sopenharmony_ci	rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
18448c2ecf20Sopenharmony_ci	wmb();
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	rp->cur_tx++;
18478c2ecf20Sopenharmony_ci	/*
18488c2ecf20Sopenharmony_ci	 * Nobody wants cur_tx write to rot for ages after the NIC will have
18498c2ecf20Sopenharmony_ci	 * seen the transmit request, especially as the transmit completion
18508c2ecf20Sopenharmony_ci	 * handler could miss it.
18518c2ecf20Sopenharmony_ci	 */
18528c2ecf20Sopenharmony_ci	smp_wmb();
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	/* Non-x86 Todo: explicitly flush cache lines here. */
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	if (skb_vlan_tag_present(skb))
18578c2ecf20Sopenharmony_ci		/* Tx queues are bits 7-0 (first Tx queue: bit 7) */
18588c2ecf20Sopenharmony_ci		BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	/* Wake the potentially-idle transmit channel */
18618c2ecf20Sopenharmony_ci	iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
18628c2ecf20Sopenharmony_ci	       ioaddr + ChipCmd1);
18638c2ecf20Sopenharmony_ci	IOSYNC;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/* dirty_tx may be pessimistically out-of-sync. See rhine_tx. */
18668c2ecf20Sopenharmony_ci	if (rhine_tx_queue_full(rp)) {
18678c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
18688c2ecf20Sopenharmony_ci		smp_rmb();
18698c2ecf20Sopenharmony_ci		/* Rejuvenate. */
18708c2ecf20Sopenharmony_ci		if (!rhine_tx_queue_full(rp))
18718c2ecf20Sopenharmony_ci			netif_wake_queue(dev);
18728c2ecf20Sopenharmony_ci	}
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n",
18758c2ecf20Sopenharmony_ci		  rp->cur_tx - 1, entry);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
18788c2ecf20Sopenharmony_ci}
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_cistatic void rhine_irq_disable(struct rhine_private *rp)
18818c2ecf20Sopenharmony_ci{
18828c2ecf20Sopenharmony_ci	iowrite16(0x0000, rp->base + IntrEnable);
18838c2ecf20Sopenharmony_ci}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up
18868c2ecf20Sopenharmony_ci   after the Tx thread. */
18878c2ecf20Sopenharmony_cistatic irqreturn_t rhine_interrupt(int irq, void *dev_instance)
18888c2ecf20Sopenharmony_ci{
18898c2ecf20Sopenharmony_ci	struct net_device *dev = dev_instance;
18908c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
18918c2ecf20Sopenharmony_ci	u32 status;
18928c2ecf20Sopenharmony_ci	int handled = 0;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	status = rhine_get_events(rp);
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status);
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (status & RHINE_EVENT) {
18998c2ecf20Sopenharmony_ci		handled = 1;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci		rhine_irq_disable(rp);
19028c2ecf20Sopenharmony_ci		napi_schedule(&rp->napi);
19038c2ecf20Sopenharmony_ci	}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) {
19068c2ecf20Sopenharmony_ci		netif_err(rp, intr, dev, "Something Wicked happened! %08x\n",
19078c2ecf20Sopenharmony_ci			  status);
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	return IRQ_RETVAL(handled);
19118c2ecf20Sopenharmony_ci}
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci/* This routine is logically part of the interrupt handler, but isolated
19148c2ecf20Sopenharmony_ci   for clarity. */
19158c2ecf20Sopenharmony_cistatic void rhine_tx(struct net_device *dev)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
19188c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
19198c2ecf20Sopenharmony_ci	unsigned int pkts_compl = 0, bytes_compl = 0;
19208c2ecf20Sopenharmony_ci	unsigned int dirty_tx = rp->dirty_tx;
19218c2ecf20Sopenharmony_ci	unsigned int cur_tx;
19228c2ecf20Sopenharmony_ci	struct sk_buff *skb;
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	/*
19258c2ecf20Sopenharmony_ci	 * The race with rhine_start_tx does not matter here as long as the
19268c2ecf20Sopenharmony_ci	 * driver enforces a value of cur_tx that was relevant when the
19278c2ecf20Sopenharmony_ci	 * packet was scheduled to the network chipset.
19288c2ecf20Sopenharmony_ci	 * Executive summary: smp_rmb() balances smp_wmb() in rhine_start_tx.
19298c2ecf20Sopenharmony_ci	 */
19308c2ecf20Sopenharmony_ci	smp_rmb();
19318c2ecf20Sopenharmony_ci	cur_tx = rp->cur_tx;
19328c2ecf20Sopenharmony_ci	/* find and cleanup dirty tx descriptors */
19338c2ecf20Sopenharmony_ci	while (dirty_tx != cur_tx) {
19348c2ecf20Sopenharmony_ci		unsigned int entry = dirty_tx % TX_RING_SIZE;
19358c2ecf20Sopenharmony_ci		u32 txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
19368c2ecf20Sopenharmony_ci
19378c2ecf20Sopenharmony_ci		netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n",
19388c2ecf20Sopenharmony_ci			  entry, txstatus);
19398c2ecf20Sopenharmony_ci		if (txstatus & DescOwn)
19408c2ecf20Sopenharmony_ci			break;
19418c2ecf20Sopenharmony_ci		skb = rp->tx_skbuff[entry];
19428c2ecf20Sopenharmony_ci		if (txstatus & 0x8000) {
19438c2ecf20Sopenharmony_ci			netif_dbg(rp, tx_done, dev,
19448c2ecf20Sopenharmony_ci				  "Transmit error, Tx status %08x\n", txstatus);
19458c2ecf20Sopenharmony_ci			dev->stats.tx_errors++;
19468c2ecf20Sopenharmony_ci			if (txstatus & 0x0400)
19478c2ecf20Sopenharmony_ci				dev->stats.tx_carrier_errors++;
19488c2ecf20Sopenharmony_ci			if (txstatus & 0x0200)
19498c2ecf20Sopenharmony_ci				dev->stats.tx_window_errors++;
19508c2ecf20Sopenharmony_ci			if (txstatus & 0x0100)
19518c2ecf20Sopenharmony_ci				dev->stats.tx_aborted_errors++;
19528c2ecf20Sopenharmony_ci			if (txstatus & 0x0080)
19538c2ecf20Sopenharmony_ci				dev->stats.tx_heartbeat_errors++;
19548c2ecf20Sopenharmony_ci			if (((rp->quirks & rqRhineI) && txstatus & 0x0002) ||
19558c2ecf20Sopenharmony_ci			    (txstatus & 0x0800) || (txstatus & 0x1000)) {
19568c2ecf20Sopenharmony_ci				dev->stats.tx_fifo_errors++;
19578c2ecf20Sopenharmony_ci				rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
19588c2ecf20Sopenharmony_ci				break; /* Keep the skb - we try again */
19598c2ecf20Sopenharmony_ci			}
19608c2ecf20Sopenharmony_ci			/* Transmitter restarted in 'abnormal' handler. */
19618c2ecf20Sopenharmony_ci		} else {
19628c2ecf20Sopenharmony_ci			if (rp->quirks & rqRhineI)
19638c2ecf20Sopenharmony_ci				dev->stats.collisions += (txstatus >> 3) & 0x0F;
19648c2ecf20Sopenharmony_ci			else
19658c2ecf20Sopenharmony_ci				dev->stats.collisions += txstatus & 0x0F;
19668c2ecf20Sopenharmony_ci			netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
19678c2ecf20Sopenharmony_ci				  (txstatus >> 3) & 0xF, txstatus & 0xF);
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci			u64_stats_update_begin(&rp->tx_stats.syncp);
19708c2ecf20Sopenharmony_ci			rp->tx_stats.bytes += skb->len;
19718c2ecf20Sopenharmony_ci			rp->tx_stats.packets++;
19728c2ecf20Sopenharmony_ci			u64_stats_update_end(&rp->tx_stats.syncp);
19738c2ecf20Sopenharmony_ci		}
19748c2ecf20Sopenharmony_ci		/* Free the original skb. */
19758c2ecf20Sopenharmony_ci		if (rp->tx_skbuff_dma[entry]) {
19768c2ecf20Sopenharmony_ci			dma_unmap_single(hwdev,
19778c2ecf20Sopenharmony_ci					 rp->tx_skbuff_dma[entry],
19788c2ecf20Sopenharmony_ci					 skb->len,
19798c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
19808c2ecf20Sopenharmony_ci		}
19818c2ecf20Sopenharmony_ci		bytes_compl += skb->len;
19828c2ecf20Sopenharmony_ci		pkts_compl++;
19838c2ecf20Sopenharmony_ci		dev_consume_skb_any(skb);
19848c2ecf20Sopenharmony_ci		rp->tx_skbuff[entry] = NULL;
19858c2ecf20Sopenharmony_ci		dirty_tx++;
19868c2ecf20Sopenharmony_ci	}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	rp->dirty_tx = dirty_tx;
19898c2ecf20Sopenharmony_ci	/* Pity we can't rely on the nearby BQL completion implicit barrier. */
19908c2ecf20Sopenharmony_ci	smp_wmb();
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	netdev_completed_queue(dev, pkts_compl, bytes_compl);
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	/* cur_tx may be optimistically out-of-sync. See rhine_start_tx. */
19958c2ecf20Sopenharmony_ci	if (!rhine_tx_queue_full(rp) && netif_queue_stopped(dev)) {
19968c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
19978c2ecf20Sopenharmony_ci		smp_rmb();
19988c2ecf20Sopenharmony_ci		/* Rejuvenate. */
19998c2ecf20Sopenharmony_ci		if (rhine_tx_queue_full(rp))
20008c2ecf20Sopenharmony_ci			netif_stop_queue(dev);
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci/**
20058c2ecf20Sopenharmony_ci * rhine_get_vlan_tci - extract TCI from Rx data buffer
20068c2ecf20Sopenharmony_ci * @skb: pointer to sk_buff
20078c2ecf20Sopenharmony_ci * @data_size: used data area of the buffer including CRC
20088c2ecf20Sopenharmony_ci *
20098c2ecf20Sopenharmony_ci * If hardware VLAN tag extraction is enabled and the chip indicates a 802.1Q
20108c2ecf20Sopenharmony_ci * packet, the extracted 802.1Q header (2 bytes TPID + 2 bytes TCI) is 4-byte
20118c2ecf20Sopenharmony_ci * aligned following the CRC.
20128c2ecf20Sopenharmony_ci */
20138c2ecf20Sopenharmony_cistatic inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
20148c2ecf20Sopenharmony_ci{
20158c2ecf20Sopenharmony_ci	u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2;
20168c2ecf20Sopenharmony_ci	return be16_to_cpup((__be16 *)trailer);
20178c2ecf20Sopenharmony_ci}
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_cistatic inline void rhine_rx_vlan_tag(struct sk_buff *skb, struct rx_desc *desc,
20208c2ecf20Sopenharmony_ci				     int data_size)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	dma_rmb();
20238c2ecf20Sopenharmony_ci	if (unlikely(desc->desc_length & cpu_to_le32(DescTag))) {
20248c2ecf20Sopenharmony_ci		u16 vlan_tci;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci		vlan_tci = rhine_get_vlan_tci(skb, data_size);
20278c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci/* Process up to limit frames from receive ring */
20328c2ecf20Sopenharmony_cistatic int rhine_rx(struct net_device *dev, int limit)
20338c2ecf20Sopenharmony_ci{
20348c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
20358c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
20368c2ecf20Sopenharmony_ci	int entry = rp->cur_rx % RX_RING_SIZE;
20378c2ecf20Sopenharmony_ci	int count;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci	netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__,
20408c2ecf20Sopenharmony_ci		  entry, le32_to_cpu(rp->rx_ring[entry].rx_status));
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/* If EOP is set on the next entry, it's a new packet. Send it up. */
20438c2ecf20Sopenharmony_ci	for (count = 0; count < limit; ++count) {
20448c2ecf20Sopenharmony_ci		struct rx_desc *desc = rp->rx_ring + entry;
20458c2ecf20Sopenharmony_ci		u32 desc_status = le32_to_cpu(desc->rx_status);
20468c2ecf20Sopenharmony_ci		int data_size = desc_status >> 16;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci		if (desc_status & DescOwn)
20498c2ecf20Sopenharmony_ci			break;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci		netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__,
20528c2ecf20Sopenharmony_ci			  desc_status);
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_ci		if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
20558c2ecf20Sopenharmony_ci			if ((desc_status & RxWholePkt) != RxWholePkt) {
20568c2ecf20Sopenharmony_ci				netdev_warn(dev,
20578c2ecf20Sopenharmony_ci	"Oversized Ethernet frame spanned multiple buffers, "
20588c2ecf20Sopenharmony_ci	"entry %#x length %d status %08x!\n",
20598c2ecf20Sopenharmony_ci					    entry, data_size,
20608c2ecf20Sopenharmony_ci					    desc_status);
20618c2ecf20Sopenharmony_ci				dev->stats.rx_length_errors++;
20628c2ecf20Sopenharmony_ci			} else if (desc_status & RxErr) {
20638c2ecf20Sopenharmony_ci				/* There was a error. */
20648c2ecf20Sopenharmony_ci				netif_dbg(rp, rx_err, dev,
20658c2ecf20Sopenharmony_ci					  "%s() Rx error %08x\n", __func__,
20668c2ecf20Sopenharmony_ci					  desc_status);
20678c2ecf20Sopenharmony_ci				dev->stats.rx_errors++;
20688c2ecf20Sopenharmony_ci				if (desc_status & 0x0030)
20698c2ecf20Sopenharmony_ci					dev->stats.rx_length_errors++;
20708c2ecf20Sopenharmony_ci				if (desc_status & 0x0048)
20718c2ecf20Sopenharmony_ci					dev->stats.rx_fifo_errors++;
20728c2ecf20Sopenharmony_ci				if (desc_status & 0x0004)
20738c2ecf20Sopenharmony_ci					dev->stats.rx_frame_errors++;
20748c2ecf20Sopenharmony_ci				if (desc_status & 0x0002) {
20758c2ecf20Sopenharmony_ci					/* this can also be updated outside the interrupt handler */
20768c2ecf20Sopenharmony_ci					spin_lock(&rp->lock);
20778c2ecf20Sopenharmony_ci					dev->stats.rx_crc_errors++;
20788c2ecf20Sopenharmony_ci					spin_unlock(&rp->lock);
20798c2ecf20Sopenharmony_ci				}
20808c2ecf20Sopenharmony_ci			}
20818c2ecf20Sopenharmony_ci		} else {
20828c2ecf20Sopenharmony_ci			/* Length should omit the CRC */
20838c2ecf20Sopenharmony_ci			int pkt_len = data_size - 4;
20848c2ecf20Sopenharmony_ci			struct sk_buff *skb;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci			/* Check if the packet is long enough to accept without
20878c2ecf20Sopenharmony_ci			   copying to a minimally-sized skbuff. */
20888c2ecf20Sopenharmony_ci			if (pkt_len < rx_copybreak) {
20898c2ecf20Sopenharmony_ci				skb = netdev_alloc_skb_ip_align(dev, pkt_len);
20908c2ecf20Sopenharmony_ci				if (unlikely(!skb))
20918c2ecf20Sopenharmony_ci					goto drop;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci				dma_sync_single_for_cpu(hwdev,
20948c2ecf20Sopenharmony_ci							rp->rx_skbuff_dma[entry],
20958c2ecf20Sopenharmony_ci							rp->rx_buf_sz,
20968c2ecf20Sopenharmony_ci							DMA_FROM_DEVICE);
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci				skb_copy_to_linear_data(skb,
20998c2ecf20Sopenharmony_ci						 rp->rx_skbuff[entry]->data,
21008c2ecf20Sopenharmony_ci						 pkt_len);
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci				dma_sync_single_for_device(hwdev,
21038c2ecf20Sopenharmony_ci							   rp->rx_skbuff_dma[entry],
21048c2ecf20Sopenharmony_ci							   rp->rx_buf_sz,
21058c2ecf20Sopenharmony_ci							   DMA_FROM_DEVICE);
21068c2ecf20Sopenharmony_ci			} else {
21078c2ecf20Sopenharmony_ci				struct rhine_skb_dma sd;
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci				if (unlikely(rhine_skb_dma_init(dev, &sd) < 0))
21108c2ecf20Sopenharmony_ci					goto drop;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci				skb = rp->rx_skbuff[entry];
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci				dma_unmap_single(hwdev,
21158c2ecf20Sopenharmony_ci						 rp->rx_skbuff_dma[entry],
21168c2ecf20Sopenharmony_ci						 rp->rx_buf_sz,
21178c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
21188c2ecf20Sopenharmony_ci				rhine_skb_dma_nic_store(rp, &sd, entry);
21198c2ecf20Sopenharmony_ci			}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci			skb_put(skb, pkt_len);
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci			rhine_rx_vlan_tag(skb, desc, data_size);
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci			skb->protocol = eth_type_trans(skb, dev);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci			netif_receive_skb(skb);
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci			u64_stats_update_begin(&rp->rx_stats.syncp);
21308c2ecf20Sopenharmony_ci			rp->rx_stats.bytes += pkt_len;
21318c2ecf20Sopenharmony_ci			rp->rx_stats.packets++;
21328c2ecf20Sopenharmony_ci			u64_stats_update_end(&rp->rx_stats.syncp);
21338c2ecf20Sopenharmony_ci		}
21348c2ecf20Sopenharmony_cigive_descriptor_to_nic:
21358c2ecf20Sopenharmony_ci		desc->rx_status = cpu_to_le32(DescOwn);
21368c2ecf20Sopenharmony_ci		entry = (++rp->cur_rx) % RX_RING_SIZE;
21378c2ecf20Sopenharmony_ci	}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci	return count;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_cidrop:
21428c2ecf20Sopenharmony_ci	dev->stats.rx_dropped++;
21438c2ecf20Sopenharmony_ci	goto give_descriptor_to_nic;
21448c2ecf20Sopenharmony_ci}
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_cistatic void rhine_restart_tx(struct net_device *dev) {
21478c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
21488c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
21498c2ecf20Sopenharmony_ci	int entry = rp->dirty_tx % TX_RING_SIZE;
21508c2ecf20Sopenharmony_ci	u32 intr_status;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	/*
21538c2ecf20Sopenharmony_ci	 * If new errors occurred, we need to sort them out before doing Tx.
21548c2ecf20Sopenharmony_ci	 * In that case the ISR will be back here RSN anyway.
21558c2ecf20Sopenharmony_ci	 */
21568c2ecf20Sopenharmony_ci	intr_status = rhine_get_events(rp);
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	if ((intr_status & IntrTxErrSummary) == 0) {
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci		/* We know better than the chip where it should continue. */
21618c2ecf20Sopenharmony_ci		iowrite32(rp->tx_ring_dma + entry * sizeof(struct tx_desc),
21628c2ecf20Sopenharmony_ci		       ioaddr + TxRingPtr);
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + ChipCmd) | CmdTxOn,
21658c2ecf20Sopenharmony_ci		       ioaddr + ChipCmd);
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci		if (rp->tx_ring[entry].desc_length & cpu_to_le32(0x020000))
21688c2ecf20Sopenharmony_ci			/* Tx queues are bits 7-0 (first Tx queue: bit 7) */
21698c2ecf20Sopenharmony_ci			BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
21728c2ecf20Sopenharmony_ci		       ioaddr + ChipCmd1);
21738c2ecf20Sopenharmony_ci		IOSYNC;
21748c2ecf20Sopenharmony_ci	}
21758c2ecf20Sopenharmony_ci	else {
21768c2ecf20Sopenharmony_ci		/* This should never happen */
21778c2ecf20Sopenharmony_ci		netif_warn(rp, tx_err, dev, "another error occurred %08x\n",
21788c2ecf20Sopenharmony_ci			   intr_status);
21798c2ecf20Sopenharmony_ci	}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci}
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_cistatic void rhine_slow_event_task(struct work_struct *work)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	struct rhine_private *rp =
21868c2ecf20Sopenharmony_ci		container_of(work, struct rhine_private, slow_event_task);
21878c2ecf20Sopenharmony_ci	struct net_device *dev = rp->dev;
21888c2ecf20Sopenharmony_ci	u32 intr_status;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	if (!rp->task_enable)
21938c2ecf20Sopenharmony_ci		goto out_unlock;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	intr_status = rhine_get_events(rp);
21968c2ecf20Sopenharmony_ci	rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW);
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	if (intr_status & IntrLinkChange)
21998c2ecf20Sopenharmony_ci		rhine_check_media(dev, 0);
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	if (intr_status & IntrPCIErr)
22028c2ecf20Sopenharmony_ci		netif_warn(rp, hw, dev, "PCI error\n");
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable);
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ciout_unlock:
22078c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_cistatic void
22118c2ecf20Sopenharmony_cirhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
22128c2ecf20Sopenharmony_ci{
22138c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
22148c2ecf20Sopenharmony_ci	unsigned int start;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	spin_lock_bh(&rp->lock);
22178c2ecf20Sopenharmony_ci	rhine_update_rx_crc_and_missed_errord(rp);
22188c2ecf20Sopenharmony_ci	spin_unlock_bh(&rp->lock);
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	netdev_stats_to_stats64(stats, &dev->stats);
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	do {
22238c2ecf20Sopenharmony_ci		start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp);
22248c2ecf20Sopenharmony_ci		stats->rx_packets = rp->rx_stats.packets;
22258c2ecf20Sopenharmony_ci		stats->rx_bytes = rp->rx_stats.bytes;
22268c2ecf20Sopenharmony_ci	} while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start));
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	do {
22298c2ecf20Sopenharmony_ci		start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp);
22308c2ecf20Sopenharmony_ci		stats->tx_packets = rp->tx_stats.packets;
22318c2ecf20Sopenharmony_ci		stats->tx_bytes = rp->tx_stats.bytes;
22328c2ecf20Sopenharmony_ci	} while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start));
22338c2ecf20Sopenharmony_ci}
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_cistatic void rhine_set_rx_mode(struct net_device *dev)
22368c2ecf20Sopenharmony_ci{
22378c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
22388c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
22398c2ecf20Sopenharmony_ci	u32 mc_filter[2];	/* Multicast hash filter */
22408c2ecf20Sopenharmony_ci	u8 rx_mode = 0x0C;	/* Note: 0x02=accept runt, 0x01=accept errs */
22418c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {		/* Set promiscuous. */
22448c2ecf20Sopenharmony_ci		rx_mode = 0x1C;
22458c2ecf20Sopenharmony_ci		iowrite32(0xffffffff, ioaddr + MulticastFilter0);
22468c2ecf20Sopenharmony_ci		iowrite32(0xffffffff, ioaddr + MulticastFilter1);
22478c2ecf20Sopenharmony_ci	} else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
22488c2ecf20Sopenharmony_ci		   (dev->flags & IFF_ALLMULTI)) {
22498c2ecf20Sopenharmony_ci		/* Too many to match, or accept all multicasts. */
22508c2ecf20Sopenharmony_ci		iowrite32(0xffffffff, ioaddr + MulticastFilter0);
22518c2ecf20Sopenharmony_ci		iowrite32(0xffffffff, ioaddr + MulticastFilter1);
22528c2ecf20Sopenharmony_ci	} else if (rp->quirks & rqMgmt) {
22538c2ecf20Sopenharmony_ci		int i = 0;
22548c2ecf20Sopenharmony_ci		u32 mCAMmask = 0;	/* 32 mCAMs (6105M and better) */
22558c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
22568c2ecf20Sopenharmony_ci			if (i == MCAM_SIZE)
22578c2ecf20Sopenharmony_ci				break;
22588c2ecf20Sopenharmony_ci			rhine_set_cam(ioaddr, i, ha->addr);
22598c2ecf20Sopenharmony_ci			mCAMmask |= 1 << i;
22608c2ecf20Sopenharmony_ci			i++;
22618c2ecf20Sopenharmony_ci		}
22628c2ecf20Sopenharmony_ci		rhine_set_cam_mask(ioaddr, mCAMmask);
22638c2ecf20Sopenharmony_ci	} else {
22648c2ecf20Sopenharmony_ci		memset(mc_filter, 0, sizeof(mc_filter));
22658c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, dev) {
22668c2ecf20Sopenharmony_ci			int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
22698c2ecf20Sopenharmony_ci		}
22708c2ecf20Sopenharmony_ci		iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
22718c2ecf20Sopenharmony_ci		iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
22728c2ecf20Sopenharmony_ci	}
22738c2ecf20Sopenharmony_ci	/* enable/disable VLAN receive filtering */
22748c2ecf20Sopenharmony_ci	if (rp->quirks & rqMgmt) {
22758c2ecf20Sopenharmony_ci		if (dev->flags & IFF_PROMISC)
22768c2ecf20Sopenharmony_ci			BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
22778c2ecf20Sopenharmony_ci		else
22788c2ecf20Sopenharmony_ci			BYTE_REG_BITS_ON(BCR1_VIDFR, ioaddr + PCIBusConfig1);
22798c2ecf20Sopenharmony_ci	}
22808c2ecf20Sopenharmony_ci	BYTE_REG_BITS_ON(rx_mode, ioaddr + RxConfig);
22818c2ecf20Sopenharmony_ci}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_cistatic void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
22848c2ecf20Sopenharmony_ci{
22858c2ecf20Sopenharmony_ci	struct device *hwdev = dev->dev.parent;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
22888c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, dev_name(hwdev), sizeof(info->bus_info));
22898c2ecf20Sopenharmony_ci}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_cistatic int netdev_get_link_ksettings(struct net_device *dev,
22928c2ecf20Sopenharmony_ci				     struct ethtool_link_ksettings *cmd)
22938c2ecf20Sopenharmony_ci{
22948c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
22978c2ecf20Sopenharmony_ci	mii_ethtool_get_link_ksettings(&rp->mii_if, cmd);
22988c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_ci	return 0;
23018c2ecf20Sopenharmony_ci}
23028c2ecf20Sopenharmony_ci
23038c2ecf20Sopenharmony_cistatic int netdev_set_link_ksettings(struct net_device *dev,
23048c2ecf20Sopenharmony_ci				     const struct ethtool_link_ksettings *cmd)
23058c2ecf20Sopenharmony_ci{
23068c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23078c2ecf20Sopenharmony_ci	int rc;
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
23108c2ecf20Sopenharmony_ci	rc = mii_ethtool_set_link_ksettings(&rp->mii_if, cmd);
23118c2ecf20Sopenharmony_ci	rhine_set_carrier(&rp->mii_if);
23128c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	return rc;
23158c2ecf20Sopenharmony_ci}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_cistatic int netdev_nway_reset(struct net_device *dev)
23188c2ecf20Sopenharmony_ci{
23198c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	return mii_nway_restart(&rp->mii_if);
23228c2ecf20Sopenharmony_ci}
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_cistatic u32 netdev_get_link(struct net_device *dev)
23258c2ecf20Sopenharmony_ci{
23268c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	return mii_link_ok(&rp->mii_if);
23298c2ecf20Sopenharmony_ci}
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_cistatic u32 netdev_get_msglevel(struct net_device *dev)
23328c2ecf20Sopenharmony_ci{
23338c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	return rp->msg_enable;
23368c2ecf20Sopenharmony_ci}
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_cistatic void netdev_set_msglevel(struct net_device *dev, u32 value)
23398c2ecf20Sopenharmony_ci{
23408c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci	rp->msg_enable = value;
23438c2ecf20Sopenharmony_ci}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_cistatic void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
23468c2ecf20Sopenharmony_ci{
23478c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	if (!(rp->quirks & rqWOL))
23508c2ecf20Sopenharmony_ci		return;
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci	spin_lock_irq(&rp->lock);
23538c2ecf20Sopenharmony_ci	wol->supported = WAKE_PHY | WAKE_MAGIC |
23548c2ecf20Sopenharmony_ci			 WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;	/* Untested */
23558c2ecf20Sopenharmony_ci	wol->wolopts = rp->wolopts;
23568c2ecf20Sopenharmony_ci	spin_unlock_irq(&rp->lock);
23578c2ecf20Sopenharmony_ci}
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_cistatic int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
23608c2ecf20Sopenharmony_ci{
23618c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23628c2ecf20Sopenharmony_ci	u32 support = WAKE_PHY | WAKE_MAGIC |
23638c2ecf20Sopenharmony_ci		      WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;	/* Untested */
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci	if (!(rp->quirks & rqWOL))
23668c2ecf20Sopenharmony_ci		return -EINVAL;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci	if (wol->wolopts & ~support)
23698c2ecf20Sopenharmony_ci		return -EINVAL;
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	spin_lock_irq(&rp->lock);
23728c2ecf20Sopenharmony_ci	rp->wolopts = wol->wolopts;
23738c2ecf20Sopenharmony_ci	spin_unlock_irq(&rp->lock);
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	return 0;
23768c2ecf20Sopenharmony_ci}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = {
23798c2ecf20Sopenharmony_ci	.get_drvinfo		= netdev_get_drvinfo,
23808c2ecf20Sopenharmony_ci	.nway_reset		= netdev_nway_reset,
23818c2ecf20Sopenharmony_ci	.get_link		= netdev_get_link,
23828c2ecf20Sopenharmony_ci	.get_msglevel		= netdev_get_msglevel,
23838c2ecf20Sopenharmony_ci	.set_msglevel		= netdev_set_msglevel,
23848c2ecf20Sopenharmony_ci	.get_wol		= rhine_get_wol,
23858c2ecf20Sopenharmony_ci	.set_wol		= rhine_set_wol,
23868c2ecf20Sopenharmony_ci	.get_link_ksettings	= netdev_get_link_ksettings,
23878c2ecf20Sopenharmony_ci	.set_link_ksettings	= netdev_set_link_ksettings,
23888c2ecf20Sopenharmony_ci};
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
23918c2ecf20Sopenharmony_ci{
23928c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
23938c2ecf20Sopenharmony_ci	int rc;
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	if (!netif_running(dev))
23968c2ecf20Sopenharmony_ci		return -EINVAL;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	mutex_lock(&rp->task_lock);
23998c2ecf20Sopenharmony_ci	rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
24008c2ecf20Sopenharmony_ci	rhine_set_carrier(&rp->mii_if);
24018c2ecf20Sopenharmony_ci	mutex_unlock(&rp->task_lock);
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	return rc;
24048c2ecf20Sopenharmony_ci}
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_cistatic int rhine_close(struct net_device *dev)
24078c2ecf20Sopenharmony_ci{
24088c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
24098c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	rhine_task_disable(rp);
24128c2ecf20Sopenharmony_ci	napi_disable(&rp->napi);
24138c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
24148c2ecf20Sopenharmony_ci
24158c2ecf20Sopenharmony_ci	netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n",
24168c2ecf20Sopenharmony_ci		  ioread16(ioaddr + ChipCmd));
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	/* Switch to loopback mode to avoid hardware races. */
24198c2ecf20Sopenharmony_ci	iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_ci	rhine_irq_disable(rp);
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_ci	/* Stop the chip's Tx and Rx processes. */
24248c2ecf20Sopenharmony_ci	iowrite16(CmdStop, ioaddr + ChipCmd);
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci	free_irq(rp->irq, dev);
24278c2ecf20Sopenharmony_ci	free_rbufs(dev);
24288c2ecf20Sopenharmony_ci	free_tbufs(dev);
24298c2ecf20Sopenharmony_ci	free_ring(dev);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	return 0;
24328c2ecf20Sopenharmony_ci}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_cistatic void rhine_remove_one_pci(struct pci_dev *pdev)
24368c2ecf20Sopenharmony_ci{
24378c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
24388c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci	unregister_netdev(dev);
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	pci_iounmap(pdev, rp->base);
24438c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	free_netdev(dev);
24468c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
24478c2ecf20Sopenharmony_ci}
24488c2ecf20Sopenharmony_ci
24498c2ecf20Sopenharmony_cistatic int rhine_remove_one_platform(struct platform_device *pdev)
24508c2ecf20Sopenharmony_ci{
24518c2ecf20Sopenharmony_ci	struct net_device *dev = platform_get_drvdata(pdev);
24528c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	unregister_netdev(dev);
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	iounmap(rp->base);
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci	free_netdev(dev);
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	return 0;
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_cistatic void rhine_shutdown_pci(struct pci_dev *pdev)
24648c2ecf20Sopenharmony_ci{
24658c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
24668c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
24678c2ecf20Sopenharmony_ci	void __iomem *ioaddr = rp->base;
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	if (!(rp->quirks & rqWOL))
24708c2ecf20Sopenharmony_ci		return; /* Nothing to do for non-WOL adapters */
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	rhine_power_init(dev);
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci	/* Make sure we use pattern 0, 1 and not 4, 5 */
24758c2ecf20Sopenharmony_ci	if (rp->quirks & rq6patterns)
24768c2ecf20Sopenharmony_ci		iowrite8(0x04, ioaddr + WOLcgClr);
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci	spin_lock(&rp->lock);
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	if (rp->wolopts & WAKE_MAGIC) {
24818c2ecf20Sopenharmony_ci		iowrite8(WOLmagic, ioaddr + WOLcrSet);
24828c2ecf20Sopenharmony_ci		/*
24838c2ecf20Sopenharmony_ci		 * Turn EEPROM-controlled wake-up back on -- some hardware may
24848c2ecf20Sopenharmony_ci		 * not cooperate otherwise.
24858c2ecf20Sopenharmony_ci		 */
24868c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + ConfigA) | 0x03, ioaddr + ConfigA);
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	if (rp->wolopts & (WAKE_BCAST|WAKE_MCAST))
24908c2ecf20Sopenharmony_ci		iowrite8(WOLbmcast, ioaddr + WOLcgSet);
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	if (rp->wolopts & WAKE_PHY)
24938c2ecf20Sopenharmony_ci		iowrite8(WOLlnkon | WOLlnkoff, ioaddr + WOLcrSet);
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci	if (rp->wolopts & WAKE_UCAST)
24968c2ecf20Sopenharmony_ci		iowrite8(WOLucast, ioaddr + WOLcrSet);
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_ci	if (rp->wolopts) {
24998c2ecf20Sopenharmony_ci		/* Enable legacy WOL (for old motherboards) */
25008c2ecf20Sopenharmony_ci		iowrite8(0x01, ioaddr + PwcfgSet);
25018c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW);
25028c2ecf20Sopenharmony_ci	}
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	spin_unlock(&rp->lock);
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_ci	if (system_state == SYSTEM_POWER_OFF && !avoid_D3) {
25078c2ecf20Sopenharmony_ci		iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
25088c2ecf20Sopenharmony_ci
25098c2ecf20Sopenharmony_ci		pci_wake_from_d3(pdev, true);
25108c2ecf20Sopenharmony_ci		pci_set_power_state(pdev, PCI_D3hot);
25118c2ecf20Sopenharmony_ci	}
25128c2ecf20Sopenharmony_ci}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
25158c2ecf20Sopenharmony_cistatic int rhine_suspend(struct device *device)
25168c2ecf20Sopenharmony_ci{
25178c2ecf20Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(device);
25188c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	if (!netif_running(dev))
25218c2ecf20Sopenharmony_ci		return 0;
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	rhine_task_disable(rp);
25248c2ecf20Sopenharmony_ci	rhine_irq_disable(rp);
25258c2ecf20Sopenharmony_ci	napi_disable(&rp->napi);
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	netif_device_detach(dev);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	if (dev_is_pci(device))
25308c2ecf20Sopenharmony_ci		rhine_shutdown_pci(to_pci_dev(device));
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	return 0;
25338c2ecf20Sopenharmony_ci}
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_cistatic int rhine_resume(struct device *device)
25368c2ecf20Sopenharmony_ci{
25378c2ecf20Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(device);
25388c2ecf20Sopenharmony_ci	struct rhine_private *rp = netdev_priv(dev);
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	if (!netif_running(dev))
25418c2ecf20Sopenharmony_ci		return 0;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	enable_mmio(rp->pioaddr, rp->quirks);
25448c2ecf20Sopenharmony_ci	rhine_power_init(dev);
25458c2ecf20Sopenharmony_ci	free_tbufs(dev);
25468c2ecf20Sopenharmony_ci	alloc_tbufs(dev);
25478c2ecf20Sopenharmony_ci	rhine_reset_rbufs(rp);
25488c2ecf20Sopenharmony_ci	rhine_task_enable(rp);
25498c2ecf20Sopenharmony_ci	spin_lock_bh(&rp->lock);
25508c2ecf20Sopenharmony_ci	init_registers(dev);
25518c2ecf20Sopenharmony_ci	spin_unlock_bh(&rp->lock);
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	netif_device_attach(dev);
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_ci	return 0;
25568c2ecf20Sopenharmony_ci}
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume);
25598c2ecf20Sopenharmony_ci#define RHINE_PM_OPS	(&rhine_pm_ops)
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci#else
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci#define RHINE_PM_OPS	NULL
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci#endif /* !CONFIG_PM_SLEEP */
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic struct pci_driver rhine_driver_pci = {
25688c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
25698c2ecf20Sopenharmony_ci	.id_table	= rhine_pci_tbl,
25708c2ecf20Sopenharmony_ci	.probe		= rhine_init_one_pci,
25718c2ecf20Sopenharmony_ci	.remove		= rhine_remove_one_pci,
25728c2ecf20Sopenharmony_ci	.shutdown	= rhine_shutdown_pci,
25738c2ecf20Sopenharmony_ci	.driver.pm	= RHINE_PM_OPS,
25748c2ecf20Sopenharmony_ci};
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_cistatic struct platform_driver rhine_driver_platform = {
25778c2ecf20Sopenharmony_ci	.probe		= rhine_init_one_platform,
25788c2ecf20Sopenharmony_ci	.remove		= rhine_remove_one_platform,
25798c2ecf20Sopenharmony_ci	.driver = {
25808c2ecf20Sopenharmony_ci		.name	= DRV_NAME,
25818c2ecf20Sopenharmony_ci		.of_match_table	= rhine_of_tbl,
25828c2ecf20Sopenharmony_ci		.pm		= RHINE_PM_OPS,
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci};
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_cistatic const struct dmi_system_id rhine_dmi_table[] __initconst = {
25878c2ecf20Sopenharmony_ci	{
25888c2ecf20Sopenharmony_ci		.ident = "EPIA-M",
25898c2ecf20Sopenharmony_ci		.matches = {
25908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."),
25918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"),
25928c2ecf20Sopenharmony_ci		},
25938c2ecf20Sopenharmony_ci	},
25948c2ecf20Sopenharmony_ci	{
25958c2ecf20Sopenharmony_ci		.ident = "KV7",
25968c2ecf20Sopenharmony_ci		.matches = {
25978c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
25988c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"),
25998c2ecf20Sopenharmony_ci		},
26008c2ecf20Sopenharmony_ci	},
26018c2ecf20Sopenharmony_ci	{ NULL }
26028c2ecf20Sopenharmony_ci};
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_cistatic int __init rhine_init(void)
26058c2ecf20Sopenharmony_ci{
26068c2ecf20Sopenharmony_ci	int ret_pci, ret_platform;
26078c2ecf20Sopenharmony_ci
26088c2ecf20Sopenharmony_ci/* when a module, this is printed whether or not devices are found in probe */
26098c2ecf20Sopenharmony_ci	if (dmi_check_system(rhine_dmi_table)) {
26108c2ecf20Sopenharmony_ci		/* these BIOSes fail at PXE boot if chip is in D3 */
26118c2ecf20Sopenharmony_ci		avoid_D3 = true;
26128c2ecf20Sopenharmony_ci		pr_warn("Broken BIOS detected, avoid_D3 enabled\n");
26138c2ecf20Sopenharmony_ci	}
26148c2ecf20Sopenharmony_ci	else if (avoid_D3)
26158c2ecf20Sopenharmony_ci		pr_info("avoid_D3 set\n");
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	ret_pci = pci_register_driver(&rhine_driver_pci);
26188c2ecf20Sopenharmony_ci	ret_platform = platform_driver_register(&rhine_driver_platform);
26198c2ecf20Sopenharmony_ci	if ((ret_pci < 0) && (ret_platform < 0))
26208c2ecf20Sopenharmony_ci		return ret_pci;
26218c2ecf20Sopenharmony_ci
26228c2ecf20Sopenharmony_ci	return 0;
26238c2ecf20Sopenharmony_ci}
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_cistatic void __exit rhine_cleanup(void)
26278c2ecf20Sopenharmony_ci{
26288c2ecf20Sopenharmony_ci	platform_driver_unregister(&rhine_driver_platform);
26298c2ecf20Sopenharmony_ci	pci_unregister_driver(&rhine_driver_pci);
26308c2ecf20Sopenharmony_ci}
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_cimodule_init(rhine_init);
26348c2ecf20Sopenharmony_cimodule_exit(rhine_cleanup);
2635