blob: a5d6a6bd0c1adfae58469ab7f08fe56e14e17d9f [file] [log] [blame]
Francois Romieu890e8d02005-07-30 13:08:43 +02001/*
2 sis190.c: Silicon Integrated Systems SiS190 ethernet driver
3
4 Copyright (c) 2003 K.M. Liu <kmliu@sis.com>
5 Copyright (c) 2003, 2004 Jeff Garzik <jgarzik@pobox.com>
6 Copyright (c) 2003, 2004, 2005 Francois Romieu <romieu@fr.zoreil.com>
7
Francois Romieu40292fb2005-07-30 13:12:06 +02008 Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191
9 genuine driver.
Francois Romieu890e8d02005-07-30 13:08:43 +020010
11 This software may be used and distributed according to the terms of
12 the GNU General Public License (GPL), incorporated herein by reference.
13 Drivers based on or derived from this code fall under the GPL and must
14 retain the authorship, copyright and license notice. This file is not
15 a complete program and may only be used when the entire operating
16 system is licensed under the GPL.
17
18 See the file COPYING in this distribution for more information.
19
Joe Perchesad06ab22010-02-17 20:00:17 +000020*/
21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
Francois Romieu890e8d02005-07-30 13:08:43 +020023
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/netdevice.h>
Francois Romieu43afb942005-07-30 13:10:21 +020027#include <linux/rtnetlink.h>
Francois Romieu890e8d02005-07-30 13:08:43 +020028#include <linux/etherdevice.h>
29#include <linux/ethtool.h>
30#include <linux/pci.h>
31#include <linux/mii.h>
32#include <linux/delay.h>
33#include <linux/crc32.h>
34#include <linux/dma-mapping.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090035#include <linux/slab.h>
Francois Romieu890e8d02005-07-30 13:08:43 +020036#include <asm/irq.h>
37
Francois Romieufcb98212005-07-30 13:15:22 +020038#define PHY_MAX_ADDR 32
39#define PHY_ID_ANY 0x1f
40#define MII_REG_ANY 0x1f
41
Riccardo Ghetta08326db2010-02-17 09:28:58 +000042#define DRV_VERSION "1.4"
Francois Romieu890e8d02005-07-30 13:08:43 +020043#define DRV_NAME "sis190"
44#define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
Francois Romieu890e8d02005-07-30 13:08:43 +020045
Francois Romieu890e8d02005-07-30 13:08:43 +020046#define sis190_rx_skb netif_rx
47#define sis190_rx_quota(count, quota) count
Francois Romieu890e8d02005-07-30 13:08:43 +020048
49#define MAC_ADDR_LEN 6
50
Francois Romieubcad5e52005-07-30 13:13:47 +020051#define NUM_TX_DESC 64 /* [8..1024] */
52#define NUM_RX_DESC 64 /* [8..8192] */
Francois Romieu890e8d02005-07-30 13:08:43 +020053#define TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
54#define RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
55#define RX_BUF_SIZE 1536
Francois Romieu8b5641d2005-07-30 13:13:03 +020056#define RX_BUF_MASK 0xfff8
Francois Romieu890e8d02005-07-30 13:08:43 +020057
58#define SIS190_REGS_SIZE 0x80
59#define SIS190_TX_TIMEOUT (6*HZ)
60#define SIS190_PHY_TIMEOUT (10*HZ)
61#define SIS190_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \
62 NETIF_MSG_LINK | NETIF_MSG_IFUP | \
63 NETIF_MSG_IFDOWN)
64
65/* Enhanced PHY access register bit definitions */
66#define EhnMIIread 0x0000
67#define EhnMIIwrite 0x0020
68#define EhnMIIdataShift 16
69#define EhnMIIpmdShift 6 /* 7016 only */
70#define EhnMIIregShift 11
71#define EhnMIIreq 0x0010
72#define EhnMIInotDone 0x0010
73
74/* Write/read MMIO register */
75#define SIS_W8(reg, val) writeb ((val), ioaddr + (reg))
76#define SIS_W16(reg, val) writew ((val), ioaddr + (reg))
77#define SIS_W32(reg, val) writel ((val), ioaddr + (reg))
78#define SIS_R8(reg) readb (ioaddr + (reg))
79#define SIS_R16(reg) readw (ioaddr + (reg))
80#define SIS_R32(reg) readl (ioaddr + (reg))
81
82#define SIS_PCI_COMMIT() SIS_R32(IntrControl)
83
84enum sis190_registers {
85 TxControl = 0x00,
86 TxDescStartAddr = 0x04,
Francois Romieu188f23b2005-07-30 13:11:43 +020087 rsv0 = 0x08, // reserved
88 TxSts = 0x0c, // unused (Control/Status)
Francois Romieu890e8d02005-07-30 13:08:43 +020089 RxControl = 0x10,
90 RxDescStartAddr = 0x14,
Francois Romieu188f23b2005-07-30 13:11:43 +020091 rsv1 = 0x18, // reserved
92 RxSts = 0x1c, // unused
Francois Romieu890e8d02005-07-30 13:08:43 +020093 IntrStatus = 0x20,
94 IntrMask = 0x24,
95 IntrControl = 0x28,
Francois Romieu188f23b2005-07-30 13:11:43 +020096 IntrTimer = 0x2c, // unused (Interupt Timer)
97 PMControl = 0x30, // unused (Power Mgmt Control/Status)
98 rsv2 = 0x34, // reserved
Francois Romieu890e8d02005-07-30 13:08:43 +020099 ROMControl = 0x38,
100 ROMInterface = 0x3c,
101 StationControl = 0x40,
102 GMIIControl = 0x44,
Francois Romieu188f23b2005-07-30 13:11:43 +0200103 GIoCR = 0x48, // unused (GMAC IO Compensation)
104 GIoCtrl = 0x4c, // unused (GMAC IO Control)
Francois Romieu890e8d02005-07-30 13:08:43 +0200105 TxMacControl = 0x50,
Francois Romieu188f23b2005-07-30 13:11:43 +0200106 TxLimit = 0x54, // unused (Tx MAC Timer/TryLimit)
107 RGDelay = 0x58, // unused (RGMII Tx Internal Delay)
108 rsv3 = 0x5c, // reserved
Francois Romieu890e8d02005-07-30 13:08:43 +0200109 RxMacControl = 0x60,
110 RxMacAddr = 0x62,
111 RxHashTable = 0x68,
112 // Undocumented = 0x6c,
Francois Romieu188f23b2005-07-30 13:11:43 +0200113 RxWolCtrl = 0x70,
114 RxWolData = 0x74, // unused (Rx WOL Data Access)
115 RxMPSControl = 0x78, // unused (Rx MPS Control)
116 rsv4 = 0x7c, // reserved
Francois Romieu890e8d02005-07-30 13:08:43 +0200117};
118
119enum sis190_register_content {
120 /* IntrStatus */
121 SoftInt = 0x40000000, // unused
122 Timeup = 0x20000000, // unused
123 PauseFrame = 0x00080000, // unused
124 MagicPacket = 0x00040000, // unused
125 WakeupFrame = 0x00020000, // unused
126 LinkChange = 0x00010000,
127 RxQEmpty = 0x00000080,
128 RxQInt = 0x00000040,
129 TxQ1Empty = 0x00000020, // unused
130 TxQ1Int = 0x00000010,
131 TxQ0Empty = 0x00000008, // unused
132 TxQ0Int = 0x00000004,
133 RxHalt = 0x00000002,
134 TxHalt = 0x00000001,
135
Francois Romieu890e8d02005-07-30 13:08:43 +0200136 /* {Rx/Tx}CmdBits */
137 CmdReset = 0x10,
138 CmdRxEnb = 0x08, // unused
139 CmdTxEnb = 0x01,
140 RxBufEmpty = 0x01, // unused
141
142 /* Cfg9346Bits */
143 Cfg9346_Lock = 0x00, // unused
144 Cfg9346_Unlock = 0xc0, // unused
145
146 /* RxMacControl */
147 AcceptErr = 0x20, // unused
148 AcceptRunt = 0x10, // unused
149 AcceptBroadcast = 0x0800,
150 AcceptMulticast = 0x0400,
151 AcceptMyPhys = 0x0200,
152 AcceptAllPhys = 0x0100,
153
154 /* RxConfigBits */
155 RxCfgFIFOShift = 13,
156 RxCfgDMAShift = 8, // 0x1a in RxControl ?
157
158 /* TxConfigBits */
159 TxInterFrameGapShift = 24,
160 TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
161
Francois Romieu890e8d02005-07-30 13:08:43 +0200162 LinkStatus = 0x02, // unused
163 FullDup = 0x01, // unused
164
165 /* TBICSRBit */
166 TBILinkOK = 0x02000000, // unused
167};
168
169struct TxDesc {
Francois Romieu3cec93c2005-07-30 13:14:18 +0200170 __le32 PSize;
171 __le32 status;
172 __le32 addr;
173 __le32 size;
Francois Romieu890e8d02005-07-30 13:08:43 +0200174};
175
176struct RxDesc {
Francois Romieu3cec93c2005-07-30 13:14:18 +0200177 __le32 PSize;
178 __le32 status;
179 __le32 addr;
180 __le32 size;
Francois Romieu890e8d02005-07-30 13:08:43 +0200181};
182
183enum _DescStatusBit {
184 /* _Desc.status */
Francois Romieubcad5e52005-07-30 13:13:47 +0200185 OWNbit = 0x80000000, // RXOWN/TXOWN
186 INTbit = 0x40000000, // RXINT/TXINT
187 CRCbit = 0x00020000, // CRCOFF/CRCEN
188 PADbit = 0x00010000, // PREADD/PADEN
Francois Romieu890e8d02005-07-30 13:08:43 +0200189 /* _Desc.size */
Francois Romieubcad5e52005-07-30 13:13:47 +0200190 RingEnd = 0x80000000,
191 /* TxDesc.status */
192 LSEN = 0x08000000, // TSO ? -- FR
193 IPCS = 0x04000000,
194 TCPCS = 0x02000000,
195 UDPCS = 0x01000000,
196 BSTEN = 0x00800000,
197 EXTEN = 0x00400000,
198 DEFEN = 0x00200000,
199 BKFEN = 0x00100000,
200 CRSEN = 0x00080000,
201 COLEN = 0x00040000,
202 THOL3 = 0x30000000,
203 THOL2 = 0x20000000,
204 THOL1 = 0x10000000,
205 THOL0 = 0x00000000,
Francois Romieu697c2692007-11-21 22:30:37 +0100206
207 WND = 0x00080000,
208 TABRT = 0x00040000,
209 FIFO = 0x00020000,
210 LINK = 0x00010000,
211 ColCountMask = 0x0000ffff,
Francois Romieubcad5e52005-07-30 13:13:47 +0200212 /* RxDesc.status */
213 IPON = 0x20000000,
214 TCPON = 0x10000000,
215 UDPON = 0x08000000,
216 Wakup = 0x00400000,
217 Magic = 0x00200000,
218 Pause = 0x00100000,
219 DEFbit = 0x00200000,
220 BCAST = 0x000c0000,
221 MCAST = 0x00080000,
222 UCAST = 0x00040000,
223 /* RxDesc.PSize */
224 TAGON = 0x80000000,
225 RxDescCountMask = 0x7f000000, // multi-desc pkt when > 1 ? -- FR
226 ABORT = 0x00800000,
227 SHORT = 0x00400000,
228 LIMIT = 0x00200000,
229 MIIER = 0x00100000,
230 OVRUN = 0x00080000,
231 NIBON = 0x00040000,
232 COLON = 0x00020000,
233 CRCOK = 0x00010000,
Francois Romieu890e8d02005-07-30 13:08:43 +0200234 RxSizeMask = 0x0000ffff
Francois Romieubcad5e52005-07-30 13:13:47 +0200235 /*
236 * The asic could apparently do vlan, TSO, jumbo (sis191 only) and
237 * provide two (unused with Linux) Tx queues. No publically
238 * available documentation alas.
239 */
Francois Romieu890e8d02005-07-30 13:08:43 +0200240};
241
Francois Romieu40292fb2005-07-30 13:12:06 +0200242enum sis190_eeprom_access_register_bits {
243 EECS = 0x00000001, // unused
244 EECLK = 0x00000002, // unused
245 EEDO = 0x00000008, // unused
246 EEDI = 0x00000004, // unused
247 EEREQ = 0x00000080,
248 EEROP = 0x00000200,
249 EEWOP = 0x00000100 // unused
250};
251
Francois Romieu830fb7d2005-07-30 13:12:37 +0200252/* EEPROM Addresses */
253enum sis190_eeprom_address {
254 EEPROMSignature = 0x00,
255 EEPROMCLK = 0x01, // unused
256 EEPROMInfo = 0x02,
257 EEPROMMACAddr = 0x03
258};
259
Francois Romieu900eb9d2005-09-03 00:55:27 +0200260enum sis190_feature {
261 F_HAS_RGMII = 1,
Francois Romieuc3d6f1f2005-09-03 00:56:57 +0200262 F_PHY_88E1111 = 2,
263 F_PHY_BCM5461 = 4
Francois Romieu900eb9d2005-09-03 00:55:27 +0200264};
265
Francois Romieu890e8d02005-07-30 13:08:43 +0200266struct sis190_private {
267 void __iomem *mmio_addr;
268 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000269 struct net_device *dev;
Francois Romieu890e8d02005-07-30 13:08:43 +0200270 spinlock_t lock;
271 u32 rx_buf_sz;
272 u32 cur_rx;
273 u32 cur_tx;
274 u32 dirty_rx;
275 u32 dirty_tx;
276 dma_addr_t rx_dma;
277 dma_addr_t tx_dma;
278 struct RxDesc *RxDescRing;
279 struct TxDesc *TxDescRing;
280 struct sk_buff *Rx_skbuff[NUM_RX_DESC];
281 struct sk_buff *Tx_skbuff[NUM_TX_DESC];
282 struct work_struct phy_task;
283 struct timer_list timer;
284 u32 msg_enable;
Francois Romieu43afb942005-07-30 13:10:21 +0200285 struct mii_if_info mii_if;
Francois Romieufcb98212005-07-30 13:15:22 +0200286 struct list_head first_phy;
Francois Romieu900eb9d2005-09-03 00:55:27 +0200287 u32 features;
Riccardo Ghetta08326db2010-02-17 09:28:58 +0000288 u32 negotiated_lpa;
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -0800289 enum {
290 LNK_OFF,
291 LNK_ON,
292 LNK_AUTONEG,
293 } link_status;
Francois Romieufcb98212005-07-30 13:15:22 +0200294};
295
296struct sis190_phy {
297 struct list_head list;
298 int phy_id;
299 u16 id[2];
300 u16 status;
301 u8 type;
302};
303
304enum sis190_phy_type {
305 UNKNOWN = 0x00,
306 HOME = 0x01,
307 LAN = 0x02,
308 MIX = 0x03
309};
310
311static struct mii_chip_info {
312 const char *name;
313 u16 id[2];
314 unsigned int type;
Francois Romieu900eb9d2005-09-03 00:55:27 +0200315 u32 feature;
Francois Romieufcb98212005-07-30 13:15:22 +0200316} mii_chip_table[] = {
Riccardo Ghetta856f8f42009-06-04 09:05:07 +0000317 { "Atheros PHY", { 0x004d, 0xd010 }, LAN, 0 },
Francois Romieu708f6e22008-10-20 23:37:55 +0200318 { "Atheros PHY AR8012", { 0x004d, 0xd020 }, LAN, 0 },
Francois Romieuc3d6f1f2005-09-03 00:56:57 +0200319 { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN, F_PHY_BCM5461 },
Francois Romieubd7a4442007-03-29 00:18:50 +0200320 { "Broadcom PHY AC131", { 0x0143, 0xbc70 }, LAN, 0 },
Francois Romieu900eb9d2005-09-03 00:55:27 +0200321 { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN, 0 },
322 { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN, F_PHY_88E1111 },
323 { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN, 0 },
Francois Romieufcb98212005-07-30 13:15:22 +0200324 { NULL, }
Francois Romieu890e8d02005-07-30 13:08:43 +0200325};
326
Jesper Juhl3c6bee12006-01-09 20:54:01 -0800327static const struct {
Francois Romieu890e8d02005-07-30 13:08:43 +0200328 const char *name;
Francois Romieu890e8d02005-07-30 13:08:43 +0200329} sis_chip_info[] = {
Francois Romieue7976372005-09-03 00:57:51 +0200330 { "SiS 190 PCI Fast Ethernet adapter" },
331 { "SiS 191 PCI Gigabit Ethernet adapter" },
Francois Romieu890e8d02005-07-30 13:08:43 +0200332};
333
Alexey Dobriyana3aa1882010-01-07 11:58:11 +0000334static DEFINE_PCI_DEVICE_TABLE(sis190_pci_tbl) = {
Francois Romieu890e8d02005-07-30 13:08:43 +0200335 { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 },
Francois Romieue7976372005-09-03 00:57:51 +0200336 { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0191), 0, 0, 1 },
Francois Romieu890e8d02005-07-30 13:08:43 +0200337 { 0, },
338};
339
340MODULE_DEVICE_TABLE(pci, sis190_pci_tbl);
341
342static int rx_copybreak = 200;
343
344static struct {
345 u32 msg_enable;
346} debug = { -1 };
347
Riccardo Ghettac3223d22009-06-04 09:04:55 +0000348MODULE_DESCRIPTION("SiS sis190/191 Gigabit Ethernet driver");
Francois Romieu890e8d02005-07-30 13:08:43 +0200349module_param(rx_copybreak, int, 0);
350MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
351module_param_named(debug, debug.msg_enable, int, 0);
352MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
353MODULE_AUTHOR("K.M. Liu <kmliu@sis.com>, Ueimor <romieu@fr.zoreil.com>");
354MODULE_VERSION(DRV_VERSION);
355MODULE_LICENSE("GPL");
356
357static const u32 sis190_intr_mask =
Francois Romieu21461382005-09-03 00:54:25 +0200358 RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt | LinkChange;
Francois Romieu890e8d02005-07-30 13:08:43 +0200359
360/*
361 * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
362 * The chips use a 64 element hash table based on the Ethernet CRC.
363 */
Arjan van de Venf71e1302006-03-03 21:33:57 -0500364static const int multicast_filter_limit = 32;
Francois Romieu890e8d02005-07-30 13:08:43 +0200365
366static void __mdio_cmd(void __iomem *ioaddr, u32 ctl)
367{
368 unsigned int i;
369
370 SIS_W32(GMIIControl, ctl);
371
372 msleep(1);
373
374 for (i = 0; i < 100; i++) {
375 if (!(SIS_R32(GMIIControl) & EhnMIInotDone))
376 break;
377 msleep(1);
378 }
379
Francois Romieu7bf3f232007-11-17 16:56:43 +0100380 if (i > 99)
Joe Perchesad06ab22010-02-17 20:00:17 +0000381 pr_err("PHY command failed !\n");
Francois Romieu890e8d02005-07-30 13:08:43 +0200382}
383
Francois Romieu9ede1092005-07-30 13:14:38 +0200384static void mdio_write(void __iomem *ioaddr, int phy_id, int reg, int val)
Francois Romieu890e8d02005-07-30 13:08:43 +0200385{
Francois Romieu890e8d02005-07-30 13:08:43 +0200386 __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite |
Francois Romieu9ede1092005-07-30 13:14:38 +0200387 (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) |
Francois Romieu890e8d02005-07-30 13:08:43 +0200388 (((u32) val) << EhnMIIdataShift));
389}
390
Francois Romieu9ede1092005-07-30 13:14:38 +0200391static int mdio_read(void __iomem *ioaddr, int phy_id, int reg)
Francois Romieu890e8d02005-07-30 13:08:43 +0200392{
Francois Romieu890e8d02005-07-30 13:08:43 +0200393 __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread |
Francois Romieu9ede1092005-07-30 13:14:38 +0200394 (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift));
Francois Romieu890e8d02005-07-30 13:08:43 +0200395
396 return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift);
397}
398
Francois Romieu43afb942005-07-30 13:10:21 +0200399static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val)
400{
401 struct sis190_private *tp = netdev_priv(dev);
402
Francois Romieu9ede1092005-07-30 13:14:38 +0200403 mdio_write(tp->mmio_addr, phy_id, reg, val);
Francois Romieu43afb942005-07-30 13:10:21 +0200404}
405
406static int __mdio_read(struct net_device *dev, int phy_id, int reg)
407{
408 struct sis190_private *tp = netdev_priv(dev);
409
Francois Romieu9ede1092005-07-30 13:14:38 +0200410 return mdio_read(tp->mmio_addr, phy_id, reg);
Francois Romieu43afb942005-07-30 13:10:21 +0200411}
412
Francois Romieufc10c392005-07-30 13:15:01 +0200413static u16 mdio_read_latched(void __iomem *ioaddr, int phy_id, int reg)
414{
415 mdio_read(ioaddr, phy_id, reg);
416 return mdio_read(ioaddr, phy_id, reg);
417}
418
Francois Romieu40292fb2005-07-30 13:12:06 +0200419static u16 __devinit sis190_read_eeprom(void __iomem *ioaddr, u32 reg)
Francois Romieu890e8d02005-07-30 13:08:43 +0200420{
Francois Romieu40292fb2005-07-30 13:12:06 +0200421 u16 data = 0xffff;
Francois Romieu890e8d02005-07-30 13:08:43 +0200422 unsigned int i;
Francois Romieu890e8d02005-07-30 13:08:43 +0200423
424 if (!(SIS_R32(ROMControl) & 0x0002))
425 return 0;
426
Francois Romieu40292fb2005-07-30 13:12:06 +0200427 SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10));
Francois Romieu890e8d02005-07-30 13:08:43 +0200428
429 for (i = 0; i < 200; i++) {
Francois Romieu40292fb2005-07-30 13:12:06 +0200430 if (!(SIS_R32(ROMInterface) & EEREQ)) {
431 data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16;
Francois Romieu890e8d02005-07-30 13:08:43 +0200432 break;
Francois Romieu40292fb2005-07-30 13:12:06 +0200433 }
Francois Romieu890e8d02005-07-30 13:08:43 +0200434 msleep(1);
435 }
436
Francois Romieu890e8d02005-07-30 13:08:43 +0200437 return data;
438}
439
440static void sis190_irq_mask_and_ack(void __iomem *ioaddr)
441{
442 SIS_W32(IntrMask, 0x00);
443 SIS_W32(IntrStatus, 0xffffffff);
444 SIS_PCI_COMMIT();
445}
446
447static void sis190_asic_down(void __iomem *ioaddr)
448{
449 /* Stop the chip's Tx and Rx DMA processes. */
450
451 SIS_W32(TxControl, 0x1a00);
452 SIS_W32(RxControl, 0x1a00);
453
454 sis190_irq_mask_and_ack(ioaddr);
455}
456
457static void sis190_mark_as_last_descriptor(struct RxDesc *desc)
458{
459 desc->size |= cpu_to_le32(RingEnd);
460}
461
462static inline void sis190_give_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
463{
464 u32 eor = le32_to_cpu(desc->size) & RingEnd;
465
466 desc->PSize = 0x0;
Francois Romieu8b5641d2005-07-30 13:13:03 +0200467 desc->size = cpu_to_le32((rx_buf_sz & RX_BUF_MASK) | eor);
Francois Romieu890e8d02005-07-30 13:08:43 +0200468 wmb();
469 desc->status = cpu_to_le32(OWNbit | INTbit);
470}
471
472static inline void sis190_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
473 u32 rx_buf_sz)
474{
475 desc->addr = cpu_to_le32(mapping);
476 sis190_give_to_asic(desc, rx_buf_sz);
477}
478
479static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
480{
481 desc->PSize = 0x0;
Al Viro961994a2007-12-15 01:44:33 +0000482 desc->addr = cpu_to_le32(0xdeadbeef);
Francois Romieu890e8d02005-07-30 13:08:43 +0200483 desc->size &= cpu_to_le32(RingEnd);
484 wmb();
485 desc->status = 0x0;
486}
487
Stephen Hemminger35aeb782008-04-27 14:54:32 +0200488static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
489 struct RxDesc *desc)
Francois Romieu890e8d02005-07-30 13:08:43 +0200490{
Stephen Hemminger35aeb782008-04-27 14:54:32 +0200491 u32 rx_buf_sz = tp->rx_buf_sz;
Francois Romieu890e8d02005-07-30 13:08:43 +0200492 struct sk_buff *skb;
kirjanov@gmail.come382c302010-02-24 08:41:18 +0000493 dma_addr_t mapping;
Francois Romieu890e8d02005-07-30 13:08:43 +0200494
Stephen Hemminger35aeb782008-04-27 14:54:32 +0200495 skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
kirjanov@gmail.come382c302010-02-24 08:41:18 +0000496 if (unlikely(!skb))
497 goto skb_alloc_failed;
498 mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
499 PCI_DMA_FROMDEVICE);
500 if (pci_dma_mapping_error(tp->pci_dev, mapping))
501 goto out;
502 sis190_map_to_asic(desc, mapping, rx_buf_sz);
Francois Romieu890e8d02005-07-30 13:08:43 +0200503
Stephen Hemminger4709aa52008-04-27 14:36:59 +0200504 return skb;
kirjanov@gmail.come382c302010-02-24 08:41:18 +0000505
506out:
507 dev_kfree_skb_any(skb);
508skb_alloc_failed:
509 sis190_make_unusable_by_asic(desc);
510 return NULL;
Francois Romieu890e8d02005-07-30 13:08:43 +0200511}
512
513static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
514 u32 start, u32 end)
515{
516 u32 cur;
517
518 for (cur = start; cur < end; cur++) {
Stephen Hemminger4709aa52008-04-27 14:36:59 +0200519 unsigned int i = cur % NUM_RX_DESC;
Francois Romieu890e8d02005-07-30 13:08:43 +0200520
521 if (tp->Rx_skbuff[i])
522 continue;
523
Stephen Hemminger35aeb782008-04-27 14:54:32 +0200524 tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);
525
Stephen Hemminger4709aa52008-04-27 14:36:59 +0200526 if (!tp->Rx_skbuff[i])
Francois Romieu890e8d02005-07-30 13:08:43 +0200527 break;
528 }
529 return cur - start;
530}
531
Francois Romieu47e47812008-04-27 17:59:52 +0200532static bool sis190_try_rx_copy(struct sis190_private *tp,
533 struct sk_buff **sk_buff, int pkt_size,
534 dma_addr_t addr)
Francois Romieu890e8d02005-07-30 13:08:43 +0200535{
Francois Romieu47e47812008-04-27 17:59:52 +0200536 struct sk_buff *skb;
537 bool done = false;
Francois Romieu890e8d02005-07-30 13:08:43 +0200538
Francois Romieu47e47812008-04-27 17:59:52 +0200539 if (pkt_size >= rx_copybreak)
540 goto out;
Francois Romieu890e8d02005-07-30 13:08:43 +0200541
Eric Dumazet89d71a62009-10-13 05:34:20 +0000542 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
Francois Romieu47e47812008-04-27 17:59:52 +0200543 if (!skb)
544 goto out;
545
Riccardo Ghetta744c6b22009-06-07 19:47:58 +0000546 pci_dma_sync_single_for_cpu(tp->pci_dev, addr, tp->rx_buf_sz,
547 PCI_DMA_FROMDEVICE);
Francois Romieu47e47812008-04-27 17:59:52 +0200548 skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
549 *sk_buff = skb;
550 done = true;
551out:
552 return done;
Francois Romieu890e8d02005-07-30 13:08:43 +0200553}
554
Francois Romieubcad5e52005-07-30 13:13:47 +0200555static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
556{
557#define ErrMask (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT)
558
559 if ((status & CRCOK) && !(status & ErrMask))
560 return 0;
561
562 if (!(status & CRCOK))
563 stats->rx_crc_errors++;
564 else if (status & OVRUN)
565 stats->rx_over_errors++;
566 else if (status & (SHORT | LIMIT))
567 stats->rx_length_errors++;
568 else if (status & (MIIER | NIBON | COLON))
569 stats->rx_frame_errors++;
570
571 stats->rx_errors++;
572 return -1;
573}
574
Francois Romieu890e8d02005-07-30 13:08:43 +0200575static int sis190_rx_interrupt(struct net_device *dev,
576 struct sis190_private *tp, void __iomem *ioaddr)
577{
Jeff Garzik09f75cd2007-10-03 17:41:50 -0700578 struct net_device_stats *stats = &dev->stats;
Francois Romieu890e8d02005-07-30 13:08:43 +0200579 u32 rx_left, cur_rx = tp->cur_rx;
580 u32 delta, count;
581
582 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
583 rx_left = sis190_rx_quota(rx_left, (u32) dev->quota);
584
585 for (; rx_left > 0; rx_left--, cur_rx++) {
586 unsigned int entry = cur_rx % NUM_RX_DESC;
587 struct RxDesc *desc = tp->RxDescRing + entry;
588 u32 status;
589
Al Viro961994a2007-12-15 01:44:33 +0000590 if (le32_to_cpu(desc->status) & OWNbit)
Francois Romieu890e8d02005-07-30 13:08:43 +0200591 break;
592
593 status = le32_to_cpu(desc->PSize);
594
Joe Perchesad06ab22010-02-17 20:00:17 +0000595 //netif_info(tp, intr, dev, "Rx PSize = %08x\n", status);
Francois Romieu890e8d02005-07-30 13:08:43 +0200596
Francois Romieubcad5e52005-07-30 13:13:47 +0200597 if (sis190_rx_pkt_err(status, stats) < 0)
Francois Romieu890e8d02005-07-30 13:08:43 +0200598 sis190_give_to_asic(desc, tp->rx_buf_sz);
Francois Romieubcad5e52005-07-30 13:13:47 +0200599 else {
Francois Romieu890e8d02005-07-30 13:08:43 +0200600 struct sk_buff *skb = tp->Rx_skbuff[entry];
Francois Romieu47e47812008-04-27 17:59:52 +0200601 dma_addr_t addr = le32_to_cpu(desc->addr);
Francois Romieu890e8d02005-07-30 13:08:43 +0200602 int pkt_size = (status & RxSizeMask) - 4;
Francois Romieu47e47812008-04-27 17:59:52 +0200603 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu890e8d02005-07-30 13:08:43 +0200604
605 if (unlikely(pkt_size > tp->rx_buf_sz)) {
Joe Perchesad06ab22010-02-17 20:00:17 +0000606 netif_info(tp, intr, dev,
607 "(frag) status = %08x\n", status);
Francois Romieu890e8d02005-07-30 13:08:43 +0200608 stats->rx_dropped++;
609 stats->rx_length_errors++;
610 sis190_give_to_asic(desc, tp->rx_buf_sz);
611 continue;
612 }
613
Francois Romieu890e8d02005-07-30 13:08:43 +0200614
Francois Romieu47e47812008-04-27 17:59:52 +0200615 if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
616 pci_dma_sync_single_for_device(pdev, addr,
617 tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
618 sis190_give_to_asic(desc, tp->rx_buf_sz);
619 } else {
620 pci_unmap_single(pdev, addr, tp->rx_buf_sz,
621 PCI_DMA_FROMDEVICE);
Francois Romieu890e8d02005-07-30 13:08:43 +0200622 tp->Rx_skbuff[entry] = NULL;
623 sis190_make_unusable_by_asic(desc);
624 }
625
Francois Romieu890e8d02005-07-30 13:08:43 +0200626 skb_put(skb, pkt_size);
627 skb->protocol = eth_type_trans(skb, dev);
628
629 sis190_rx_skb(skb);
630
Francois Romieu890e8d02005-07-30 13:08:43 +0200631 stats->rx_packets++;
Francois Romieubcad5e52005-07-30 13:13:47 +0200632 stats->rx_bytes += pkt_size;
633 if ((status & BCAST) == MCAST)
634 stats->multicast++;
Francois Romieu890e8d02005-07-30 13:08:43 +0200635 }
636 }
637 count = cur_rx - tp->cur_rx;
638 tp->cur_rx = cur_rx;
639
640 delta = sis190_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
Joe Perchesad06ab22010-02-17 20:00:17 +0000641 if (!delta && count)
642 netif_info(tp, intr, dev, "no Rx buffer allocated\n");
Francois Romieu890e8d02005-07-30 13:08:43 +0200643 tp->dirty_rx += delta;
644
Joe Perchesad06ab22010-02-17 20:00:17 +0000645 if ((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx)
646 netif_emerg(tp, intr, dev, "Rx buffers exhausted\n");
Francois Romieu890e8d02005-07-30 13:08:43 +0200647
648 return count;
649}
650
651static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
652 struct TxDesc *desc)
653{
654 unsigned int len;
655
656 len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
657
658 pci_unmap_single(pdev, le32_to_cpu(desc->addr), len, PCI_DMA_TODEVICE);
659
660 memset(desc, 0x00, sizeof(*desc));
661}
662
Francois Romieu697c2692007-11-21 22:30:37 +0100663static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
664{
665#define TxErrMask (WND | TABRT | FIFO | LINK)
666
667 if (!unlikely(status & TxErrMask))
668 return 0;
669
670 if (status & WND)
671 stats->tx_window_errors++;
672 if (status & TABRT)
673 stats->tx_aborted_errors++;
674 if (status & FIFO)
675 stats->tx_fifo_errors++;
676 if (status & LINK)
677 stats->tx_carrier_errors++;
678
679 stats->tx_errors++;
680
681 return -1;
682}
683
Francois Romieu890e8d02005-07-30 13:08:43 +0200684static void sis190_tx_interrupt(struct net_device *dev,
685 struct sis190_private *tp, void __iomem *ioaddr)
686{
Francois Romieu697c2692007-11-21 22:30:37 +0100687 struct net_device_stats *stats = &dev->stats;
Francois Romieu890e8d02005-07-30 13:08:43 +0200688 u32 pending, dirty_tx = tp->dirty_tx;
689 /*
690 * It would not be needed if queueing was allowed to be enabled
691 * again too early (hint: think preempt and unclocked smp systems).
692 */
693 unsigned int queue_stopped;
694
695 smp_rmb();
696 pending = tp->cur_tx - dirty_tx;
697 queue_stopped = (pending == NUM_TX_DESC);
698
699 for (; pending; pending--, dirty_tx++) {
700 unsigned int entry = dirty_tx % NUM_TX_DESC;
701 struct TxDesc *txd = tp->TxDescRing + entry;
Francois Romieu697c2692007-11-21 22:30:37 +0100702 u32 status = le32_to_cpu(txd->status);
Francois Romieu890e8d02005-07-30 13:08:43 +0200703 struct sk_buff *skb;
704
Francois Romieu697c2692007-11-21 22:30:37 +0100705 if (status & OWNbit)
Francois Romieu890e8d02005-07-30 13:08:43 +0200706 break;
707
708 skb = tp->Tx_skbuff[entry];
709
Francois Romieu697c2692007-11-21 22:30:37 +0100710 if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
711 stats->tx_packets++;
712 stats->tx_bytes += skb->len;
713 stats->collisions += ((status & ColCountMask) - 1);
714 }
Francois Romieu890e8d02005-07-30 13:08:43 +0200715
716 sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
717 tp->Tx_skbuff[entry] = NULL;
718 dev_kfree_skb_irq(skb);
719 }
720
721 if (tp->dirty_tx != dirty_tx) {
722 tp->dirty_tx = dirty_tx;
723 smp_wmb();
724 if (queue_stopped)
725 netif_wake_queue(dev);
726 }
727}
728
729/*
730 * The interrupt handler does all of the Rx thread work and cleans up after
731 * the Tx thread.
732 */
David Howells7d12e782006-10-05 14:55:46 +0100733static irqreturn_t sis190_interrupt(int irq, void *__dev)
Francois Romieu890e8d02005-07-30 13:08:43 +0200734{
735 struct net_device *dev = __dev;
736 struct sis190_private *tp = netdev_priv(dev);
737 void __iomem *ioaddr = tp->mmio_addr;
738 unsigned int handled = 0;
739 u32 status;
740
741 status = SIS_R32(IntrStatus);
742
743 if ((status == 0xffffffff) || !status)
744 goto out;
745
746 handled = 1;
747
748 if (unlikely(!netif_running(dev))) {
749 sis190_asic_down(ioaddr);
750 goto out;
751 }
752
753 SIS_W32(IntrStatus, status);
754
Joe Perchesad06ab22010-02-17 20:00:17 +0000755// netif_info(tp, intr, dev, "status = %08x\n", status);
Francois Romieu890e8d02005-07-30 13:08:43 +0200756
757 if (status & LinkChange) {
Joe Perchesad06ab22010-02-17 20:00:17 +0000758 netif_info(tp, intr, dev, "link change\n");
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -0800759 del_timer(&tp->timer);
Francois Romieu890e8d02005-07-30 13:08:43 +0200760 schedule_work(&tp->phy_task);
761 }
762
763 if (status & RxQInt)
764 sis190_rx_interrupt(dev, tp, ioaddr);
765
766 if (status & TxQ0Int)
767 sis190_tx_interrupt(dev, tp, ioaddr);
768out:
769 return IRQ_RETVAL(handled);
770}
771
Francois Romieu4405d3b2005-07-30 13:09:20 +0200772#ifdef CONFIG_NET_POLL_CONTROLLER
773static void sis190_netpoll(struct net_device *dev)
774{
775 struct sis190_private *tp = netdev_priv(dev);
776 struct pci_dev *pdev = tp->pci_dev;
777
778 disable_irq(pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +0100779 sis190_interrupt(pdev->irq, dev);
Francois Romieu4405d3b2005-07-30 13:09:20 +0200780 enable_irq(pdev->irq);
781}
782#endif
783
Francois Romieu890e8d02005-07-30 13:08:43 +0200784static void sis190_free_rx_skb(struct sis190_private *tp,
785 struct sk_buff **sk_buff, struct RxDesc *desc)
786{
787 struct pci_dev *pdev = tp->pci_dev;
788
789 pci_unmap_single(pdev, le32_to_cpu(desc->addr), tp->rx_buf_sz,
790 PCI_DMA_FROMDEVICE);
791 dev_kfree_skb(*sk_buff);
792 *sk_buff = NULL;
793 sis190_make_unusable_by_asic(desc);
794}
795
796static void sis190_rx_clear(struct sis190_private *tp)
797{
798 unsigned int i;
799
800 for (i = 0; i < NUM_RX_DESC; i++) {
801 if (!tp->Rx_skbuff[i])
802 continue;
803 sis190_free_rx_skb(tp, tp->Rx_skbuff + i, tp->RxDescRing + i);
804 }
805}
806
807static void sis190_init_ring_indexes(struct sis190_private *tp)
808{
809 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
810}
811
812static int sis190_init_ring(struct net_device *dev)
813{
814 struct sis190_private *tp = netdev_priv(dev);
815
816 sis190_init_ring_indexes(tp);
817
818 memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *));
819 memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
820
821 if (sis190_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
822 goto err_rx_clear;
823
824 sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1);
825
826 return 0;
827
828err_rx_clear:
829 sis190_rx_clear(tp);
830 return -ENOMEM;
831}
832
833static void sis190_set_rx_mode(struct net_device *dev)
834{
835 struct sis190_private *tp = netdev_priv(dev);
836 void __iomem *ioaddr = tp->mmio_addr;
837 unsigned long flags;
838 u32 mc_filter[2]; /* Multicast hash filter */
839 u16 rx_mode;
840
841 if (dev->flags & IFF_PROMISC) {
Francois Romieu890e8d02005-07-30 13:08:43 +0200842 rx_mode =
843 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
844 AcceptAllPhys;
845 mc_filter[1] = mc_filter[0] = 0xffffffff;
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000846 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
Francois Romieu890e8d02005-07-30 13:08:43 +0200847 (dev->flags & IFF_ALLMULTI)) {
848 /* Too many to filter perfectly -- accept all multicasts. */
849 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
850 mc_filter[1] = mc_filter[0] = 0xffffffff;
851 } else {
Jiri Pirko22bedad2010-04-01 21:22:57 +0000852 struct netdev_hw_addr *ha;
Francois Romieu890e8d02005-07-30 13:08:43 +0200853
854 rx_mode = AcceptBroadcast | AcceptMyPhys;
855 mc_filter[1] = mc_filter[0] = 0;
Jiri Pirko22bedad2010-04-01 21:22:57 +0000856 netdev_for_each_mc_addr(ha, dev) {
Francois Romieu890e8d02005-07-30 13:08:43 +0200857 int bit_nr =
Jiri Pirko22bedad2010-04-01 21:22:57 +0000858 ether_crc(ETH_ALEN, ha->addr) & 0x3f;
Francois Romieu890e8d02005-07-30 13:08:43 +0200859 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
860 rx_mode |= AcceptMulticast;
861 }
862 }
863
864 spin_lock_irqsave(&tp->lock, flags);
865
866 SIS_W16(RxMacControl, rx_mode | 0x2);
867 SIS_W32(RxHashTable, mc_filter[0]);
868 SIS_W32(RxHashTable + 4, mc_filter[1]);
869
870 spin_unlock_irqrestore(&tp->lock, flags);
871}
872
873static void sis190_soft_reset(void __iomem *ioaddr)
874{
875 SIS_W32(IntrControl, 0x8000);
876 SIS_PCI_COMMIT();
Francois Romieu890e8d02005-07-30 13:08:43 +0200877 SIS_W32(IntrControl, 0x0);
878 sis190_asic_down(ioaddr);
Francois Romieu890e8d02005-07-30 13:08:43 +0200879}
880
881static void sis190_hw_start(struct net_device *dev)
882{
883 struct sis190_private *tp = netdev_priv(dev);
884 void __iomem *ioaddr = tp->mmio_addr;
885
886 sis190_soft_reset(ioaddr);
887
888 SIS_W32(TxDescStartAddr, tp->tx_dma);
889 SIS_W32(RxDescStartAddr, tp->rx_dma);
890
891 SIS_W32(IntrStatus, 0xffffffff);
892 SIS_W32(IntrMask, 0x0);
Francois Romieu890e8d02005-07-30 13:08:43 +0200893 SIS_W32(GMIIControl, 0x0);
894 SIS_W32(TxMacControl, 0x60);
895 SIS_W16(RxMacControl, 0x02);
896 SIS_W32(RxHashTable, 0x0);
897 SIS_W32(0x6c, 0x0);
Francois Romieu188f23b2005-07-30 13:11:43 +0200898 SIS_W32(RxWolCtrl, 0x0);
899 SIS_W32(RxWolData, 0x0);
Francois Romieu890e8d02005-07-30 13:08:43 +0200900
901 SIS_PCI_COMMIT();
902
903 sis190_set_rx_mode(dev);
904
905 /* Enable all known interrupts by setting the interrupt mask. */
906 SIS_W32(IntrMask, sis190_intr_mask);
907
908 SIS_W32(TxControl, 0x1a00 | CmdTxEnb);
909 SIS_W32(RxControl, 0x1a1d);
910
911 netif_start_queue(dev);
912}
913
David Howellsc4028952006-11-22 14:57:56 +0000914static void sis190_phy_task(struct work_struct *work)
Francois Romieu890e8d02005-07-30 13:08:43 +0200915{
David Howellsc4028952006-11-22 14:57:56 +0000916 struct sis190_private *tp =
917 container_of(work, struct sis190_private, phy_task);
918 struct net_device *dev = tp->dev;
Francois Romieu890e8d02005-07-30 13:08:43 +0200919 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9ede1092005-07-30 13:14:38 +0200920 int phy_id = tp->mii_if.phy_id;
Francois Romieu890e8d02005-07-30 13:08:43 +0200921 u16 val;
922
Francois Romieu43afb942005-07-30 13:10:21 +0200923 rtnl_lock();
924
Francois Romieuc014f6c2007-02-15 23:37:29 +0100925 if (!netif_running(dev))
926 goto out_unlock;
927
Francois Romieu9ede1092005-07-30 13:14:38 +0200928 val = mdio_read(ioaddr, phy_id, MII_BMCR);
Francois Romieu890e8d02005-07-30 13:08:43 +0200929 if (val & BMCR_RESET) {
930 // FIXME: needlessly high ? -- FR 02/07/2005
931 mod_timer(&tp->timer, jiffies + HZ/10);
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -0800932 goto out_unlock;
933 }
934
935 val = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
936 if (!(val & BMSR_ANEGCOMPLETE) && tp->link_status != LNK_AUTONEG) {
Francois Romieu21461382005-09-03 00:54:25 +0200937 netif_carrier_off(dev);
Joe Perchesad06ab22010-02-17 20:00:17 +0000938 netif_warn(tp, link, dev, "auto-negotiating...\n");
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -0800939 tp->link_status = LNK_AUTONEG;
940 } else if ((val & BMSR_LSTATUS) && tp->link_status != LNK_ON) {
Francois Romieu890e8d02005-07-30 13:08:43 +0200941 /* Rejoice ! */
942 struct {
943 int val;
Francois Romieu6614a6d2005-09-03 00:56:16 +0200944 u32 ctl;
Francois Romieu890e8d02005-07-30 13:08:43 +0200945 const char *msg;
Francois Romieu890e8d02005-07-30 13:08:43 +0200946 } reg31[] = {
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000947 { LPA_1000FULL, 0x07000c00 | 0x00001000,
Francois Romieu6614a6d2005-09-03 00:56:16 +0200948 "1000 Mbps Full Duplex" },
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000949 { LPA_1000HALF, 0x07000c00,
Francois Romieu6614a6d2005-09-03 00:56:16 +0200950 "1000 Mbps Half Duplex" },
951 { LPA_100FULL, 0x04000800 | 0x00001000,
952 "100 Mbps Full Duplex" },
953 { LPA_100HALF, 0x04000800,
954 "100 Mbps Half Duplex" },
955 { LPA_10FULL, 0x04000400 | 0x00001000,
956 "10 Mbps Full Duplex" },
957 { LPA_10HALF, 0x04000400,
958 "10 Mbps Half Duplex" },
959 { 0, 0x04000400, "unknown" }
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000960 }, *p = NULL;
961 u16 adv, autoexp, gigadv, gigrec;
Francois Romieu890e8d02005-07-30 13:08:43 +0200962
Francois Romieu9ede1092005-07-30 13:14:38 +0200963 val = mdio_read(ioaddr, phy_id, 0x1f);
Joe Perchesad06ab22010-02-17 20:00:17 +0000964 netif_info(tp, link, dev, "mii ext = %04x\n", val);
Francois Romieu890e8d02005-07-30 13:08:43 +0200965
Francois Romieu9ede1092005-07-30 13:14:38 +0200966 val = mdio_read(ioaddr, phy_id, MII_LPA);
Francois Romieu8348b4d2005-07-30 13:16:14 +0200967 adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000968 autoexp = mdio_read(ioaddr, phy_id, MII_EXPANSION);
Joe Perchesad06ab22010-02-17 20:00:17 +0000969 netif_info(tp, link, dev, "mii lpa=%04x adv=%04x exp=%04x\n",
970 val, adv, autoexp);
Francois Romieu8348b4d2005-07-30 13:16:14 +0200971
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000972 if (val & LPA_NPAGE && autoexp & EXPANSION_NWAY) {
973 /* check for gigabit speed */
974 gigadv = mdio_read(ioaddr, phy_id, MII_CTRL1000);
975 gigrec = mdio_read(ioaddr, phy_id, MII_STAT1000);
976 val = (gigadv & (gigrec >> 2));
977 if (val & ADVERTISE_1000FULL)
978 p = reg31;
979 else if (val & ADVERTISE_1000HALF)
980 p = reg31 + 1;
981 }
982 if (!p) {
983 val &= adv;
Francois Romieu890e8d02005-07-30 13:08:43 +0200984
Riccardo Ghetta1feede02009-06-04 09:05:20 +0000985 for (p = reg31; p->val; p++) {
986 if ((val & p->val) == p->val)
987 break;
988 }
Francois Romieu890e8d02005-07-30 13:08:43 +0200989 }
Francois Romieu6614a6d2005-09-03 00:56:16 +0200990
991 p->ctl |= SIS_R32(StationControl) & ~0x0f001c00;
992
Francois Romieuc3d6f1f2005-09-03 00:56:57 +0200993 if ((tp->features & F_HAS_RGMII) &&
994 (tp->features & F_PHY_BCM5461)) {
995 // Set Tx Delay in RGMII mode.
996 mdio_write(ioaddr, phy_id, 0x18, 0xf1c7);
997 udelay(200);
998 mdio_write(ioaddr, phy_id, 0x1c, 0x8c00);
999 p->ctl |= 0x03000000;
1000 }
1001
Francois Romieu6614a6d2005-09-03 00:56:16 +02001002 SIS_W32(StationControl, p->ctl);
1003
Francois Romieuc3d6f1f2005-09-03 00:56:57 +02001004 if (tp->features & F_HAS_RGMII) {
1005 SIS_W32(RGDelay, 0x0441);
1006 SIS_W32(RGDelay, 0x0440);
1007 }
1008
Riccardo Ghetta08326db2010-02-17 09:28:58 +00001009 tp->negotiated_lpa = p->val;
1010
Joe Perchesad06ab22010-02-17 20:00:17 +00001011 netif_info(tp, link, dev, "link on %s mode\n", p->msg);
Francois Romieu890e8d02005-07-30 13:08:43 +02001012 netif_carrier_on(dev);
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -08001013 tp->link_status = LNK_ON;
1014 } else if (!(val & BMSR_LSTATUS) && tp->link_status != LNK_AUTONEG)
1015 tp->link_status = LNK_OFF;
1016 mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
Francois Romieu43afb942005-07-30 13:10:21 +02001017
Francois Romieuc014f6c2007-02-15 23:37:29 +01001018out_unlock:
Francois Romieu43afb942005-07-30 13:10:21 +02001019 rtnl_unlock();
Francois Romieu890e8d02005-07-30 13:08:43 +02001020}
1021
1022static void sis190_phy_timer(unsigned long __opaque)
1023{
1024 struct net_device *dev = (struct net_device *)__opaque;
1025 struct sis190_private *tp = netdev_priv(dev);
1026
1027 if (likely(netif_running(dev)))
1028 schedule_work(&tp->phy_task);
1029}
1030
1031static inline void sis190_delete_timer(struct net_device *dev)
1032{
1033 struct sis190_private *tp = netdev_priv(dev);
1034
1035 del_timer_sync(&tp->timer);
1036}
1037
1038static inline void sis190_request_timer(struct net_device *dev)
1039{
1040 struct sis190_private *tp = netdev_priv(dev);
1041 struct timer_list *timer = &tp->timer;
1042
1043 init_timer(timer);
1044 timer->expires = jiffies + SIS190_PHY_TIMEOUT;
1045 timer->data = (unsigned long)dev;
1046 timer->function = sis190_phy_timer;
1047 add_timer(timer);
1048}
1049
1050static void sis190_set_rxbufsize(struct sis190_private *tp,
1051 struct net_device *dev)
1052{
1053 unsigned int mtu = dev->mtu;
1054
1055 tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE;
Francois Romieu8b5641d2005-07-30 13:13:03 +02001056 /* RxDesc->size has a licence to kill the lower bits */
1057 if (tp->rx_buf_sz & 0x07) {
1058 tp->rx_buf_sz += 8;
1059 tp->rx_buf_sz &= RX_BUF_MASK;
1060 }
Francois Romieu890e8d02005-07-30 13:08:43 +02001061}
1062
1063static int sis190_open(struct net_device *dev)
1064{
1065 struct sis190_private *tp = netdev_priv(dev);
1066 struct pci_dev *pdev = tp->pci_dev;
1067 int rc = -ENOMEM;
1068
1069 sis190_set_rxbufsize(tp, dev);
1070
1071 /*
1072 * Rx and Tx descriptors need 256 bytes alignment.
1073 * pci_alloc_consistent() guarantees a stronger alignment.
1074 */
1075 tp->TxDescRing = pci_alloc_consistent(pdev, TX_RING_BYTES, &tp->tx_dma);
1076 if (!tp->TxDescRing)
1077 goto out;
1078
1079 tp->RxDescRing = pci_alloc_consistent(pdev, RX_RING_BYTES, &tp->rx_dma);
1080 if (!tp->RxDescRing)
1081 goto err_free_tx_0;
1082
1083 rc = sis190_init_ring(dev);
1084 if (rc < 0)
1085 goto err_free_rx_1;
1086
Francois Romieu890e8d02005-07-30 13:08:43 +02001087 sis190_request_timer(dev);
1088
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07001089 rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev);
Francois Romieu890e8d02005-07-30 13:08:43 +02001090 if (rc < 0)
1091 goto err_release_timer_2;
1092
1093 sis190_hw_start(dev);
1094out:
1095 return rc;
1096
1097err_release_timer_2:
1098 sis190_delete_timer(dev);
1099 sis190_rx_clear(tp);
1100err_free_rx_1:
1101 pci_free_consistent(tp->pci_dev, RX_RING_BYTES, tp->RxDescRing,
1102 tp->rx_dma);
1103err_free_tx_0:
1104 pci_free_consistent(tp->pci_dev, TX_RING_BYTES, tp->TxDescRing,
1105 tp->tx_dma);
1106 goto out;
1107}
1108
1109static void sis190_tx_clear(struct sis190_private *tp)
1110{
1111 unsigned int i;
1112
1113 for (i = 0; i < NUM_TX_DESC; i++) {
1114 struct sk_buff *skb = tp->Tx_skbuff[i];
1115
1116 if (!skb)
1117 continue;
1118
1119 sis190_unmap_tx_skb(tp->pci_dev, skb, tp->TxDescRing + i);
1120 tp->Tx_skbuff[i] = NULL;
1121 dev_kfree_skb(skb);
1122
Jeff Garzik09f75cd2007-10-03 17:41:50 -07001123 tp->dev->stats.tx_dropped++;
Francois Romieu890e8d02005-07-30 13:08:43 +02001124 }
1125 tp->cur_tx = tp->dirty_tx = 0;
1126}
1127
1128static void sis190_down(struct net_device *dev)
1129{
1130 struct sis190_private *tp = netdev_priv(dev);
1131 void __iomem *ioaddr = tp->mmio_addr;
1132 unsigned int poll_locked = 0;
1133
1134 sis190_delete_timer(dev);
1135
1136 netif_stop_queue(dev);
1137
Francois Romieu890e8d02005-07-30 13:08:43 +02001138 do {
1139 spin_lock_irq(&tp->lock);
1140
1141 sis190_asic_down(ioaddr);
1142
1143 spin_unlock_irq(&tp->lock);
1144
1145 synchronize_irq(dev->irq);
1146
Stephen Hemmingerbea33482007-10-03 16:41:36 -07001147 if (!poll_locked)
Francois Romieu890e8d02005-07-30 13:08:43 +02001148 poll_locked++;
Francois Romieu890e8d02005-07-30 13:08:43 +02001149
1150 synchronize_sched();
1151
1152 } while (SIS_R32(IntrMask));
1153
1154 sis190_tx_clear(tp);
1155 sis190_rx_clear(tp);
1156}
1157
1158static int sis190_close(struct net_device *dev)
1159{
1160 struct sis190_private *tp = netdev_priv(dev);
1161 struct pci_dev *pdev = tp->pci_dev;
1162
1163 sis190_down(dev);
1164
1165 free_irq(dev->irq, dev);
1166
Francois Romieu890e8d02005-07-30 13:08:43 +02001167 pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma);
1168 pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma);
1169
1170 tp->TxDescRing = NULL;
1171 tp->RxDescRing = NULL;
1172
1173 return 0;
1174}
1175
Stephen Hemminger613573252009-08-31 19:50:58 +00001176static netdev_tx_t sis190_start_xmit(struct sk_buff *skb,
1177 struct net_device *dev)
Francois Romieu890e8d02005-07-30 13:08:43 +02001178{
1179 struct sis190_private *tp = netdev_priv(dev);
1180 void __iomem *ioaddr = tp->mmio_addr;
1181 u32 len, entry, dirty_tx;
1182 struct TxDesc *desc;
1183 dma_addr_t mapping;
1184
1185 if (unlikely(skb->len < ETH_ZLEN)) {
Herbert Xu5b057c62006-06-23 02:06:41 -07001186 if (skb_padto(skb, ETH_ZLEN)) {
Jeff Garzik09f75cd2007-10-03 17:41:50 -07001187 dev->stats.tx_dropped++;
Francois Romieu890e8d02005-07-30 13:08:43 +02001188 goto out;
1189 }
1190 len = ETH_ZLEN;
1191 } else {
1192 len = skb->len;
1193 }
1194
1195 entry = tp->cur_tx % NUM_TX_DESC;
1196 desc = tp->TxDescRing + entry;
1197
1198 if (unlikely(le32_to_cpu(desc->status) & OWNbit)) {
1199 netif_stop_queue(dev);
Joe Perchesad06ab22010-02-17 20:00:17 +00001200 netif_err(tp, tx_err, dev,
1201 "BUG! Tx Ring full when queue awake!\n");
Francois Romieu890e8d02005-07-30 13:08:43 +02001202 return NETDEV_TX_BUSY;
1203 }
1204
1205 mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
kirjanov@gmail.come382c302010-02-24 08:41:18 +00001206 if (pci_dma_mapping_error(tp->pci_dev, mapping)) {
1207 netif_err(tp, tx_err, dev,
1208 "PCI mapping failed, dropping packet");
1209 return NETDEV_TX_BUSY;
1210 }
Francois Romieu890e8d02005-07-30 13:08:43 +02001211
1212 tp->Tx_skbuff[entry] = skb;
1213
1214 desc->PSize = cpu_to_le32(len);
1215 desc->addr = cpu_to_le32(mapping);
1216
1217 desc->size = cpu_to_le32(len);
1218 if (entry == (NUM_TX_DESC - 1))
1219 desc->size |= cpu_to_le32(RingEnd);
1220
1221 wmb();
1222
1223 desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit);
Riccardo Ghetta08326db2010-02-17 09:28:58 +00001224 if (tp->negotiated_lpa & (LPA_1000HALF | LPA_100HALF | LPA_10HALF)) {
1225 /* Half Duplex */
1226 desc->status |= cpu_to_le32(COLEN | CRSEN | BKFEN);
1227 if (tp->negotiated_lpa & (LPA_1000HALF | LPA_1000FULL))
1228 desc->status |= cpu_to_le32(EXTEN | BSTEN); /* gigabit HD */
1229 }
Francois Romieu890e8d02005-07-30 13:08:43 +02001230
1231 tp->cur_tx++;
1232
1233 smp_wmb();
1234
1235 SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb);
1236
Francois Romieu890e8d02005-07-30 13:08:43 +02001237 dirty_tx = tp->dirty_tx;
1238 if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) {
1239 netif_stop_queue(dev);
1240 smp_rmb();
1241 if (dirty_tx != tp->dirty_tx)
1242 netif_wake_queue(dev);
1243 }
1244out:
1245 return NETDEV_TX_OK;
1246}
1247
Francois Romieufcb98212005-07-30 13:15:22 +02001248static void sis190_free_phy(struct list_head *first_phy)
1249{
1250 struct sis190_phy *cur, *next;
1251
1252 list_for_each_entry_safe(cur, next, first_phy, list) {
1253 kfree(cur);
1254 }
1255}
1256
1257/**
1258 * sis190_default_phy - Select default PHY for sis190 mac.
1259 * @dev: the net device to probe for
1260 *
1261 * Select first detected PHY with link as default.
1262 * If no one is link on, select PHY whose types is HOME as default.
1263 * If HOME doesn't exist, select LAN.
1264 */
1265static u16 sis190_default_phy(struct net_device *dev)
1266{
1267 struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan;
1268 struct sis190_private *tp = netdev_priv(dev);
1269 struct mii_if_info *mii_if = &tp->mii_if;
1270 void __iomem *ioaddr = tp->mmio_addr;
1271 u16 status;
1272
1273 phy_home = phy_default = phy_lan = NULL;
1274
1275 list_for_each_entry(phy, &tp->first_phy, list) {
1276 status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR);
1277
1278 // Link ON & Not select default PHY & not ghost PHY.
1279 if ((status & BMSR_LSTATUS) &&
1280 !phy_default &&
1281 (phy->type != UNKNOWN)) {
1282 phy_default = phy;
1283 } else {
1284 status = mdio_read(ioaddr, phy->phy_id, MII_BMCR);
1285 mdio_write(ioaddr, phy->phy_id, MII_BMCR,
1286 status | BMCR_ANENABLE | BMCR_ISOLATE);
1287 if (phy->type == HOME)
1288 phy_home = phy;
1289 else if (phy->type == LAN)
1290 phy_lan = phy;
1291 }
1292 }
1293
1294 if (!phy_default) {
1295 if (phy_home)
1296 phy_default = phy_home;
1297 else if (phy_lan)
1298 phy_default = phy_lan;
1299 else
françois romieuc2f3f3a2009-06-17 11:43:11 +00001300 phy_default = list_first_entry(&tp->first_phy,
Francois Romieufcb98212005-07-30 13:15:22 +02001301 struct sis190_phy, list);
1302 }
1303
1304 if (mii_if->phy_id != phy_default->phy_id) {
1305 mii_if->phy_id = phy_default->phy_id;
Joe Perchesad06ab22010-02-17 20:00:17 +00001306 if (netif_msg_probe(tp))
1307 pr_info("%s: Using transceiver at address %d as default\n",
1308 pci_name(tp->pci_dev), mii_if->phy_id);
Francois Romieufcb98212005-07-30 13:15:22 +02001309 }
1310
1311 status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR);
1312 status &= (~BMCR_ISOLATE);
1313
1314 mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status);
1315 status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR);
1316
1317 return status;
1318}
1319
1320static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp,
1321 struct sis190_phy *phy, unsigned int phy_id,
1322 u16 mii_status)
1323{
1324 void __iomem *ioaddr = tp->mmio_addr;
1325 struct mii_chip_info *p;
1326
1327 INIT_LIST_HEAD(&phy->list);
1328 phy->status = mii_status;
1329 phy->phy_id = phy_id;
1330
1331 phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1);
1332 phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2);
1333
1334 for (p = mii_chip_table; p->type; p++) {
1335 if ((p->id[0] == phy->id[0]) &&
1336 (p->id[1] == (phy->id[1] & 0xfff0))) {
1337 break;
1338 }
1339 }
1340
1341 if (p->id[1]) {
1342 phy->type = (p->type == MIX) ?
1343 ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ?
1344 LAN : HOME) : p->type;
Francois Romieu900eb9d2005-09-03 00:55:27 +02001345 tp->features |= p->feature;
Joe Perchesad06ab22010-02-17 20:00:17 +00001346 if (netif_msg_probe(tp))
1347 pr_info("%s: %s transceiver at address %d\n",
1348 pci_name(tp->pci_dev), p->name, phy_id);
Riccardo Ghettac3223d22009-06-04 09:04:55 +00001349 } else {
Francois Romieufcb98212005-07-30 13:15:22 +02001350 phy->type = UNKNOWN;
Joe Perchesad06ab22010-02-17 20:00:17 +00001351 if (netif_msg_probe(tp))
1352 pr_info("%s: unknown PHY 0x%x:0x%x transceiver at address %d\n",
1353 pci_name(tp->pci_dev),
1354 phy->id[0], (phy->id[1] & 0xfff0), phy_id);
Riccardo Ghettac3223d22009-06-04 09:04:55 +00001355 }
Francois Romieufcb98212005-07-30 13:15:22 +02001356}
1357
Francois Romieu900eb9d2005-09-03 00:55:27 +02001358static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp)
1359{
1360 if (tp->features & F_PHY_88E1111) {
1361 void __iomem *ioaddr = tp->mmio_addr;
1362 int phy_id = tp->mii_if.phy_id;
1363 u16 reg[2][2] = {
1364 { 0x808b, 0x0ce1 },
1365 { 0x808f, 0x0c60 }
1366 }, *p;
1367
1368 p = (tp->features & F_HAS_RGMII) ? reg[0] : reg[1];
1369
1370 mdio_write(ioaddr, phy_id, 0x1b, p[0]);
1371 udelay(200);
1372 mdio_write(ioaddr, phy_id, 0x14, p[1]);
1373 udelay(200);
1374 }
1375}
1376
Francois Romieufcb98212005-07-30 13:15:22 +02001377/**
1378 * sis190_mii_probe - Probe MII PHY for sis190
1379 * @dev: the net device to probe for
1380 *
1381 * Search for total of 32 possible mii phy addresses.
1382 * Identify and set current phy if found one,
1383 * return error if it failed to found.
1384 */
1385static int __devinit sis190_mii_probe(struct net_device *dev)
1386{
1387 struct sis190_private *tp = netdev_priv(dev);
1388 struct mii_if_info *mii_if = &tp->mii_if;
1389 void __iomem *ioaddr = tp->mmio_addr;
1390 int phy_id;
1391 int rc = 0;
1392
1393 INIT_LIST_HEAD(&tp->first_phy);
1394
1395 for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
1396 struct sis190_phy *phy;
1397 u16 status;
1398
1399 status = mdio_read_latched(ioaddr, phy_id, MII_BMSR);
1400
1401 // Try next mii if the current one is not accessible.
1402 if (status == 0xffff || status == 0x0000)
1403 continue;
1404
1405 phy = kmalloc(sizeof(*phy), GFP_KERNEL);
1406 if (!phy) {
1407 sis190_free_phy(&tp->first_phy);
1408 rc = -ENOMEM;
1409 goto out;
1410 }
1411
1412 sis190_init_phy(dev, tp, phy, phy_id, status);
1413
1414 list_add(&tp->first_phy, &phy->list);
1415 }
1416
1417 if (list_empty(&tp->first_phy)) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001418 if (netif_msg_probe(tp))
1419 pr_info("%s: No MII transceivers found!\n",
1420 pci_name(tp->pci_dev));
Francois Romieufcb98212005-07-30 13:15:22 +02001421 rc = -EIO;
1422 goto out;
1423 }
1424
1425 /* Select default PHY for mac */
1426 sis190_default_phy(dev);
1427
Francois Romieu900eb9d2005-09-03 00:55:27 +02001428 sis190_mii_probe_88e1111_fixup(tp);
1429
Francois Romieufcb98212005-07-30 13:15:22 +02001430 mii_if->dev = dev;
1431 mii_if->mdio_read = __mdio_read;
1432 mii_if->mdio_write = __mdio_write;
1433 mii_if->phy_id_mask = PHY_ID_ANY;
1434 mii_if->reg_num_mask = MII_REG_ANY;
1435out:
1436 return rc;
1437}
1438
Adrian Bunkc2b75f02007-12-11 23:23:56 +01001439static void sis190_mii_remove(struct net_device *dev)
Francois Romieufcb98212005-07-30 13:15:22 +02001440{
1441 struct sis190_private *tp = netdev_priv(dev);
1442
1443 sis190_free_phy(&tp->first_phy);
1444}
1445
Francois Romieu890e8d02005-07-30 13:08:43 +02001446static void sis190_release_board(struct pci_dev *pdev)
1447{
1448 struct net_device *dev = pci_get_drvdata(pdev);
1449 struct sis190_private *tp = netdev_priv(dev);
1450
1451 iounmap(tp->mmio_addr);
1452 pci_release_regions(pdev);
1453 pci_disable_device(pdev);
1454 free_netdev(dev);
1455}
1456
1457static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
1458{
1459 struct sis190_private *tp;
1460 struct net_device *dev;
1461 void __iomem *ioaddr;
1462 int rc;
1463
1464 dev = alloc_etherdev(sizeof(*tp));
1465 if (!dev) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001466 if (netif_msg_drv(&debug))
1467 pr_err("unable to alloc new ethernet\n");
Francois Romieu890e8d02005-07-30 13:08:43 +02001468 rc = -ENOMEM;
1469 goto err_out_0;
1470 }
1471
Francois Romieu890e8d02005-07-30 13:08:43 +02001472 SET_NETDEV_DEV(dev, &pdev->dev);
1473
1474 tp = netdev_priv(dev);
David Howellsc4028952006-11-22 14:57:56 +00001475 tp->dev = dev;
Francois Romieu890e8d02005-07-30 13:08:43 +02001476 tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT);
1477
1478 rc = pci_enable_device(pdev);
1479 if (rc < 0) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001480 if (netif_msg_probe(tp))
1481 pr_err("%s: enable failure\n", pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001482 goto err_free_dev_1;
1483 }
1484
1485 rc = -ENODEV;
1486
1487 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001488 if (netif_msg_probe(tp))
1489 pr_err("%s: region #0 is no MMIO resource\n",
1490 pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001491 goto err_pci_disable_2;
1492 }
1493 if (pci_resource_len(pdev, 0) < SIS190_REGS_SIZE) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001494 if (netif_msg_probe(tp))
1495 pr_err("%s: invalid PCI region size(s)\n",
1496 pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001497 goto err_pci_disable_2;
1498 }
1499
1500 rc = pci_request_regions(pdev, DRV_NAME);
1501 if (rc < 0) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001502 if (netif_msg_probe(tp))
1503 pr_err("%s: could not request regions\n",
1504 pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001505 goto err_pci_disable_2;
1506 }
1507
Yang Hongyang284901a2009-04-06 19:01:15 -07001508 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
Francois Romieu890e8d02005-07-30 13:08:43 +02001509 if (rc < 0) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001510 if (netif_msg_probe(tp))
1511 pr_err("%s: DMA configuration failed\n",
1512 pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001513 goto err_free_res_3;
1514 }
1515
1516 pci_set_master(pdev);
1517
1518 ioaddr = ioremap(pci_resource_start(pdev, 0), SIS190_REGS_SIZE);
1519 if (!ioaddr) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001520 if (netif_msg_probe(tp))
1521 pr_err("%s: cannot remap MMIO, aborting\n",
1522 pci_name(pdev));
Francois Romieu890e8d02005-07-30 13:08:43 +02001523 rc = -EIO;
1524 goto err_free_res_3;
1525 }
1526
1527 tp->pci_dev = pdev;
1528 tp->mmio_addr = ioaddr;
Herton Ronaldo Krzesinskib88aafd2010-03-02 03:44:41 -08001529 tp->link_status = LNK_OFF;
Francois Romieu890e8d02005-07-30 13:08:43 +02001530
1531 sis190_irq_mask_and_ack(ioaddr);
1532
1533 sis190_soft_reset(ioaddr);
1534out:
1535 return dev;
1536
1537err_free_res_3:
1538 pci_release_regions(pdev);
1539err_pci_disable_2:
1540 pci_disable_device(pdev);
1541err_free_dev_1:
1542 free_netdev(dev);
1543err_out_0:
1544 dev = ERR_PTR(rc);
1545 goto out;
1546}
1547
1548static void sis190_tx_timeout(struct net_device *dev)
1549{
1550 struct sis190_private *tp = netdev_priv(dev);
1551 void __iomem *ioaddr = tp->mmio_addr;
1552 u8 tmp8;
1553
1554 /* Disable Tx, if not already */
1555 tmp8 = SIS_R8(TxControl);
1556 if (tmp8 & CmdTxEnb)
1557 SIS_W8(TxControl, tmp8 & ~CmdTxEnb);
1558
Joe Perchesad06ab22010-02-17 20:00:17 +00001559 netif_info(tp, tx_err, dev, "Transmit timeout, status %08x %08x\n",
1560 SIS_R32(TxControl), SIS_R32(TxSts));
Francois Romieu188f23b2005-07-30 13:11:43 +02001561
Francois Romieu890e8d02005-07-30 13:08:43 +02001562 /* Disable interrupts by clearing the interrupt mask. */
1563 SIS_W32(IntrMask, 0x0000);
1564
1565 /* Stop a shared interrupt from scavenging while we are. */
1566 spin_lock_irq(&tp->lock);
1567 sis190_tx_clear(tp);
1568 spin_unlock_irq(&tp->lock);
1569
1570 /* ...and finally, reset everything. */
1571 sis190_hw_start(dev);
1572
1573 netif_wake_queue(dev);
1574}
1575
Francois Romieu900eb9d2005-09-03 00:55:27 +02001576static void sis190_set_rgmii(struct sis190_private *tp, u8 reg)
1577{
1578 tp->features |= (reg & 0x80) ? F_HAS_RGMII : 0;
1579}
1580
Francois Romieu830fb7d2005-07-30 13:12:37 +02001581static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
1582 struct net_device *dev)
1583{
1584 struct sis190_private *tp = netdev_priv(dev);
1585 void __iomem *ioaddr = tp->mmio_addr;
1586 u16 sig;
1587 int i;
1588
Joe Perchesad06ab22010-02-17 20:00:17 +00001589 if (netif_msg_probe(tp))
1590 pr_info("%s: Read MAC address from EEPROM\n", pci_name(pdev));
Francois Romieu830fb7d2005-07-30 13:12:37 +02001591
1592 /* Check to see if there is a sane EEPROM */
1593 sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature);
1594
1595 if ((sig == 0xffff) || (sig == 0x0000)) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001596 if (netif_msg_probe(tp))
1597 pr_info("%s: Error EEPROM read %x\n",
1598 pci_name(pdev), sig);
Francois Romieu830fb7d2005-07-30 13:12:37 +02001599 return -EIO;
1600 }
1601
1602 /* Get MAC address from EEPROM */
1603 for (i = 0; i < MAC_ADDR_LEN / 2; i++) {
Al Viro961994a2007-12-15 01:44:33 +00001604 u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
Francois Romieu830fb7d2005-07-30 13:12:37 +02001605
Al Viro961994a2007-12-15 01:44:33 +00001606 ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(w);
Francois Romieu830fb7d2005-07-30 13:12:37 +02001607 }
1608
Francois Romieu900eb9d2005-09-03 00:55:27 +02001609 sis190_set_rgmii(tp, sis190_read_eeprom(ioaddr, EEPROMInfo));
1610
Francois Romieu830fb7d2005-07-30 13:12:37 +02001611 return 0;
1612}
1613
1614/**
Francois Romieuebc71642007-12-04 22:58:41 +01001615 * sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model
Francois Romieu830fb7d2005-07-30 13:12:37 +02001616 * @pdev: PCI device
1617 * @dev: network device to get address for
1618 *
Francois Romieuebc71642007-12-04 22:58:41 +01001619 * SiS96x model, use APC CMOS RAM to store MAC address.
Francois Romieu830fb7d2005-07-30 13:12:37 +02001620 * APC CMOS RAM is accessed through ISA bridge.
1621 * MAC address is read into @net_dev->dev_addr.
1622 */
1623static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
1624 struct net_device *dev)
1625{
Francois Romieuebc71642007-12-04 22:58:41 +01001626 static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 };
Francois Romieu830fb7d2005-07-30 13:12:37 +02001627 struct sis190_private *tp = netdev_priv(dev);
1628 struct pci_dev *isa_bridge;
1629 u8 reg, tmp8;
Francois Romieuebc71642007-12-04 22:58:41 +01001630 unsigned int i;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001631
Joe Perchesad06ab22010-02-17 20:00:17 +00001632 if (netif_msg_probe(tp))
1633 pr_info("%s: Read MAC address from APC\n", pci_name(pdev));
Francois Romieu830fb7d2005-07-30 13:12:37 +02001634
Francois Romieuebc71642007-12-04 22:58:41 +01001635 for (i = 0; i < ARRAY_SIZE(ids); i++) {
1636 isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL);
1637 if (isa_bridge)
1638 break;
1639 }
Neil Muller8eb7ad62007-08-01 17:52:04 +02001640
Francois Romieu830fb7d2005-07-30 13:12:37 +02001641 if (!isa_bridge) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001642 if (netif_msg_probe(tp))
1643 pr_info("%s: Can not find ISA bridge\n",
1644 pci_name(pdev));
Francois Romieu830fb7d2005-07-30 13:12:37 +02001645 return -EIO;
1646 }
1647
1648 /* Enable port 78h & 79h to access APC Registers. */
1649 pci_read_config_byte(isa_bridge, 0x48, &tmp8);
1650 reg = (tmp8 & ~0x02);
1651 pci_write_config_byte(isa_bridge, 0x48, reg);
1652 udelay(50);
1653 pci_read_config_byte(isa_bridge, 0x48, &reg);
1654
1655 for (i = 0; i < MAC_ADDR_LEN; i++) {
1656 outb(0x9 + i, 0x78);
1657 dev->dev_addr[i] = inb(0x79);
1658 }
1659
1660 outb(0x12, 0x78);
1661 reg = inb(0x79);
1662
Francois Romieu900eb9d2005-09-03 00:55:27 +02001663 sis190_set_rgmii(tp, reg);
1664
Francois Romieu830fb7d2005-07-30 13:12:37 +02001665 /* Restore the value to ISA Bridge */
1666 pci_write_config_byte(isa_bridge, 0x48, tmp8);
1667 pci_dev_put(isa_bridge);
1668
1669 return 0;
1670}
1671
1672/**
1673 * sis190_init_rxfilter - Initialize the Rx filter
1674 * @dev: network device to initialize
1675 *
1676 * Set receive filter address to our MAC address
1677 * and enable packet filtering.
1678 */
1679static inline void sis190_init_rxfilter(struct net_device *dev)
1680{
1681 struct sis190_private *tp = netdev_priv(dev);
1682 void __iomem *ioaddr = tp->mmio_addr;
1683 u16 ctl;
1684 int i;
1685
1686 ctl = SIS_R16(RxMacControl);
1687 /*
1688 * Disable packet filtering before setting filter.
1689 * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits
1690 * only and followed by RxMacAddr (6 bytes). Strange. -- FR
1691 */
1692 SIS_W16(RxMacControl, ctl & ~0x0f00);
1693
1694 for (i = 0; i < MAC_ADDR_LEN; i++)
1695 SIS_W8(RxMacAddr + i, dev->dev_addr[i]);
1696
1697 SIS_W16(RxMacControl, ctl);
1698 SIS_PCI_COMMIT();
1699}
1700
Jeff Garzik7d2e3cb2008-05-13 01:41:58 -04001701static int __devinit sis190_get_mac_addr(struct pci_dev *pdev,
Sergio Luisd785ad742008-02-10 17:56:25 -03001702 struct net_device *dev)
Francois Romieu830fb7d2005-07-30 13:12:37 +02001703{
Francois Romieu563e0ae2008-02-18 21:20:32 +01001704 int rc;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001705
Francois Romieu563e0ae2008-02-18 21:20:32 +01001706 rc = sis190_get_mac_addr_from_eeprom(pdev, dev);
1707 if (rc < 0) {
1708 u8 reg;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001709
Francois Romieu563e0ae2008-02-18 21:20:32 +01001710 pci_read_config_byte(pdev, 0x73, &reg);
1711
1712 if (reg & 0x00000001)
1713 rc = sis190_get_mac_addr_from_apc(pdev, dev);
1714 }
1715 return rc;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001716}
1717
Francois Romieu890e8d02005-07-30 13:08:43 +02001718static void sis190_set_speed_auto(struct net_device *dev)
1719{
1720 struct sis190_private *tp = netdev_priv(dev);
1721 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9ede1092005-07-30 13:14:38 +02001722 int phy_id = tp->mii_if.phy_id;
Francois Romieu890e8d02005-07-30 13:08:43 +02001723 int val;
1724
Joe Perchesad06ab22010-02-17 20:00:17 +00001725 netif_info(tp, link, dev, "Enabling Auto-negotiation\n");
Francois Romieu890e8d02005-07-30 13:08:43 +02001726
Francois Romieu9ede1092005-07-30 13:14:38 +02001727 val = mdio_read(ioaddr, phy_id, MII_ADVERTISE);
Francois Romieu890e8d02005-07-30 13:08:43 +02001728
1729 // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0
1730 // unchanged.
Francois Romieu9ede1092005-07-30 13:14:38 +02001731 mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) |
Francois Romieu890e8d02005-07-30 13:08:43 +02001732 ADVERTISE_100FULL | ADVERTISE_10FULL |
1733 ADVERTISE_100HALF | ADVERTISE_10HALF);
1734
1735 // Enable 1000 Full Mode.
Francois Romieu9ede1092005-07-30 13:14:38 +02001736 mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL);
Francois Romieu890e8d02005-07-30 13:08:43 +02001737
1738 // Enable auto-negotiation and restart auto-negotiation.
Francois Romieu9ede1092005-07-30 13:14:38 +02001739 mdio_write(ioaddr, phy_id, MII_BMCR,
Francois Romieu890e8d02005-07-30 13:08:43 +02001740 BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET);
1741}
1742
Francois Romieu43afb942005-07-30 13:10:21 +02001743static int sis190_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1744{
1745 struct sis190_private *tp = netdev_priv(dev);
1746
1747 return mii_ethtool_gset(&tp->mii_if, cmd);
1748}
1749
1750static int sis190_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1751{
1752 struct sis190_private *tp = netdev_priv(dev);
1753
1754 return mii_ethtool_sset(&tp->mii_if, cmd);
1755}
1756
Francois Romieu890e8d02005-07-30 13:08:43 +02001757static void sis190_get_drvinfo(struct net_device *dev,
1758 struct ethtool_drvinfo *info)
1759{
1760 struct sis190_private *tp = netdev_priv(dev);
1761
1762 strcpy(info->driver, DRV_NAME);
1763 strcpy(info->version, DRV_VERSION);
1764 strcpy(info->bus_info, pci_name(tp->pci_dev));
1765}
1766
1767static int sis190_get_regs_len(struct net_device *dev)
1768{
1769 return SIS190_REGS_SIZE;
1770}
1771
1772static void sis190_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1773 void *p)
1774{
1775 struct sis190_private *tp = netdev_priv(dev);
1776 unsigned long flags;
1777
1778 if (regs->len > SIS190_REGS_SIZE)
1779 regs->len = SIS190_REGS_SIZE;
1780
1781 spin_lock_irqsave(&tp->lock, flags);
1782 memcpy_fromio(p, tp->mmio_addr, regs->len);
1783 spin_unlock_irqrestore(&tp->lock, flags);
1784}
1785
Francois Romieu43afb942005-07-30 13:10:21 +02001786static int sis190_nway_reset(struct net_device *dev)
1787{
1788 struct sis190_private *tp = netdev_priv(dev);
1789
1790 return mii_nway_restart(&tp->mii_if);
1791}
1792
Francois Romieu890e8d02005-07-30 13:08:43 +02001793static u32 sis190_get_msglevel(struct net_device *dev)
1794{
1795 struct sis190_private *tp = netdev_priv(dev);
1796
1797 return tp->msg_enable;
1798}
1799
1800static void sis190_set_msglevel(struct net_device *dev, u32 value)
1801{
1802 struct sis190_private *tp = netdev_priv(dev);
1803
1804 tp->msg_enable = value;
1805}
1806
Jeff Garzik7282d492006-09-13 14:30:00 -04001807static const struct ethtool_ops sis190_ethtool_ops = {
Francois Romieu43afb942005-07-30 13:10:21 +02001808 .get_settings = sis190_get_settings,
1809 .set_settings = sis190_set_settings,
Francois Romieu890e8d02005-07-30 13:08:43 +02001810 .get_drvinfo = sis190_get_drvinfo,
1811 .get_regs_len = sis190_get_regs_len,
1812 .get_regs = sis190_get_regs,
1813 .get_link = ethtool_op_get_link,
1814 .get_msglevel = sis190_get_msglevel,
1815 .set_msglevel = sis190_set_msglevel,
Francois Romieu43afb942005-07-30 13:10:21 +02001816 .nway_reset = sis190_nway_reset,
Francois Romieu890e8d02005-07-30 13:08:43 +02001817};
1818
Francois Romieu43afb942005-07-30 13:10:21 +02001819static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1820{
1821 struct sis190_private *tp = netdev_priv(dev);
1822
1823 return !netif_running(dev) ? -EINVAL :
1824 generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL);
1825}
1826
Stephen Hemminger97488c52009-01-07 17:35:41 -08001827static const struct net_device_ops sis190_netdev_ops = {
1828 .ndo_open = sis190_open,
1829 .ndo_stop = sis190_close,
1830 .ndo_do_ioctl = sis190_ioctl,
1831 .ndo_start_xmit = sis190_start_xmit,
1832 .ndo_tx_timeout = sis190_tx_timeout,
1833 .ndo_set_multicast_list = sis190_set_rx_mode,
1834 .ndo_change_mtu = eth_change_mtu,
1835 .ndo_set_mac_address = eth_mac_addr,
1836 .ndo_validate_addr = eth_validate_addr,
1837#ifdef CONFIG_NET_POLL_CONTROLLER
1838 .ndo_poll_controller = sis190_netpoll,
1839#endif
1840};
1841
Francois Romieu890e8d02005-07-30 13:08:43 +02001842static int __devinit sis190_init_one(struct pci_dev *pdev,
1843 const struct pci_device_id *ent)
1844{
1845 static int printed_version = 0;
1846 struct sis190_private *tp;
1847 struct net_device *dev;
1848 void __iomem *ioaddr;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001849 int rc;
Francois Romieu890e8d02005-07-30 13:08:43 +02001850
1851 if (!printed_version) {
Joe Perchesad06ab22010-02-17 20:00:17 +00001852 if (netif_msg_drv(&debug))
1853 pr_info(SIS190_DRIVER_NAME " loaded\n");
Francois Romieu890e8d02005-07-30 13:08:43 +02001854 printed_version = 1;
1855 }
1856
1857 dev = sis190_init_board(pdev);
1858 if (IS_ERR(dev)) {
1859 rc = PTR_ERR(dev);
1860 goto out;
1861 }
1862
Francois Romieu10487fb2006-02-16 22:17:00 +01001863 pci_set_drvdata(pdev, dev);
1864
Francois Romieu890e8d02005-07-30 13:08:43 +02001865 tp = netdev_priv(dev);
1866 ioaddr = tp->mmio_addr;
1867
Francois Romieu830fb7d2005-07-30 13:12:37 +02001868 rc = sis190_get_mac_addr(pdev, dev);
1869 if (rc < 0)
1870 goto err_release_board;
Francois Romieu890e8d02005-07-30 13:08:43 +02001871
Francois Romieu830fb7d2005-07-30 13:12:37 +02001872 sis190_init_rxfilter(dev);
Francois Romieu890e8d02005-07-30 13:08:43 +02001873
David Howellsc4028952006-11-22 14:57:56 +00001874 INIT_WORK(&tp->phy_task, sis190_phy_task);
Francois Romieu890e8d02005-07-30 13:08:43 +02001875
Stephen Hemminger97488c52009-01-07 17:35:41 -08001876 dev->netdev_ops = &sis190_netdev_ops;
1877
Francois Romieu890e8d02005-07-30 13:08:43 +02001878 SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops);
1879 dev->irq = pdev->irq;
1880 dev->base_addr = (unsigned long) 0xdead;
Stephen Hemminger97488c52009-01-07 17:35:41 -08001881 dev->watchdog_timeo = SIS190_TX_TIMEOUT;
Francois Romieu890e8d02005-07-30 13:08:43 +02001882
1883 spin_lock_init(&tp->lock);
Francois Romieu890e8d02005-07-30 13:08:43 +02001884
Francois Romieufcb98212005-07-30 13:15:22 +02001885 rc = sis190_mii_probe(dev);
1886 if (rc < 0)
Francois Romieu3690b6c2005-08-26 00:30:37 +02001887 goto err_release_board;
1888
1889 rc = register_netdev(dev);
1890 if (rc < 0)
1891 goto err_remove_mii;
1892
Joe Perchesad06ab22010-02-17 20:00:17 +00001893 if (netif_msg_probe(tp)) {
1894 netdev_info(dev, "%s: %s at %p (IRQ: %d), %pM\n",
1895 pci_name(pdev),
1896 sis_chip_info[ent->driver_data].name,
1897 ioaddr, dev->irq, dev->dev_addr);
1898 netdev_info(dev, "%s mode.\n",
1899 (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
1900 }
Francois Romieu900eb9d2005-09-03 00:55:27 +02001901
Francois Romieu890e8d02005-07-30 13:08:43 +02001902 netif_carrier_off(dev);
1903
1904 sis190_set_speed_auto(dev);
1905out:
1906 return rc;
Francois Romieu830fb7d2005-07-30 13:12:37 +02001907
Francois Romieu3690b6c2005-08-26 00:30:37 +02001908err_remove_mii:
1909 sis190_mii_remove(dev);
Francois Romieu830fb7d2005-07-30 13:12:37 +02001910err_release_board:
1911 sis190_release_board(pdev);
1912 goto out;
Francois Romieu890e8d02005-07-30 13:08:43 +02001913}
1914
1915static void __devexit sis190_remove_one(struct pci_dev *pdev)
1916{
1917 struct net_device *dev = pci_get_drvdata(pdev);
1918
Francois Romieufcb98212005-07-30 13:15:22 +02001919 sis190_mii_remove(dev);
Francois Romieuc014f6c2007-02-15 23:37:29 +01001920 flush_scheduled_work();
Francois Romieu890e8d02005-07-30 13:08:43 +02001921 unregister_netdev(dev);
1922 sis190_release_board(pdev);
1923 pci_set_drvdata(pdev, NULL);
1924}
1925
1926static struct pci_driver sis190_pci_driver = {
1927 .name = DRV_NAME,
1928 .id_table = sis190_pci_tbl,
1929 .probe = sis190_init_one,
1930 .remove = __devexit_p(sis190_remove_one),
1931};
1932
1933static int __init sis190_init_module(void)
1934{
Jeff Garzik29917622006-08-19 17:48:59 -04001935 return pci_register_driver(&sis190_pci_driver);
Francois Romieu890e8d02005-07-30 13:08:43 +02001936}
1937
1938static void __exit sis190_cleanup_module(void)
1939{
1940 pci_unregister_driver(&sis190_pci_driver);
1941}
1942
1943module_init(sis190_init_module);
1944module_exit(sis190_cleanup_module);