blob: 123c6a5c5fe66dd1b02f950df5ef6d55bf8599a3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Francois Romieu07d3f512007-02-21 22:40:46 +01002 * r8169.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/delay.h>
17#include <linux/ethtool.h>
18#include <linux/mii.h>
19#include <linux/if_vlan.h>
20#include <linux/crc32.h>
21#include <linux/in.h>
22#include <linux/ip.h>
23#include <linux/tcp.h>
24#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000025#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/dma-mapping.h>
Rafael J. Wysockie1759442010-03-14 14:33:51 +000027#include <linux/pm_runtime.h>
françois romieubca03d52011-01-03 15:07:31 +000028#include <linux/firmware.h>
Stanislaw Gruszkaba04c7c2011-02-22 02:00:11 +000029#include <linux/pci-aspm.h>
Paul Gortmaker70c71602011-05-22 16:47:17 -040030#include <linux/prefetch.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <asm/io.h>
33#include <asm/irq.h>
34
Francois Romieu865c6522008-05-11 14:51:00 +020035#define RTL8169_VERSION "2.3LK-NAPI"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MODULENAME "r8169"
37#define PFX MODULENAME ": "
38
françois romieubca03d52011-01-03 15:07:31 +000039#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
40#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
hayeswang01dc7fe2011-03-21 01:50:28 +000041#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
42#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
Hayes Wang70090422011-07-06 15:58:06 +080043#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
Hayes Wangc2218922011-09-06 16:55:18 +080044#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
45#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
Hayes Wang5a5e4442011-02-22 17:26:21 +080046#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
Hayes Wang7e18dca2012-03-30 14:33:02 +080047#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
Hayes Wangb3d7b2f2012-03-30 14:48:06 +080048#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
Hayes Wang5598bfe2012-07-02 17:23:21 +080049#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
Hayes Wangc5583862012-07-02 17:23:22 +080050#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
françois romieubca03d52011-01-03 15:07:31 +000051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#ifdef RTL8169_DEBUG
53#define assert(expr) \
Francois Romieu5b0384f2006-08-16 16:00:01 +020054 if (!(expr)) { \
55 printk( "Assertion failed! %s,%s,%s,line=%d\n", \
Harvey Harrisonb39d66a2008-08-20 16:52:04 -070056 #expr,__FILE__,__func__,__LINE__); \
Francois Romieu5b0384f2006-08-16 16:00:01 +020057 }
Joe Perches06fa7352007-10-18 21:15:00 +020058#define dprintk(fmt, args...) \
59 do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#else
61#define assert(expr) do {} while (0)
62#define dprintk(fmt, args...) do {} while (0)
63#endif /* RTL8169_DEBUG */
64
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020065#define R8169_MSG_DEFAULT \
Francois Romieuf0e837d2005-09-30 16:54:02 -070066 (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020067
Julien Ducourthial477206a2012-05-09 00:00:06 +020068#define TX_SLOTS_AVAIL(tp) \
69 (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
70
71/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
72#define TX_FRAGS_READY_FOR(tp,nr_frags) \
73 (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
76 The RTL chips use a 64 element hash table based on the Ethernet CRC. */
Arjan van de Venf71e1302006-03-03 21:33:57 -050077static const int multicast_filter_limit = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Francois Romieu9c14cea2008-07-05 00:21:15 +020079#define MAX_READ_REQUEST_SHIFT 12
Michal Schmidtaee77e42012-09-09 13:55:26 +000080#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
82#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
83
84#define R8169_REGS_SIZE 256
85#define R8169_NAPI_WEIGHT 64
86#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
87#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
88#define RX_BUF_SIZE 1536 /* Rx Buffer size */
89#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
90#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
91
92#define RTL8169_TX_TIMEOUT (6*HZ)
93#define RTL8169_PHY_TIMEOUT (10*HZ)
94
françois romieuea8dbdd2009-03-15 01:10:50 +000095#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
96#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
Francois Romieue1564ec2008-10-16 22:46:13 +020097#define RTL_EEPROM_SIG_ADDR 0x0000
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099/* write/read MMIO register */
100#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
101#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
102#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
103#define RTL_R8(reg) readb (ioaddr + (reg))
104#define RTL_R16(reg) readw (ioaddr + (reg))
Junchang Wang06f555f2010-05-30 02:26:07 +0000105#define RTL_R32(reg) readl (ioaddr + (reg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107enum mac_version {
Francois Romieu85bffe62011-04-27 08:22:39 +0200108 RTL_GIGA_MAC_VER_01 = 0,
109 RTL_GIGA_MAC_VER_02,
110 RTL_GIGA_MAC_VER_03,
111 RTL_GIGA_MAC_VER_04,
112 RTL_GIGA_MAC_VER_05,
113 RTL_GIGA_MAC_VER_06,
114 RTL_GIGA_MAC_VER_07,
115 RTL_GIGA_MAC_VER_08,
116 RTL_GIGA_MAC_VER_09,
117 RTL_GIGA_MAC_VER_10,
118 RTL_GIGA_MAC_VER_11,
119 RTL_GIGA_MAC_VER_12,
120 RTL_GIGA_MAC_VER_13,
121 RTL_GIGA_MAC_VER_14,
122 RTL_GIGA_MAC_VER_15,
123 RTL_GIGA_MAC_VER_16,
124 RTL_GIGA_MAC_VER_17,
125 RTL_GIGA_MAC_VER_18,
126 RTL_GIGA_MAC_VER_19,
127 RTL_GIGA_MAC_VER_20,
128 RTL_GIGA_MAC_VER_21,
129 RTL_GIGA_MAC_VER_22,
130 RTL_GIGA_MAC_VER_23,
131 RTL_GIGA_MAC_VER_24,
132 RTL_GIGA_MAC_VER_25,
133 RTL_GIGA_MAC_VER_26,
134 RTL_GIGA_MAC_VER_27,
135 RTL_GIGA_MAC_VER_28,
136 RTL_GIGA_MAC_VER_29,
137 RTL_GIGA_MAC_VER_30,
138 RTL_GIGA_MAC_VER_31,
139 RTL_GIGA_MAC_VER_32,
140 RTL_GIGA_MAC_VER_33,
Hayes Wang70090422011-07-06 15:58:06 +0800141 RTL_GIGA_MAC_VER_34,
Hayes Wangc2218922011-09-06 16:55:18 +0800142 RTL_GIGA_MAC_VER_35,
143 RTL_GIGA_MAC_VER_36,
Hayes Wang7e18dca2012-03-30 14:33:02 +0800144 RTL_GIGA_MAC_VER_37,
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800145 RTL_GIGA_MAC_VER_38,
Hayes Wang5598bfe2012-07-02 17:23:21 +0800146 RTL_GIGA_MAC_VER_39,
Hayes Wangc5583862012-07-02 17:23:22 +0800147 RTL_GIGA_MAC_VER_40,
148 RTL_GIGA_MAC_VER_41,
Francois Romieu85bffe62011-04-27 08:22:39 +0200149 RTL_GIGA_MAC_NONE = 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150};
151
Francois Romieu2b7b4312011-04-18 22:53:24 -0700152enum rtl_tx_desc_version {
153 RTL_TD_0 = 0,
154 RTL_TD_1 = 1,
155};
156
Francois Romieud58d46b2011-05-03 16:38:29 +0200157#define JUMBO_1K ETH_DATA_LEN
158#define JUMBO_4K (4*1024 - ETH_HLEN - 2)
159#define JUMBO_6K (6*1024 - ETH_HLEN - 2)
160#define JUMBO_7K (7*1024 - ETH_HLEN - 2)
161#define JUMBO_9K (9*1024 - ETH_HLEN - 2)
162
163#define _R(NAME,TD,FW,SZ,B) { \
164 .name = NAME, \
165 .txd_version = TD, \
166 .fw_name = FW, \
167 .jumbo_max = SZ, \
168 .jumbo_tx_csum = B \
169}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Jesper Juhl3c6bee12006-01-09 20:54:01 -0800171static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 const char *name;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700173 enum rtl_tx_desc_version txd_version;
Francois Romieu85bffe62011-04-27 08:22:39 +0200174 const char *fw_name;
Francois Romieud58d46b2011-05-03 16:38:29 +0200175 u16 jumbo_max;
176 bool jumbo_tx_csum;
Francois Romieu85bffe62011-04-27 08:22:39 +0200177} rtl_chip_infos[] = {
178 /* PCI devices. */
179 [RTL_GIGA_MAC_VER_01] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200180 _R("RTL8169", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200181 [RTL_GIGA_MAC_VER_02] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200182 _R("RTL8169s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200183 [RTL_GIGA_MAC_VER_03] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200184 _R("RTL8110s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200185 [RTL_GIGA_MAC_VER_04] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200186 _R("RTL8169sb/8110sb", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200187 [RTL_GIGA_MAC_VER_05] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200188 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200189 [RTL_GIGA_MAC_VER_06] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200190 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200191 /* PCI-E devices. */
192 [RTL_GIGA_MAC_VER_07] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200193 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200194 [RTL_GIGA_MAC_VER_08] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200195 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200196 [RTL_GIGA_MAC_VER_09] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200197 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200198 [RTL_GIGA_MAC_VER_10] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200199 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200200 [RTL_GIGA_MAC_VER_11] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200201 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200202 [RTL_GIGA_MAC_VER_12] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200203 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200204 [RTL_GIGA_MAC_VER_13] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200205 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200206 [RTL_GIGA_MAC_VER_14] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200207 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200208 [RTL_GIGA_MAC_VER_15] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200209 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200210 [RTL_GIGA_MAC_VER_16] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200211 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200212 [RTL_GIGA_MAC_VER_17] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200213 _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200214 [RTL_GIGA_MAC_VER_18] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200215 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200216 [RTL_GIGA_MAC_VER_19] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200217 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200218 [RTL_GIGA_MAC_VER_20] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200219 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200220 [RTL_GIGA_MAC_VER_21] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200221 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200222 [RTL_GIGA_MAC_VER_22] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200223 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200224 [RTL_GIGA_MAC_VER_23] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200225 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200226 [RTL_GIGA_MAC_VER_24] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200227 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200228 [RTL_GIGA_MAC_VER_25] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200229 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1,
230 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200231 [RTL_GIGA_MAC_VER_26] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200232 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2,
233 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200234 [RTL_GIGA_MAC_VER_27] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200235 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200236 [RTL_GIGA_MAC_VER_28] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200237 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200238 [RTL_GIGA_MAC_VER_29] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200239 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
240 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200241 [RTL_GIGA_MAC_VER_30] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200242 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
243 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200244 [RTL_GIGA_MAC_VER_31] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200245 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200246 [RTL_GIGA_MAC_VER_32] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200247 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1,
248 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200249 [RTL_GIGA_MAC_VER_33] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200250 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2,
251 JUMBO_9K, false),
Hayes Wang70090422011-07-06 15:58:06 +0800252 [RTL_GIGA_MAC_VER_34] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200253 _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
254 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800255 [RTL_GIGA_MAC_VER_35] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200256 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_1,
257 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800258 [RTL_GIGA_MAC_VER_36] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200259 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2,
260 JUMBO_9K, false),
Hayes Wang7e18dca2012-03-30 14:33:02 +0800261 [RTL_GIGA_MAC_VER_37] =
262 _R("RTL8402", RTL_TD_1, FIRMWARE_8402_1,
263 JUMBO_1K, true),
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800264 [RTL_GIGA_MAC_VER_38] =
265 _R("RTL8411", RTL_TD_1, FIRMWARE_8411_1,
266 JUMBO_9K, false),
Hayes Wang5598bfe2012-07-02 17:23:21 +0800267 [RTL_GIGA_MAC_VER_39] =
268 _R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_1,
269 JUMBO_1K, true),
Hayes Wangc5583862012-07-02 17:23:22 +0800270 [RTL_GIGA_MAC_VER_40] =
271 _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_1,
272 JUMBO_9K, false),
273 [RTL_GIGA_MAC_VER_41] =
274 _R("RTL8168g/8111g", RTL_TD_1, NULL, JUMBO_9K, false),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275};
276#undef _R
277
Francois Romieubcf0bf92006-07-26 23:14:13 +0200278enum cfg_version {
279 RTL_CFG_0 = 0x00,
280 RTL_CFG_1,
281 RTL_CFG_2
282};
283
Alexey Dobriyana3aa1882010-01-07 11:58:11 +0000284static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
Francois Romieubcf0bf92006-07-26 23:14:13 +0200285 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
Francois Romieud2eed8c2006-08-31 22:01:07 +0200286 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
Francois Romieud81bf552006-09-20 21:31:20 +0200287 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
Francois Romieu07ce4062007-02-23 23:36:39 +0100288 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200289 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
Francois Romieu2a35cfa2012-08-31 23:06:17 +0200290 { PCI_VENDOR_ID_DLINK, 0x4300,
291 PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200292 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
Lennart Sorensen93a3aa22011-07-28 13:18:11 +0000293 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 },
Francois Romieubc1660b2007-10-12 23:58:09 +0200294 { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200295 { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
296 { PCI_VENDOR_ID_LINKSYS, 0x1032,
297 PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
Ciaran McCreesh11d2e282007-11-01 22:48:15 +0100298 { 0x0001, 0x8168,
299 PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 {0,},
301};
302
303MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
304
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000305static int rx_buf_sz = 16383;
David S. Miller4300e8c2010-03-26 10:23:30 -0700306static int use_dac;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200307static struct {
308 u32 msg_enable;
309} debug = { -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Francois Romieu07d3f512007-02-21 22:40:46 +0100311enum rtl_registers {
312 MAC0 = 0, /* Ethernet hardware address. */
Francois Romieu773d2022007-01-31 23:47:43 +0100313 MAC4 = 4,
Francois Romieu07d3f512007-02-21 22:40:46 +0100314 MAR0 = 8, /* Multicast filter. */
315 CounterAddrLow = 0x10,
316 CounterAddrHigh = 0x14,
317 TxDescStartAddrLow = 0x20,
318 TxDescStartAddrHigh = 0x24,
319 TxHDescStartAddrLow = 0x28,
320 TxHDescStartAddrHigh = 0x2c,
321 FLASH = 0x30,
322 ERSR = 0x36,
323 ChipCmd = 0x37,
324 TxPoll = 0x38,
325 IntrMask = 0x3c,
326 IntrStatus = 0x3e,
Francois Romieu2b7b4312011-04-18 22:53:24 -0700327
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800328 TxConfig = 0x40,
329#define TXCFG_AUTO_FIFO (1 << 7) /* 8111e-vl */
330#define TXCFG_EMPTY (1 << 11) /* 8111e-vl */
331
332 RxConfig = 0x44,
333#define RX128_INT_EN (1 << 15) /* 8111c and later */
334#define RX_MULTI_EN (1 << 14) /* 8111c only */
335#define RXCFG_FIFO_SHIFT 13
336 /* No threshold before first PCI xfer */
337#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
338#define RXCFG_DMA_SHIFT 8
339 /* Unlimited maximum PCI burst. */
340#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
Francois Romieu2b7b4312011-04-18 22:53:24 -0700341
Francois Romieu07d3f512007-02-21 22:40:46 +0100342 RxMissed = 0x4c,
343 Cfg9346 = 0x50,
344 Config0 = 0x51,
345 Config1 = 0x52,
346 Config2 = 0x53,
Francois Romieud387b422012-04-17 11:12:01 +0200347#define PME_SIGNAL (1 << 5) /* 8168c and later */
348
Francois Romieu07d3f512007-02-21 22:40:46 +0100349 Config3 = 0x54,
350 Config4 = 0x55,
351 Config5 = 0x56,
352 MultiIntr = 0x5c,
353 PHYAR = 0x60,
Francois Romieu07d3f512007-02-21 22:40:46 +0100354 PHYstatus = 0x6c,
355 RxMaxSize = 0xda,
356 CPlusCmd = 0xe0,
357 IntrMitigate = 0xe2,
358 RxDescAddrLow = 0xe4,
359 RxDescAddrHigh = 0xe8,
françois romieuf0298f82011-01-03 15:07:42 +0000360 EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
361
362#define NoEarlyTx 0x3f /* Max value : no early transmit. */
363
364 MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
365
366#define TxPacketMax (8064 >> 7)
Hayes Wang3090bd92011-09-06 16:55:15 +0800367#define EarlySize 0x27
françois romieuf0298f82011-01-03 15:07:42 +0000368
Francois Romieu07d3f512007-02-21 22:40:46 +0100369 FuncEvent = 0xf0,
370 FuncEventMask = 0xf4,
371 FuncPresetState = 0xf8,
372 FuncForceEvent = 0xfc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373};
374
Francois Romieuf162a5d2008-06-01 22:37:49 +0200375enum rtl8110_registers {
376 TBICSR = 0x64,
377 TBI_ANAR = 0x68,
378 TBI_LPAR = 0x6a,
379};
380
381enum rtl8168_8101_registers {
382 CSIDR = 0x64,
383 CSIAR = 0x68,
384#define CSIAR_FLAG 0x80000000
385#define CSIAR_WRITE_CMD 0x80000000
386#define CSIAR_BYTE_ENABLE 0x0f
387#define CSIAR_BYTE_ENABLE_SHIFT 12
388#define CSIAR_ADDR_MASK 0x0fff
Hayes Wang7e18dca2012-03-30 14:33:02 +0800389#define CSIAR_FUNC_CARD 0x00000000
390#define CSIAR_FUNC_SDIO 0x00010000
391#define CSIAR_FUNC_NIC 0x00020000
françois romieu065c27c2011-01-03 15:08:12 +0000392 PMCH = 0x6f,
Francois Romieuf162a5d2008-06-01 22:37:49 +0200393 EPHYAR = 0x80,
394#define EPHYAR_FLAG 0x80000000
395#define EPHYAR_WRITE_CMD 0x80000000
396#define EPHYAR_REG_MASK 0x1f
397#define EPHYAR_REG_SHIFT 16
398#define EPHYAR_DATA_MASK 0xffff
Hayes Wang5a5e4442011-02-22 17:26:21 +0800399 DLLPR = 0xd0,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800400#define PFM_EN (1 << 6)
Francois Romieuf162a5d2008-06-01 22:37:49 +0200401 DBG_REG = 0xd1,
402#define FIX_NAK_1 (1 << 4)
403#define FIX_NAK_2 (1 << 3)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800404 TWSI = 0xd2,
405 MCU = 0xd3,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800406#define NOW_IS_OOB (1 << 7)
Hayes Wangc5583862012-07-02 17:23:22 +0800407#define TX_EMPTY (1 << 5)
408#define RX_EMPTY (1 << 4)
409#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800410#define EN_NDP (1 << 3)
411#define EN_OOB_RESET (1 << 2)
Hayes Wangc5583862012-07-02 17:23:22 +0800412#define LINK_LIST_RDY (1 << 1)
françois romieudaf9df62009-10-07 12:44:20 +0000413 EFUSEAR = 0xdc,
414#define EFUSEAR_FLAG 0x80000000
415#define EFUSEAR_WRITE_CMD 0x80000000
416#define EFUSEAR_READ_CMD 0x00000000
417#define EFUSEAR_REG_MASK 0x03ff
418#define EFUSEAR_REG_SHIFT 8
419#define EFUSEAR_DATA_MASK 0xff
Francois Romieuf162a5d2008-06-01 22:37:49 +0200420};
421
françois romieuc0e45c12011-01-03 15:08:04 +0000422enum rtl8168_registers {
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800423 LED_FREQ = 0x1a,
424 EEE_LED = 0x1b,
françois romieub646d902011-01-03 15:08:21 +0000425 ERIDR = 0x70,
426 ERIAR = 0x74,
427#define ERIAR_FLAG 0x80000000
428#define ERIAR_WRITE_CMD 0x80000000
429#define ERIAR_READ_CMD 0x00000000
430#define ERIAR_ADDR_BYTE_ALIGN 4
françois romieub646d902011-01-03 15:08:21 +0000431#define ERIAR_TYPE_SHIFT 16
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800432#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT)
433#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT)
434#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT)
435#define ERIAR_MASK_SHIFT 12
436#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT)
437#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT)
Hayes Wangc5583862012-07-02 17:23:22 +0800438#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT)
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800439#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT)
françois romieuc0e45c12011-01-03 15:08:04 +0000440 EPHY_RXER_NUM = 0x7c,
441 OCPDR = 0xb0, /* OCP GPHY access */
442#define OCPDR_WRITE_CMD 0x80000000
443#define OCPDR_READ_CMD 0x00000000
444#define OCPDR_REG_MASK 0x7f
445#define OCPDR_GPHY_REG_SHIFT 16
446#define OCPDR_DATA_MASK 0xffff
447 OCPAR = 0xb4,
448#define OCPAR_FLAG 0x80000000
449#define OCPAR_GPHY_WRITE_CMD 0x8000f060
450#define OCPAR_GPHY_READ_CMD 0x0000f060
Hayes Wangc5583862012-07-02 17:23:22 +0800451 GPHY_OCP = 0xb8,
hayeswang01dc7fe2011-03-21 01:50:28 +0000452 RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */
453 MISC = 0xf0, /* 8168e only. */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200454#define TXPLA_RST (1 << 29)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800455#define DISABLE_LAN_EN (1 << 23) /* Enable GPIO pin */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800456#define PWM_EN (1 << 22)
Hayes Wangc5583862012-07-02 17:23:22 +0800457#define RXDV_GATED_EN (1 << 19)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800458#define EARLY_TALLY_EN (1 << 16)
françois romieuc0e45c12011-01-03 15:08:04 +0000459};
460
Francois Romieu07d3f512007-02-21 22:40:46 +0100461enum rtl_register_content {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /* InterruptStatusBits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100463 SYSErr = 0x8000,
464 PCSTimeout = 0x4000,
465 SWInt = 0x0100,
466 TxDescUnavail = 0x0080,
467 RxFIFOOver = 0x0040,
468 LinkChg = 0x0020,
469 RxOverflow = 0x0010,
470 TxErr = 0x0008,
471 TxOK = 0x0004,
472 RxErr = 0x0002,
473 RxOK = 0x0001,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 /* RxStatusDesc */
David S. Miller8decf862011-09-22 03:23:13 -0400476 RxBOVF = (1 << 24),
Francois Romieu9dccf612006-05-14 12:31:17 +0200477 RxFOVF = (1 << 23),
478 RxRWT = (1 << 22),
479 RxRES = (1 << 21),
480 RxRUNT = (1 << 20),
481 RxCRC = (1 << 19),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 /* ChipCmdBits */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800484 StopReq = 0x80,
Francois Romieu07d3f512007-02-21 22:40:46 +0100485 CmdReset = 0x10,
486 CmdRxEnb = 0x08,
487 CmdTxEnb = 0x04,
488 RxBufEmpty = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Francois Romieu275391a2007-02-23 23:50:28 +0100490 /* TXPoll register p.5 */
491 HPQ = 0x80, /* Poll cmd on the high prio queue */
492 NPQ = 0x40, /* Poll cmd on the low prio queue */
493 FSWInt = 0x01, /* Forced software interrupt */
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 /* Cfg9346Bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100496 Cfg9346_Lock = 0x00,
497 Cfg9346_Unlock = 0xc0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 /* rx_mode_bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100500 AcceptErr = 0x20,
501 AcceptRunt = 0x10,
502 AcceptBroadcast = 0x08,
503 AcceptMulticast = 0x04,
504 AcceptMyPhys = 0x02,
505 AcceptAllPhys = 0x01,
Francois Romieu1687b562011-07-19 17:21:29 +0200506#define RX_CONFIG_ACCEPT_MASK 0x3f
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /* TxConfigBits */
509 TxInterFrameGapShift = 24,
510 TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
511
Francois Romieu5d06a992006-02-23 00:47:58 +0100512 /* Config1 register p.24 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200513 LEDS1 = (1 << 7),
514 LEDS0 = (1 << 6),
Francois Romieuf162a5d2008-06-01 22:37:49 +0200515 Speed_down = (1 << 4),
516 MEMMAP = (1 << 3),
517 IOMAP = (1 << 2),
518 VPD = (1 << 1),
Francois Romieu5d06a992006-02-23 00:47:58 +0100519 PMEnable = (1 << 0), /* Power Management Enable */
520
Francois Romieu6dccd162007-02-13 23:38:05 +0100521 /* Config2 register p. 25 */
françois romieu2ca6cf02011-12-15 08:37:43 +0000522 MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
Francois Romieu6dccd162007-02-13 23:38:05 +0100523 PCI_Clock_66MHz = 0x01,
524 PCI_Clock_33MHz = 0x00,
525
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100526 /* Config3 register p.25 */
527 MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
528 LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
Francois Romieud58d46b2011-05-03 16:38:29 +0200529 Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200530 Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100531
Francois Romieud58d46b2011-05-03 16:38:29 +0200532 /* Config4 register */
533 Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */
534
Francois Romieu5d06a992006-02-23 00:47:58 +0100535 /* Config5 register p.27 */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100536 BWF = (1 << 6), /* Accept Broadcast wakeup frame */
537 MWF = (1 << 5), /* Accept Multicast wakeup frame */
538 UWF = (1 << 4), /* Accept Unicast wakeup frame */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200539 Spi_en = (1 << 3),
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100540 LanWake = (1 << 1), /* LanWake enable/disable */
Francois Romieu5d06a992006-02-23 00:47:58 +0100541 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 /* TBICSR p.28 */
544 TBIReset = 0x80000000,
545 TBILoopback = 0x40000000,
546 TBINwEnable = 0x20000000,
547 TBINwRestart = 0x10000000,
548 TBILinkOk = 0x02000000,
549 TBINwComplete = 0x01000000,
550
551 /* CPlusCmd p.31 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200552 EnableBist = (1 << 15), // 8168 8101
553 Mac_dbgo_oe = (1 << 14), // 8168 8101
554 Normal_mode = (1 << 13), // unused
555 Force_half_dup = (1 << 12), // 8168 8101
556 Force_rxflow_en = (1 << 11), // 8168 8101
557 Force_txflow_en = (1 << 10), // 8168 8101
558 Cxpl_dbg_sel = (1 << 9), // 8168 8101
559 ASF = (1 << 8), // 8168 8101
560 PktCntrDisable = (1 << 7), // 8168 8101
561 Mac_dbgo_sel = 0x001c, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 RxVlan = (1 << 6),
563 RxChkSum = (1 << 5),
564 PCIDAC = (1 << 4),
565 PCIMulRW = (1 << 3),
Francois Romieu0e485152007-02-20 00:00:26 +0100566 INTT_0 = 0x0000, // 8168
567 INTT_1 = 0x0001, // 8168
568 INTT_2 = 0x0002, // 8168
569 INTT_3 = 0x0003, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* rtl8169_PHYstatus */
Francois Romieu07d3f512007-02-21 22:40:46 +0100572 TBI_Enable = 0x80,
573 TxFlowCtrl = 0x40,
574 RxFlowCtrl = 0x20,
575 _1000bpsF = 0x10,
576 _100bps = 0x08,
577 _10bps = 0x04,
578 LinkStatus = 0x02,
579 FullDup = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 /* _TBICSRBit */
Francois Romieu07d3f512007-02-21 22:40:46 +0100582 TBILinkOK = 0x02000000,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +0200583
584 /* DumpCounterCommand */
Francois Romieu07d3f512007-02-21 22:40:46 +0100585 CounterDump = 0x8,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586};
587
Francois Romieu2b7b4312011-04-18 22:53:24 -0700588enum rtl_desc_bit {
589 /* First doubleword. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 DescOwn = (1 << 31), /* Descriptor is owned by NIC */
591 RingEnd = (1 << 30), /* End of descriptor ring */
592 FirstFrag = (1 << 29), /* First segment of a packet */
593 LastFrag = (1 << 28), /* Final segment of a packet */
Francois Romieu2b7b4312011-04-18 22:53:24 -0700594};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Francois Romieu2b7b4312011-04-18 22:53:24 -0700596/* Generic case. */
597enum rtl_tx_desc_bit {
598 /* First doubleword. */
599 TD_LSO = (1 << 27), /* Large Send Offload */
600#define TD_MSS_MAX 0x07ffu /* MSS value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Francois Romieu2b7b4312011-04-18 22:53:24 -0700602 /* Second doubleword. */
603 TxVlanTag = (1 << 17), /* Add VLAN tag */
604};
605
606/* 8169, 8168b and 810x except 8102e. */
607enum rtl_tx_desc_bit_0 {
608 /* First doubleword. */
609#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */
610 TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */
611 TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */
612 TD0_IP_CS = (1 << 18), /* Calculate IP checksum */
613};
614
615/* 8102e, 8168c and beyond. */
616enum rtl_tx_desc_bit_1 {
617 /* Second doubleword. */
618#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */
619 TD1_IP_CS = (1 << 29), /* Calculate IP checksum */
620 TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */
621 TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */
622};
623
624static const struct rtl_tx_desc_info {
625 struct {
626 u32 udp;
627 u32 tcp;
628 } checksum;
629 u16 mss_shift;
630 u16 opts_offset;
631} tx_desc_info [] = {
632 [RTL_TD_0] = {
633 .checksum = {
634 .udp = TD0_IP_CS | TD0_UDP_CS,
635 .tcp = TD0_IP_CS | TD0_TCP_CS
636 },
637 .mss_shift = TD0_MSS_SHIFT,
638 .opts_offset = 0
639 },
640 [RTL_TD_1] = {
641 .checksum = {
642 .udp = TD1_IP_CS | TD1_UDP_CS,
643 .tcp = TD1_IP_CS | TD1_TCP_CS
644 },
645 .mss_shift = TD1_MSS_SHIFT,
646 .opts_offset = 1
647 }
648};
649
650enum rtl_rx_desc_bit {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 /* Rx private */
652 PID1 = (1 << 18), /* Protocol ID bit 1/2 */
653 PID0 = (1 << 17), /* Protocol ID bit 2/2 */
654
655#define RxProtoUDP (PID1)
656#define RxProtoTCP (PID0)
657#define RxProtoIP (PID1 | PID0)
658#define RxProtoMask RxProtoIP
659
660 IPFail = (1 << 16), /* IP checksum failed */
661 UDPFail = (1 << 15), /* UDP/IP checksum failed */
662 TCPFail = (1 << 14), /* TCP/IP checksum failed */
663 RxVlanTag = (1 << 16), /* VLAN tag available */
664};
665
666#define RsvdMask 0x3fffc000
667
668struct TxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200669 __le32 opts1;
670 __le32 opts2;
671 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672};
673
674struct RxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200675 __le32 opts1;
676 __le32 opts2;
677 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678};
679
680struct ring_info {
681 struct sk_buff *skb;
682 u32 len;
683 u8 __pad[sizeof(void *) - sizeof(u32)];
684};
685
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200686enum features {
Francois Romieuccdffb92008-07-26 14:26:06 +0200687 RTL_FEATURE_WOL = (1 << 0),
688 RTL_FEATURE_MSI = (1 << 1),
689 RTL_FEATURE_GMII = (1 << 2),
hayeswange0c07552012-10-23 20:24:03 +0000690 RTL_FEATURE_FW_LOADED = (1 << 3),
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200691};
692
Ivan Vecera355423d2009-02-06 21:49:57 -0800693struct rtl8169_counters {
694 __le64 tx_packets;
695 __le64 rx_packets;
696 __le64 tx_errors;
697 __le32 rx_errors;
698 __le16 rx_missed;
699 __le16 align_errors;
700 __le32 tx_one_collision;
701 __le32 tx_multi_collision;
702 __le64 rx_unicast;
703 __le64 rx_broadcast;
704 __le32 rx_multicast;
705 __le16 tx_aborted;
706 __le16 tx_underun;
707};
708
Francois Romieuda78dbf2012-01-26 14:18:23 +0100709enum rtl_flag {
Francois Romieu6c4a70c2012-01-31 10:56:44 +0100710 RTL_FLAG_TASK_ENABLED,
Francois Romieuda78dbf2012-01-26 14:18:23 +0100711 RTL_FLAG_TASK_SLOW_PENDING,
712 RTL_FLAG_TASK_RESET_PENDING,
713 RTL_FLAG_TASK_PHY_PENDING,
714 RTL_FLAG_MAX
715};
716
Junchang Wang8027aa22012-03-04 23:30:32 +0100717struct rtl8169_stats {
718 u64 packets;
719 u64 bytes;
720 struct u64_stats_sync syncp;
721};
722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723struct rtl8169_private {
724 void __iomem *mmio_addr; /* memory map physical address */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200725 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000726 struct net_device *dev;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700727 struct napi_struct napi;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200728 u32 msg_enable;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700729 u16 txd_version;
730 u16 mac_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
732 u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
733 u32 dirty_rx;
734 u32 dirty_tx;
Junchang Wang8027aa22012-03-04 23:30:32 +0100735 struct rtl8169_stats rx_stats;
736 struct rtl8169_stats tx_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
738 struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
739 dma_addr_t TxPhyAddr;
740 dma_addr_t RxPhyAddr;
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000741 void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 struct timer_list timer;
744 u16 cp_cmd;
Francois Romieuda78dbf2012-01-26 14:18:23 +0100745
746 u16 event_slow;
françois romieuc0e45c12011-01-03 15:08:04 +0000747
748 struct mdio_ops {
Francois Romieu24192212012-07-06 20:19:42 +0200749 void (*write)(struct rtl8169_private *, int, int);
750 int (*read)(struct rtl8169_private *, int);
françois romieuc0e45c12011-01-03 15:08:04 +0000751 } mdio_ops;
752
françois romieu065c27c2011-01-03 15:08:12 +0000753 struct pll_power_ops {
754 void (*down)(struct rtl8169_private *);
755 void (*up)(struct rtl8169_private *);
756 } pll_power_ops;
757
Francois Romieud58d46b2011-05-03 16:38:29 +0200758 struct jumbo_ops {
759 void (*enable)(struct rtl8169_private *);
760 void (*disable)(struct rtl8169_private *);
761 } jumbo_ops;
762
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800763 struct csi_ops {
Francois Romieu52989f02012-07-06 13:37:00 +0200764 void (*write)(struct rtl8169_private *, int, int);
765 u32 (*read)(struct rtl8169_private *, int);
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800766 } csi_ops;
767
Oliver Neukum54405cd2011-01-06 21:55:13 +0100768 int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
Francois Romieuccdffb92008-07-26 14:26:06 +0200769 int (*get_settings)(struct net_device *, struct ethtool_cmd *);
françois romieu4da19632011-01-03 15:07:55 +0000770 void (*phy_reset_enable)(struct rtl8169_private *tp);
Francois Romieu07ce4062007-02-23 23:36:39 +0100771 void (*hw_start)(struct net_device *);
françois romieu4da19632011-01-03 15:07:55 +0000772 unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 unsigned int (*link_ok)(void __iomem *);
Francois Romieu8b4ab282008-11-19 22:05:25 -0800774 int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
Francois Romieu4422bcd2012-01-26 11:23:32 +0100775
776 struct {
Francois Romieuda78dbf2012-01-26 14:18:23 +0100777 DECLARE_BITMAP(flags, RTL_FLAG_MAX);
778 struct mutex mutex;
Francois Romieu4422bcd2012-01-26 11:23:32 +0100779 struct work_struct work;
780 } wk;
781
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200782 unsigned features;
Francois Romieuccdffb92008-07-26 14:26:06 +0200783
784 struct mii_if_info mii;
Ivan Vecera355423d2009-02-06 21:49:57 -0800785 struct rtl8169_counters counters;
Rafael J. Wysockie1759442010-03-14 14:33:51 +0000786 u32 saved_wolopts;
David S. Miller8decf862011-09-22 03:23:13 -0400787 u32 opts1_mask;
françois romieuf1e02ed2011-01-13 13:07:53 +0000788
Francois Romieub6ffd972011-06-17 17:00:05 +0200789 struct rtl_fw {
790 const struct firmware *fw;
Francois Romieu1c361ef2011-06-17 17:16:24 +0200791
792#define RTL_VER_SIZE 32
793
794 char version[RTL_VER_SIZE];
795
796 struct rtl_fw_phy_action {
797 __le32 *code;
798 size_t size;
799 } phy_action;
Francois Romieub6ffd972011-06-17 17:00:05 +0200800 } *rtl_fw;
Phil Carmody497888c2011-07-14 15:07:13 +0300801#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
Hayes Wangc5583862012-07-02 17:23:22 +0800802
803 u32 ocp_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804};
805
Ralf Baechle979b6c12005-06-13 14:30:40 -0700806MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808module_param(use_dac, int, 0);
David S. Miller4300e8c2010-03-26 10:23:30 -0700809MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200810module_param_named(debug, debug.msg_enable, int, 0);
811MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812MODULE_LICENSE("GPL");
813MODULE_VERSION(RTL8169_VERSION);
françois romieubca03d52011-01-03 15:07:31 +0000814MODULE_FIRMWARE(FIRMWARE_8168D_1);
815MODULE_FIRMWARE(FIRMWARE_8168D_2);
hayeswang01dc7fe2011-03-21 01:50:28 +0000816MODULE_FIRMWARE(FIRMWARE_8168E_1);
817MODULE_FIRMWARE(FIRMWARE_8168E_2);
David S. Miller8decf862011-09-22 03:23:13 -0400818MODULE_FIRMWARE(FIRMWARE_8168E_3);
Hayes Wang5a5e4442011-02-22 17:26:21 +0800819MODULE_FIRMWARE(FIRMWARE_8105E_1);
Hayes Wangc2218922011-09-06 16:55:18 +0800820MODULE_FIRMWARE(FIRMWARE_8168F_1);
821MODULE_FIRMWARE(FIRMWARE_8168F_2);
Hayes Wang7e18dca2012-03-30 14:33:02 +0800822MODULE_FIRMWARE(FIRMWARE_8402_1);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800823MODULE_FIRMWARE(FIRMWARE_8411_1);
Hayes Wang5598bfe2012-07-02 17:23:21 +0800824MODULE_FIRMWARE(FIRMWARE_8106E_1);
Hayes Wangc5583862012-07-02 17:23:22 +0800825MODULE_FIRMWARE(FIRMWARE_8168G_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Francois Romieuda78dbf2012-01-26 14:18:23 +0100827static void rtl_lock_work(struct rtl8169_private *tp)
828{
829 mutex_lock(&tp->wk.mutex);
830}
831
832static void rtl_unlock_work(struct rtl8169_private *tp)
833{
834 mutex_unlock(&tp->wk.mutex);
835}
836
Francois Romieud58d46b2011-05-03 16:38:29 +0200837static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
838{
Jiang Liu7d7903b2012-07-24 17:20:16 +0800839 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
840 PCI_EXP_DEVCTL_READRQ, force);
Francois Romieud58d46b2011-05-03 16:38:29 +0200841}
842
Francois Romieuffc46952012-07-06 14:19:23 +0200843struct rtl_cond {
844 bool (*check)(struct rtl8169_private *);
845 const char *msg;
846};
847
848static void rtl_udelay(unsigned int d)
849{
850 udelay(d);
851}
852
853static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
854 void (*delay)(unsigned int), unsigned int d, int n,
855 bool high)
856{
857 int i;
858
859 for (i = 0; i < n; i++) {
860 delay(d);
861 if (c->check(tp) == high)
862 return true;
863 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200864 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
865 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200866 return false;
867}
868
869static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
870 const struct rtl_cond *c,
871 unsigned int d, int n)
872{
873 return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
874}
875
876static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
877 const struct rtl_cond *c,
878 unsigned int d, int n)
879{
880 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
881}
882
883static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
884 const struct rtl_cond *c,
885 unsigned int d, int n)
886{
887 return rtl_loop_wait(tp, c, msleep, d, n, true);
888}
889
890static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
891 const struct rtl_cond *c,
892 unsigned int d, int n)
893{
894 return rtl_loop_wait(tp, c, msleep, d, n, false);
895}
896
897#define DECLARE_RTL_COND(name) \
898static bool name ## _check(struct rtl8169_private *); \
899 \
900static const struct rtl_cond name = { \
901 .check = name ## _check, \
902 .msg = #name \
903}; \
904 \
905static bool name ## _check(struct rtl8169_private *tp)
906
907DECLARE_RTL_COND(rtl_ocpar_cond)
908{
909 void __iomem *ioaddr = tp->mmio_addr;
910
911 return RTL_R32(OCPAR) & OCPAR_FLAG;
912}
913
françois romieub646d902011-01-03 15:08:21 +0000914static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
915{
916 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000917
918 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200919
920 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
921 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000922}
923
924static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
925{
926 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000927
928 RTL_W32(OCPDR, data);
929 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200930
931 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
932}
933
934DECLARE_RTL_COND(rtl_eriar_cond)
935{
936 void __iomem *ioaddr = tp->mmio_addr;
937
938 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000939}
940
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800941static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000942{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800943 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000944
945 RTL_W8(ERIDR, cmd);
946 RTL_W32(ERIAR, 0x800010e8);
947 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200948
949 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
950 return;
françois romieub646d902011-01-03 15:08:21 +0000951
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800952 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000953}
954
955#define OOB_CMD_RESET 0x00
956#define OOB_CMD_DRIVER_START 0x05
957#define OOB_CMD_DRIVER_STOP 0x06
958
Francois Romieucecb5fd2011-04-01 10:21:07 +0200959static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
960{
961 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
962}
963
Francois Romieuffc46952012-07-06 14:19:23 +0200964DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000965{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200966 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000967
Francois Romieucecb5fd2011-04-01 10:21:07 +0200968 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000969
Francois Romieuffc46952012-07-06 14:19:23 +0200970 return ocp_read(tp, 0x0f, reg) & 0x00000800;
971}
972
973static void rtl8168_driver_start(struct rtl8169_private *tp)
974{
975 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
976
977 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000978}
979
980static void rtl8168_driver_stop(struct rtl8169_private *tp)
981{
françois romieub646d902011-01-03 15:08:21 +0000982 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
983
Francois Romieuffc46952012-07-06 14:19:23 +0200984 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000985}
986
hayeswang4804b3b2011-03-21 01:50:29 +0000987static int r8168dp_check_dash(struct rtl8169_private *tp)
988{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200989 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000990
Francois Romieucecb5fd2011-04-01 10:21:07 +0200991 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000992}
françois romieub646d902011-01-03 15:08:21 +0000993
Hayes Wangc5583862012-07-02 17:23:22 +0800994static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
995{
996 if (reg & 0xffff0001) {
997 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
998 return true;
999 }
1000 return false;
1001}
1002
1003DECLARE_RTL_COND(rtl_ocp_gphy_cond)
1004{
1005 void __iomem *ioaddr = tp->mmio_addr;
1006
1007 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1008}
1009
1010static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1011{
1012 void __iomem *ioaddr = tp->mmio_addr;
1013
1014 if (rtl_ocp_reg_failure(tp, reg))
1015 return;
1016
1017 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1018
1019 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1020}
1021
1022static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1023{
1024 void __iomem *ioaddr = tp->mmio_addr;
1025
1026 if (rtl_ocp_reg_failure(tp, reg))
1027 return 0;
1028
1029 RTL_W32(GPHY_OCP, reg << 15);
1030
1031 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1032 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1033}
1034
1035static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1036{
1037 int val;
1038
1039 val = r8168_phy_ocp_read(tp, reg);
1040 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1041}
1042
Hayes Wangc5583862012-07-02 17:23:22 +08001043static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1044{
1045 void __iomem *ioaddr = tp->mmio_addr;
1046
1047 if (rtl_ocp_reg_failure(tp, reg))
1048 return;
1049
1050 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001051}
1052
1053static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1054{
1055 void __iomem *ioaddr = tp->mmio_addr;
1056
1057 if (rtl_ocp_reg_failure(tp, reg))
1058 return 0;
1059
1060 RTL_W32(OCPDR, reg << 15);
1061
Hayes Wang3a83ad12012-07-11 20:31:56 +08001062 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001063}
1064
1065#define OCP_STD_PHY_BASE 0xa400
1066
1067static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1068{
1069 if (reg == 0x1f) {
1070 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1071 return;
1072 }
1073
1074 if (tp->ocp_base != OCP_STD_PHY_BASE)
1075 reg -= 0x10;
1076
1077 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1078}
1079
1080static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1081{
1082 if (tp->ocp_base != OCP_STD_PHY_BASE)
1083 reg -= 0x10;
1084
1085 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1086}
1087
Francois Romieuffc46952012-07-06 14:19:23 +02001088DECLARE_RTL_COND(rtl_phyar_cond)
1089{
1090 void __iomem *ioaddr = tp->mmio_addr;
1091
1092 return RTL_R32(PHYAR) & 0x80000000;
1093}
1094
Francois Romieu24192212012-07-06 20:19:42 +02001095static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Francois Romieu24192212012-07-06 20:19:42 +02001097 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Francois Romieu24192212012-07-06 20:19:42 +02001099 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Francois Romieuffc46952012-07-06 14:19:23 +02001101 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001102 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001103 * According to hardware specs a 20us delay is required after write
1104 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001105 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001106 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107}
1108
Francois Romieu24192212012-07-06 20:19:42 +02001109static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
Francois Romieu24192212012-07-06 20:19:42 +02001111 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001112 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Francois Romieu24192212012-07-06 20:19:42 +02001114 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Francois Romieuffc46952012-07-06 14:19:23 +02001116 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1117 RTL_R32(PHYAR) & 0xffff : ~0;
1118
Timo Teräs81a95f02010-06-09 17:31:48 -07001119 /*
1120 * According to hardware specs a 20us delay is required after read
1121 * complete indication, but before sending next command.
1122 */
1123 udelay(20);
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 return value;
1126}
1127
Francois Romieu24192212012-07-06 20:19:42 +02001128static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001129{
Francois Romieu24192212012-07-06 20:19:42 +02001130 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001131
Francois Romieu24192212012-07-06 20:19:42 +02001132 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001133 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1134 RTL_W32(EPHY_RXER_NUM, 0);
1135
Francois Romieuffc46952012-07-06 14:19:23 +02001136 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001137}
1138
Francois Romieu24192212012-07-06 20:19:42 +02001139static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001140{
Francois Romieu24192212012-07-06 20:19:42 +02001141 r8168dp_1_mdio_access(tp, reg,
1142 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001143}
1144
Francois Romieu24192212012-07-06 20:19:42 +02001145static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001146{
Francois Romieu24192212012-07-06 20:19:42 +02001147 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001148
Francois Romieu24192212012-07-06 20:19:42 +02001149 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001150
1151 mdelay(1);
1152 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1153 RTL_W32(EPHY_RXER_NUM, 0);
1154
Francois Romieuffc46952012-07-06 14:19:23 +02001155 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1156 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001157}
1158
françois romieue6de30d2011-01-03 15:08:37 +00001159#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1160
1161static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1162{
1163 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1164}
1165
1166static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1167{
1168 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1169}
1170
Francois Romieu24192212012-07-06 20:19:42 +02001171static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001172{
Francois Romieu24192212012-07-06 20:19:42 +02001173 void __iomem *ioaddr = tp->mmio_addr;
1174
françois romieue6de30d2011-01-03 15:08:37 +00001175 r8168dp_2_mdio_start(ioaddr);
1176
Francois Romieu24192212012-07-06 20:19:42 +02001177 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001178
1179 r8168dp_2_mdio_stop(ioaddr);
1180}
1181
Francois Romieu24192212012-07-06 20:19:42 +02001182static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001183{
Francois Romieu24192212012-07-06 20:19:42 +02001184 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001185 int value;
1186
1187 r8168dp_2_mdio_start(ioaddr);
1188
Francois Romieu24192212012-07-06 20:19:42 +02001189 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001190
1191 r8168dp_2_mdio_stop(ioaddr);
1192
1193 return value;
1194}
1195
françois romieu4da19632011-01-03 15:07:55 +00001196static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001197{
Francois Romieu24192212012-07-06 20:19:42 +02001198 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001199}
1200
françois romieu4da19632011-01-03 15:07:55 +00001201static int rtl_readphy(struct rtl8169_private *tp, int location)
1202{
Francois Romieu24192212012-07-06 20:19:42 +02001203 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001204}
1205
1206static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1207{
1208 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1209}
1210
1211static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001212{
1213 int val;
1214
françois romieu4da19632011-01-03 15:07:55 +00001215 val = rtl_readphy(tp, reg_addr);
1216 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001217}
1218
Francois Romieuccdffb92008-07-26 14:26:06 +02001219static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1220 int val)
1221{
1222 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001223
françois romieu4da19632011-01-03 15:07:55 +00001224 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001225}
1226
1227static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1228{
1229 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001230
françois romieu4da19632011-01-03 15:07:55 +00001231 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001232}
1233
Francois Romieuffc46952012-07-06 14:19:23 +02001234DECLARE_RTL_COND(rtl_ephyar_cond)
1235{
1236 void __iomem *ioaddr = tp->mmio_addr;
1237
1238 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1239}
1240
Francois Romieufdf6fc02012-07-06 22:40:38 +02001241static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001242{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001243 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001244
1245 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1246 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1247
Francois Romieuffc46952012-07-06 14:19:23 +02001248 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1249
1250 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001251}
1252
Francois Romieufdf6fc02012-07-06 22:40:38 +02001253static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001254{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001255 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001256
1257 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1258
Francois Romieuffc46952012-07-06 14:19:23 +02001259 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1260 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001261}
1262
Francois Romieufdf6fc02012-07-06 22:40:38 +02001263static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1264 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001265{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001266 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001267
1268 BUG_ON((addr & 3) || (mask == 0));
1269 RTL_W32(ERIDR, val);
1270 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1271
Francois Romieuffc46952012-07-06 14:19:23 +02001272 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001273}
1274
Francois Romieufdf6fc02012-07-06 22:40:38 +02001275static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001276{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001277 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001278
1279 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1280
Francois Romieuffc46952012-07-06 14:19:23 +02001281 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1282 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001283}
1284
Francois Romieufdf6fc02012-07-06 22:40:38 +02001285static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1286 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001287{
1288 u32 val;
1289
Francois Romieufdf6fc02012-07-06 22:40:38 +02001290 val = rtl_eri_read(tp, addr, type);
1291 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001292}
1293
françois romieuc28aa382011-08-02 03:53:43 +00001294struct exgmac_reg {
1295 u16 addr;
1296 u16 mask;
1297 u32 val;
1298};
1299
Francois Romieufdf6fc02012-07-06 22:40:38 +02001300static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001301 const struct exgmac_reg *r, int len)
1302{
1303 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001304 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001305 r++;
1306 }
1307}
1308
Francois Romieuffc46952012-07-06 14:19:23 +02001309DECLARE_RTL_COND(rtl_efusear_cond)
1310{
1311 void __iomem *ioaddr = tp->mmio_addr;
1312
1313 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1314}
1315
Francois Romieufdf6fc02012-07-06 22:40:38 +02001316static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001317{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001318 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001319
1320 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1321
Francois Romieuffc46952012-07-06 14:19:23 +02001322 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1323 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001324}
1325
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001326static u16 rtl_get_events(struct rtl8169_private *tp)
1327{
1328 void __iomem *ioaddr = tp->mmio_addr;
1329
1330 return RTL_R16(IntrStatus);
1331}
1332
1333static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1334{
1335 void __iomem *ioaddr = tp->mmio_addr;
1336
1337 RTL_W16(IntrStatus, bits);
1338 mmiowb();
1339}
1340
1341static void rtl_irq_disable(struct rtl8169_private *tp)
1342{
1343 void __iomem *ioaddr = tp->mmio_addr;
1344
1345 RTL_W16(IntrMask, 0);
1346 mmiowb();
1347}
1348
Francois Romieu3e990ff2012-01-26 12:50:01 +01001349static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1350{
1351 void __iomem *ioaddr = tp->mmio_addr;
1352
1353 RTL_W16(IntrMask, bits);
1354}
1355
Francois Romieuda78dbf2012-01-26 14:18:23 +01001356#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1357#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1358#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1359
1360static void rtl_irq_enable_all(struct rtl8169_private *tp)
1361{
1362 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1363}
1364
françois romieu811fd302011-12-04 20:30:45 +00001365static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366{
françois romieu811fd302011-12-04 20:30:45 +00001367 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001369 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001370 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001371 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372}
1373
françois romieu4da19632011-01-03 15:07:55 +00001374static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
françois romieu4da19632011-01-03 15:07:55 +00001376 void __iomem *ioaddr = tp->mmio_addr;
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return RTL_R32(TBICSR) & TBIReset;
1379}
1380
françois romieu4da19632011-01-03 15:07:55 +00001381static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
françois romieu4da19632011-01-03 15:07:55 +00001383 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384}
1385
1386static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1387{
1388 return RTL_R32(TBICSR) & TBILinkOk;
1389}
1390
1391static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1392{
1393 return RTL_R8(PHYstatus) & LinkStatus;
1394}
1395
françois romieu4da19632011-01-03 15:07:55 +00001396static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
françois romieu4da19632011-01-03 15:07:55 +00001398 void __iomem *ioaddr = tp->mmio_addr;
1399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1401}
1402
françois romieu4da19632011-01-03 15:07:55 +00001403static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
1405 unsigned int val;
1406
françois romieu4da19632011-01-03 15:07:55 +00001407 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1408 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409}
1410
Hayes Wang70090422011-07-06 15:58:06 +08001411static void rtl_link_chg_patch(struct rtl8169_private *tp)
1412{
1413 void __iomem *ioaddr = tp->mmio_addr;
1414 struct net_device *dev = tp->dev;
1415
1416 if (!netif_running(dev))
1417 return;
1418
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001419 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1420 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001421 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001422 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1423 ERIAR_EXGMAC);
1424 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1425 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001426 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001427 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1428 ERIAR_EXGMAC);
1429 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1430 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001431 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001432 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1433 ERIAR_EXGMAC);
1434 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1435 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001436 }
1437 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001438 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001439 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001440 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001441 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001442 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1443 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1444 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001445 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1446 ERIAR_EXGMAC);
1447 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1448 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001449 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001450 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1451 ERIAR_EXGMAC);
1452 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1453 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001454 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001455 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1456 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001457 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1458 ERIAR_EXGMAC);
1459 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1460 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001461 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001462 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1463 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001464 }
Hayes Wang70090422011-07-06 15:58:06 +08001465 }
1466}
1467
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001468static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001469 struct rtl8169_private *tp,
1470 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001473 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001474 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001475 if (pm)
1476 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001478 if (net_ratelimit())
1479 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001480 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001482 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001483 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001484 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486}
1487
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001488static void rtl8169_check_link_status(struct net_device *dev,
1489 struct rtl8169_private *tp,
1490 void __iomem *ioaddr)
1491{
1492 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1493}
1494
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001495#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1496
1497static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1498{
1499 void __iomem *ioaddr = tp->mmio_addr;
1500 u8 options;
1501 u32 wolopts = 0;
1502
1503 options = RTL_R8(Config1);
1504 if (!(options & PMEnable))
1505 return 0;
1506
1507 options = RTL_R8(Config3);
1508 if (options & LinkUp)
1509 wolopts |= WAKE_PHY;
1510 if (options & MagicPacket)
1511 wolopts |= WAKE_MAGIC;
1512
1513 options = RTL_R8(Config5);
1514 if (options & UWF)
1515 wolopts |= WAKE_UCAST;
1516 if (options & BWF)
1517 wolopts |= WAKE_BCAST;
1518 if (options & MWF)
1519 wolopts |= WAKE_MCAST;
1520
1521 return wolopts;
1522}
1523
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001524static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1525{
1526 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001527
Francois Romieuda78dbf2012-01-26 14:18:23 +01001528 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001529
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001530 wol->supported = WAKE_ANY;
1531 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001532
Francois Romieuda78dbf2012-01-26 14:18:23 +01001533 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001534}
1535
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001536static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001537{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001538 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001539 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001540 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001541 u32 opt;
1542 u16 reg;
1543 u8 mask;
1544 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001545 { WAKE_PHY, Config3, LinkUp },
1546 { WAKE_MAGIC, Config3, MagicPacket },
1547 { WAKE_UCAST, Config5, UWF },
1548 { WAKE_BCAST, Config5, BWF },
1549 { WAKE_MCAST, Config5, MWF },
1550 { WAKE_ANY, Config5, LanWake }
1551 };
Francois Romieu851e6022012-04-17 11:10:11 +02001552 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001553
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001554 RTL_W8(Cfg9346, Cfg9346_Unlock);
1555
1556 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001557 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001558 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001559 options |= cfg[i].mask;
1560 RTL_W8(cfg[i].reg, options);
1561 }
1562
Francois Romieu851e6022012-04-17 11:10:11 +02001563 switch (tp->mac_version) {
1564 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1565 options = RTL_R8(Config1) & ~PMEnable;
1566 if (wolopts)
1567 options |= PMEnable;
1568 RTL_W8(Config1, options);
1569 break;
1570 default:
Francois Romieud387b422012-04-17 11:12:01 +02001571 options = RTL_R8(Config2) & ~PME_SIGNAL;
1572 if (wolopts)
1573 options |= PME_SIGNAL;
1574 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001575 break;
1576 }
1577
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001578 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001579}
1580
1581static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1582{
1583 struct rtl8169_private *tp = netdev_priv(dev);
1584
Francois Romieuda78dbf2012-01-26 14:18:23 +01001585 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001586
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001587 if (wol->wolopts)
1588 tp->features |= RTL_FEATURE_WOL;
1589 else
1590 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001591 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001592
1593 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001594
françois romieuea809072010-11-08 13:23:58 +00001595 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1596
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001597 return 0;
1598}
1599
Francois Romieu31bd2042011-04-26 18:58:59 +02001600static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1601{
Francois Romieu85bffe62011-04-27 08:22:39 +02001602 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001603}
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605static void rtl8169_get_drvinfo(struct net_device *dev,
1606 struct ethtool_drvinfo *info)
1607{
1608 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001609 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Rick Jones68aad782011-11-07 13:29:27 +00001611 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1612 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1613 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001614 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001615 if (!IS_ERR_OR_NULL(rtl_fw))
1616 strlcpy(info->fw_version, rtl_fw->version,
1617 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618}
1619
1620static int rtl8169_get_regs_len(struct net_device *dev)
1621{
1622 return R8169_REGS_SIZE;
1623}
1624
1625static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001626 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627{
1628 struct rtl8169_private *tp = netdev_priv(dev);
1629 void __iomem *ioaddr = tp->mmio_addr;
1630 int ret = 0;
1631 u32 reg;
1632
1633 reg = RTL_R32(TBICSR);
1634 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1635 (duplex == DUPLEX_FULL)) {
1636 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1637 } else if (autoneg == AUTONEG_ENABLE)
1638 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1639 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001640 netif_warn(tp, link, dev,
1641 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 ret = -EOPNOTSUPP;
1643 }
1644
1645 return ret;
1646}
1647
1648static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001649 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
1651 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001652 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001653 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
Hayes Wang716b50a2011-02-22 17:26:18 +08001655 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001658 int auto_nego;
1659
françois romieu4da19632011-01-03 15:07:55 +00001660 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001661 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1662 ADVERTISE_100HALF | ADVERTISE_100FULL);
1663
1664 if (adv & ADVERTISED_10baseT_Half)
1665 auto_nego |= ADVERTISE_10HALF;
1666 if (adv & ADVERTISED_10baseT_Full)
1667 auto_nego |= ADVERTISE_10FULL;
1668 if (adv & ADVERTISED_100baseT_Half)
1669 auto_nego |= ADVERTISE_100HALF;
1670 if (adv & ADVERTISED_100baseT_Full)
1671 auto_nego |= ADVERTISE_100FULL;
1672
françois romieu3577aa12009-05-19 10:46:48 +00001673 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1674
françois romieu4da19632011-01-03 15:07:55 +00001675 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001676 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1677
1678 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001679 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001680 if (adv & ADVERTISED_1000baseT_Half)
1681 giga_ctrl |= ADVERTISE_1000HALF;
1682 if (adv & ADVERTISED_1000baseT_Full)
1683 giga_ctrl |= ADVERTISE_1000FULL;
1684 } else if (adv & (ADVERTISED_1000baseT_Half |
1685 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001686 netif_info(tp, link, dev,
1687 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001688 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
françois romieu3577aa12009-05-19 10:46:48 +00001691 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001692
françois romieu4da19632011-01-03 15:07:55 +00001693 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1694 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001695 } else {
1696 giga_ctrl = 0;
1697
1698 if (speed == SPEED_10)
1699 bmcr = 0;
1700 else if (speed == SPEED_100)
1701 bmcr = BMCR_SPEED100;
1702 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001703 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001704
1705 if (duplex == DUPLEX_FULL)
1706 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001707 }
1708
françois romieu4da19632011-01-03 15:07:55 +00001709 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001710
Francois Romieucecb5fd2011-04-01 10:21:07 +02001711 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1712 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001713 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001714 rtl_writephy(tp, 0x17, 0x2138);
1715 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001716 } else {
françois romieu4da19632011-01-03 15:07:55 +00001717 rtl_writephy(tp, 0x17, 0x2108);
1718 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001719 }
1720 }
1721
Oliver Neukum54405cd2011-01-06 21:55:13 +01001722 rc = 0;
1723out:
1724 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725}
1726
1727static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001728 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
1730 struct rtl8169_private *tp = netdev_priv(dev);
1731 int ret;
1732
Oliver Neukum54405cd2011-01-06 21:55:13 +01001733 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001734 if (ret < 0)
1735 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
Francois Romieu4876cc12011-03-11 21:07:11 +01001737 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1738 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001740 }
1741out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 return ret;
1743}
1744
1745static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1746{
1747 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 int ret;
1749
Francois Romieu4876cc12011-03-11 21:07:11 +01001750 del_timer_sync(&tp->timer);
1751
Francois Romieuda78dbf2012-01-26 14:18:23 +01001752 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001753 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001754 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001755 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return ret;
1758}
1759
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001760static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1761 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
Francois Romieud58d46b2011-05-03 16:38:29 +02001763 struct rtl8169_private *tp = netdev_priv(dev);
1764
Francois Romieu2b7b4312011-04-18 22:53:24 -07001765 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001766 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
Francois Romieud58d46b2011-05-03 16:38:29 +02001768 if (dev->mtu > JUMBO_1K &&
1769 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1770 features &= ~NETIF_F_IP_CSUM;
1771
Michał Mirosław350fb322011-04-08 06:35:56 +00001772 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773}
1774
Francois Romieuda78dbf2012-01-26 14:18:23 +01001775static void __rtl8169_set_features(struct net_device *dev,
1776 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001779 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001780 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Ben Greear6bbe0212012-02-10 15:04:33 +00001782 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1783 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Ben Greear6bbe0212012-02-10 15:04:33 +00001785 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1786 if (features & NETIF_F_RXCSUM)
1787 tp->cp_cmd |= RxChkSum;
1788 else
1789 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001790
Ben Greear6bbe0212012-02-10 15:04:33 +00001791 if (dev->features & NETIF_F_HW_VLAN_RX)
1792 tp->cp_cmd |= RxVlan;
1793 else
1794 tp->cp_cmd &= ~RxVlan;
1795
1796 RTL_W16(CPlusCmd, tp->cp_cmd);
1797 RTL_R16(CPlusCmd);
1798 }
1799 if (changed & NETIF_F_RXALL) {
1800 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1801 if (features & NETIF_F_RXALL)
1802 tmp |= (AcceptErr | AcceptRunt);
1803 RTL_W32(RxConfig, tmp);
1804 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001805}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
Francois Romieuda78dbf2012-01-26 14:18:23 +01001807static int rtl8169_set_features(struct net_device *dev,
1808 netdev_features_t features)
1809{
1810 struct rtl8169_private *tp = netdev_priv(dev);
1811
1812 rtl_lock_work(tp);
1813 __rtl8169_set_features(dev, features);
1814 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816 return 0;
1817}
1818
Francois Romieuda78dbf2012-01-26 14:18:23 +01001819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1821 struct sk_buff *skb)
1822{
Jesse Grosseab6d182010-10-20 13:56:03 +00001823 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1825}
1826
Francois Romieu7a8fc772011-03-01 17:18:33 +01001827static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
1829 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Francois Romieu7a8fc772011-03-01 17:18:33 +01001831 if (opts2 & RxVlanTag)
1832 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Eric Dumazet2edae082010-09-06 18:46:39 +00001833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 desc->opts2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835}
1836
Francois Romieuccdffb92008-07-26 14:26:06 +02001837static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838{
1839 struct rtl8169_private *tp = netdev_priv(dev);
1840 void __iomem *ioaddr = tp->mmio_addr;
1841 u32 status;
1842
1843 cmd->supported =
1844 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1845 cmd->port = PORT_FIBRE;
1846 cmd->transceiver = XCVR_INTERNAL;
1847
1848 status = RTL_R32(TBICSR);
1849 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1850 cmd->autoneg = !!(status & TBINwEnable);
1851
David Decotigny70739492011-04-27 18:32:40 +00001852 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001854
1855 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856}
1857
Francois Romieuccdffb92008-07-26 14:26:06 +02001858static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
1860 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Francois Romieuccdffb92008-07-26 14:26:06 +02001862 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863}
1864
1865static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1866{
1867 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001868 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
Francois Romieuda78dbf2012-01-26 14:18:23 +01001870 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001871 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001872 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Francois Romieuccdffb92008-07-26 14:26:06 +02001874 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875}
1876
1877static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1878 void *p)
1879{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001880 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Francois Romieu5b0384f2006-08-16 16:00:01 +02001882 if (regs->len > R8169_REGS_SIZE)
1883 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884
Francois Romieuda78dbf2012-01-26 14:18:23 +01001885 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001886 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001887 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888}
1889
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001890static u32 rtl8169_get_msglevel(struct net_device *dev)
1891{
1892 struct rtl8169_private *tp = netdev_priv(dev);
1893
1894 return tp->msg_enable;
1895}
1896
1897static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1898{
1899 struct rtl8169_private *tp = netdev_priv(dev);
1900
1901 tp->msg_enable = value;
1902}
1903
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001904static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1905 "tx_packets",
1906 "rx_packets",
1907 "tx_errors",
1908 "rx_errors",
1909 "rx_missed",
1910 "align_errors",
1911 "tx_single_collisions",
1912 "tx_multi_collisions",
1913 "unicast",
1914 "broadcast",
1915 "multicast",
1916 "tx_aborted",
1917 "tx_underrun",
1918};
1919
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001920static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001921{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001922 switch (sset) {
1923 case ETH_SS_STATS:
1924 return ARRAY_SIZE(rtl8169_gstrings);
1925 default:
1926 return -EOPNOTSUPP;
1927 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001928}
1929
Francois Romieuffc46952012-07-06 14:19:23 +02001930DECLARE_RTL_COND(rtl_counters_cond)
1931{
1932 void __iomem *ioaddr = tp->mmio_addr;
1933
1934 return RTL_R32(CounterAddrLow) & CounterDump;
1935}
1936
Ivan Vecera355423d2009-02-06 21:49:57 -08001937static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001938{
1939 struct rtl8169_private *tp = netdev_priv(dev);
1940 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001941 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001942 struct rtl8169_counters *counters;
1943 dma_addr_t paddr;
1944 u32 cmd;
1945
Ivan Vecera355423d2009-02-06 21:49:57 -08001946 /*
1947 * Some chips are unable to dump tally counters when the receiver
1948 * is disabled.
1949 */
1950 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1951 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001952
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001953 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001954 if (!counters)
1955 return;
1956
1957 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001958 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001959 RTL_W32(CounterAddrLow, cmd);
1960 RTL_W32(CounterAddrLow, cmd | CounterDump);
1961
Francois Romieuffc46952012-07-06 14:19:23 +02001962 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1963 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001964
1965 RTL_W32(CounterAddrLow, 0);
1966 RTL_W32(CounterAddrHigh, 0);
1967
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001968 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001969}
1970
Ivan Vecera355423d2009-02-06 21:49:57 -08001971static void rtl8169_get_ethtool_stats(struct net_device *dev,
1972 struct ethtool_stats *stats, u64 *data)
1973{
1974 struct rtl8169_private *tp = netdev_priv(dev);
1975
1976 ASSERT_RTNL();
1977
1978 rtl8169_update_counters(dev);
1979
1980 data[0] = le64_to_cpu(tp->counters.tx_packets);
1981 data[1] = le64_to_cpu(tp->counters.rx_packets);
1982 data[2] = le64_to_cpu(tp->counters.tx_errors);
1983 data[3] = le32_to_cpu(tp->counters.rx_errors);
1984 data[4] = le16_to_cpu(tp->counters.rx_missed);
1985 data[5] = le16_to_cpu(tp->counters.align_errors);
1986 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1987 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1988 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1989 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1990 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1991 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1992 data[12] = le16_to_cpu(tp->counters.tx_underun);
1993}
1994
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001995static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
1996{
1997 switch(stringset) {
1998 case ETH_SS_STATS:
1999 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
2000 break;
2001 }
2002}
2003
Jeff Garzik7282d492006-09-13 14:30:00 -04002004static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 .get_drvinfo = rtl8169_get_drvinfo,
2006 .get_regs_len = rtl8169_get_regs_len,
2007 .get_link = ethtool_op_get_link,
2008 .get_settings = rtl8169_get_settings,
2009 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002010 .get_msglevel = rtl8169_get_msglevel,
2011 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002013 .get_wol = rtl8169_get_wol,
2014 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002015 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002016 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002017 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002018 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019};
2020
Francois Romieu07d3f512007-02-21 22:40:46 +01002021static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002022 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023{
Francois Romieu5d320a22011-05-08 17:47:36 +02002024 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002025 /*
2026 * The driver currently handles the 8168Bf and the 8168Be identically
2027 * but they can be identified more specifically through the test below
2028 * if needed:
2029 *
2030 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002031 *
2032 * Same thing for the 8101Eb and the 8101Ec:
2033 *
2034 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002035 */
Francois Romieu37441002011-06-17 22:58:54 +02002036 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002038 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 int mac_version;
2040 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002041 /* 8168G family. */
2042 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2043 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2044
Hayes Wangc2218922011-09-06 16:55:18 +08002045 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002046 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002047 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2048 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2049
hayeswang01dc7fe2011-03-21 01:50:28 +00002050 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002051 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002052 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2053 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2054 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2055
Francois Romieu5b538df2008-07-20 16:22:45 +02002056 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002057 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2058 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002059 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002060
françois romieue6de30d2011-01-03 15:08:37 +00002061 /* 8168DP family. */
2062 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2063 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002064 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002065
Francois Romieuef808d52008-06-29 13:10:54 +02002066 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002067 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002068 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002069 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002070 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002071 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2072 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002073 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002074 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002075 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002076
2077 /* 8168B family. */
2078 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2079 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2080 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2081 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2082
2083 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002084 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2085 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002086 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002087 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002088 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2089 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2090 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002091 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2092 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2093 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2094 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2095 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2096 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002097 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002098 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002099 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002100 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2101 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002102 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2103 /* FIXME: where did these entries come from ? -- FR */
2104 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2105 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2106
2107 /* 8110 family. */
2108 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2109 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2110 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2111 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2112 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2113 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2114
Jean Delvaref21b75e2009-05-26 20:54:48 -07002115 /* Catch-all */
2116 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002117 };
2118 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 u32 reg;
2120
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002121 reg = RTL_R32(TxConfig);
2122 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 p++;
2124 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002125
2126 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2127 netif_notice(tp, probe, dev,
2128 "unknown MAC, using family default\n");
2129 tp->mac_version = default_version;
2130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131}
2132
2133static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2134{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002135 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136}
2137
Francois Romieu867763c2007-08-17 18:21:58 +02002138struct phy_reg {
2139 u16 reg;
2140 u16 val;
2141};
2142
françois romieu4da19632011-01-03 15:07:55 +00002143static void rtl_writephy_batch(struct rtl8169_private *tp,
2144 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002145{
2146 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002147 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002148 regs++;
2149 }
2150}
2151
françois romieubca03d52011-01-03 15:07:31 +00002152#define PHY_READ 0x00000000
2153#define PHY_DATA_OR 0x10000000
2154#define PHY_DATA_AND 0x20000000
2155#define PHY_BJMPN 0x30000000
2156#define PHY_READ_EFUSE 0x40000000
2157#define PHY_READ_MAC_BYTE 0x50000000
2158#define PHY_WRITE_MAC_BYTE 0x60000000
2159#define PHY_CLEAR_READCOUNT 0x70000000
2160#define PHY_WRITE 0x80000000
2161#define PHY_READCOUNT_EQ_SKIP 0x90000000
2162#define PHY_COMP_EQ_SKIPN 0xa0000000
2163#define PHY_COMP_NEQ_SKIPN 0xb0000000
2164#define PHY_WRITE_PREVIOUS 0xc0000000
2165#define PHY_SKIPN 0xd0000000
2166#define PHY_DELAY_MS 0xe0000000
2167#define PHY_WRITE_ERI_WORD 0xf0000000
2168
Hayes Wang960aee62011-06-18 11:37:48 +02002169struct fw_info {
2170 u32 magic;
2171 char version[RTL_VER_SIZE];
2172 __le32 fw_start;
2173 __le32 fw_len;
2174 u8 chksum;
2175} __packed;
2176
Francois Romieu1c361ef2011-06-17 17:16:24 +02002177#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2178
2179static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002180{
Francois Romieub6ffd972011-06-17 17:00:05 +02002181 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002182 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002183 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2184 char *version = rtl_fw->version;
2185 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002186
Francois Romieu1c361ef2011-06-17 17:16:24 +02002187 if (fw->size < FW_OPCODE_SIZE)
2188 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002189
2190 if (!fw_info->magic) {
2191 size_t i, size, start;
2192 u8 checksum = 0;
2193
2194 if (fw->size < sizeof(*fw_info))
2195 goto out;
2196
2197 for (i = 0; i < fw->size; i++)
2198 checksum += fw->data[i];
2199 if (checksum != 0)
2200 goto out;
2201
2202 start = le32_to_cpu(fw_info->fw_start);
2203 if (start > fw->size)
2204 goto out;
2205
2206 size = le32_to_cpu(fw_info->fw_len);
2207 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2208 goto out;
2209
2210 memcpy(version, fw_info->version, RTL_VER_SIZE);
2211
2212 pa->code = (__le32 *)(fw->data + start);
2213 pa->size = size;
2214 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002215 if (fw->size % FW_OPCODE_SIZE)
2216 goto out;
2217
2218 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2219
2220 pa->code = (__le32 *)fw->data;
2221 pa->size = fw->size / FW_OPCODE_SIZE;
2222 }
2223 version[RTL_VER_SIZE - 1] = 0;
2224
2225 rc = true;
2226out:
2227 return rc;
2228}
2229
Francois Romieufd112f22011-06-18 00:10:29 +02002230static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2231 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002232{
Francois Romieufd112f22011-06-18 00:10:29 +02002233 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002234 size_t index;
2235
Francois Romieu1c361ef2011-06-17 17:16:24 +02002236 for (index = 0; index < pa->size; index++) {
2237 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002238 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002239
hayeswang42b82dc2011-01-10 02:07:25 +00002240 switch(action & 0xf0000000) {
2241 case PHY_READ:
2242 case PHY_DATA_OR:
2243 case PHY_DATA_AND:
2244 case PHY_READ_EFUSE:
2245 case PHY_CLEAR_READCOUNT:
2246 case PHY_WRITE:
2247 case PHY_WRITE_PREVIOUS:
2248 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002249 break;
2250
hayeswang42b82dc2011-01-10 02:07:25 +00002251 case PHY_BJMPN:
2252 if (regno > index) {
Francois Romieufd112f22011-06-18 00:10:29 +02002253 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002254 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002255 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002256 }
2257 break;
2258 case PHY_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002259 if (index + 2 >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002260 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002261 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002262 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002263 }
2264 break;
2265 case PHY_COMP_EQ_SKIPN:
2266 case PHY_COMP_NEQ_SKIPN:
2267 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002268 if (index + 1 + regno >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002269 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002270 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002271 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002272 }
2273 break;
2274
2275 case PHY_READ_MAC_BYTE:
2276 case PHY_WRITE_MAC_BYTE:
2277 case PHY_WRITE_ERI_WORD:
2278 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002279 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002280 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002281 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002282 }
2283 }
Francois Romieufd112f22011-06-18 00:10:29 +02002284 rc = true;
2285out:
2286 return rc;
2287}
françois romieubca03d52011-01-03 15:07:31 +00002288
Francois Romieufd112f22011-06-18 00:10:29 +02002289static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2290{
2291 struct net_device *dev = tp->dev;
2292 int rc = -EINVAL;
2293
2294 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2295 netif_err(tp, ifup, dev, "invalid firwmare\n");
2296 goto out;
2297 }
2298
2299 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2300 rc = 0;
2301out:
2302 return rc;
2303}
2304
2305static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2306{
2307 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2308 u32 predata, count;
2309 size_t index;
2310
2311 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002312
Francois Romieu1c361ef2011-06-17 17:16:24 +02002313 for (index = 0; index < pa->size; ) {
2314 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002315 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002316 u32 regno = (action & 0x0fff0000) >> 16;
2317
2318 if (!action)
2319 break;
françois romieubca03d52011-01-03 15:07:31 +00002320
2321 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002322 case PHY_READ:
2323 predata = rtl_readphy(tp, regno);
2324 count++;
2325 index++;
françois romieubca03d52011-01-03 15:07:31 +00002326 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002327 case PHY_DATA_OR:
2328 predata |= data;
2329 index++;
2330 break;
2331 case PHY_DATA_AND:
2332 predata &= data;
2333 index++;
2334 break;
2335 case PHY_BJMPN:
2336 index -= regno;
2337 break;
2338 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002339 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002340 index++;
2341 break;
2342 case PHY_CLEAR_READCOUNT:
2343 count = 0;
2344 index++;
2345 break;
2346 case PHY_WRITE:
2347 rtl_writephy(tp, regno, data);
2348 index++;
2349 break;
2350 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002351 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002352 break;
2353 case PHY_COMP_EQ_SKIPN:
2354 if (predata == data)
2355 index += regno;
2356 index++;
2357 break;
2358 case PHY_COMP_NEQ_SKIPN:
2359 if (predata != data)
2360 index += regno;
2361 index++;
2362 break;
2363 case PHY_WRITE_PREVIOUS:
2364 rtl_writephy(tp, regno, predata);
2365 index++;
2366 break;
2367 case PHY_SKIPN:
2368 index += regno + 1;
2369 break;
2370 case PHY_DELAY_MS:
2371 mdelay(data);
2372 index++;
2373 break;
2374
2375 case PHY_READ_MAC_BYTE:
2376 case PHY_WRITE_MAC_BYTE:
2377 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002378 default:
2379 BUG();
2380 }
2381 }
2382}
2383
françois romieuf1e02ed2011-01-13 13:07:53 +00002384static void rtl_release_firmware(struct rtl8169_private *tp)
2385{
Francois Romieub6ffd972011-06-17 17:00:05 +02002386 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2387 release_firmware(tp->rtl_fw->fw);
2388 kfree(tp->rtl_fw);
2389 }
2390 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002391}
2392
François Romieu953a12c2011-04-24 17:38:48 +02002393static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002394{
Francois Romieub6ffd972011-06-17 17:00:05 +02002395 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002396
2397 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
hayeswange0c07552012-10-23 20:24:03 +00002398 if (!IS_ERR_OR_NULL(rtl_fw)) {
Francois Romieub6ffd972011-06-17 17:00:05 +02002399 rtl_phy_write_fw(tp, rtl_fw);
hayeswange0c07552012-10-23 20:24:03 +00002400 tp->features |= RTL_FEATURE_FW_LOADED;
2401 }
François Romieu953a12c2011-04-24 17:38:48 +02002402}
2403
2404static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2405{
2406 if (rtl_readphy(tp, reg) != val)
2407 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2408 else
2409 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002410}
2411
hayeswange0c07552012-10-23 20:24:03 +00002412static void r810x_aldps_disable(struct rtl8169_private *tp)
2413{
2414 rtl_writephy(tp, 0x1f, 0x0000);
2415 rtl_writephy(tp, 0x18, 0x0310);
2416 msleep(100);
2417}
2418
2419static void r810x_aldps_enable(struct rtl8169_private *tp)
2420{
2421 if (!(tp->features & RTL_FEATURE_FW_LOADED))
2422 return;
2423
2424 rtl_writephy(tp, 0x1f, 0x0000);
2425 rtl_writephy(tp, 0x18, 0x8310);
2426}
2427
2428static void r8168_aldps_enable_1(struct rtl8169_private *tp)
2429{
2430 if (!(tp->features & RTL_FEATURE_FW_LOADED))
2431 return;
2432
2433 rtl_writephy(tp, 0x1f, 0x0000);
2434 rtl_w1w0_phy(tp, 0x15, 0x1000, 0x0000);
2435}
2436
françois romieu4da19632011-01-03 15:07:55 +00002437static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002439 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002440 { 0x1f, 0x0001 },
2441 { 0x06, 0x006e },
2442 { 0x08, 0x0708 },
2443 { 0x15, 0x4000 },
2444 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
françois romieu0b9b5712009-08-10 19:44:56 +00002446 { 0x1f, 0x0001 },
2447 { 0x03, 0x00a1 },
2448 { 0x02, 0x0008 },
2449 { 0x01, 0x0120 },
2450 { 0x00, 0x1000 },
2451 { 0x04, 0x0800 },
2452 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
françois romieu0b9b5712009-08-10 19:44:56 +00002454 { 0x03, 0xff41 },
2455 { 0x02, 0xdf60 },
2456 { 0x01, 0x0140 },
2457 { 0x00, 0x0077 },
2458 { 0x04, 0x7800 },
2459 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
françois romieu0b9b5712009-08-10 19:44:56 +00002461 { 0x03, 0x802f },
2462 { 0x02, 0x4f02 },
2463 { 0x01, 0x0409 },
2464 { 0x00, 0xf0f9 },
2465 { 0x04, 0x9800 },
2466 { 0x04, 0x9000 },
2467
2468 { 0x03, 0xdf01 },
2469 { 0x02, 0xdf20 },
2470 { 0x01, 0xff95 },
2471 { 0x00, 0xba00 },
2472 { 0x04, 0xa800 },
2473 { 0x04, 0xa000 },
2474
2475 { 0x03, 0xff41 },
2476 { 0x02, 0xdf20 },
2477 { 0x01, 0x0140 },
2478 { 0x00, 0x00bb },
2479 { 0x04, 0xb800 },
2480 { 0x04, 0xb000 },
2481
2482 { 0x03, 0xdf41 },
2483 { 0x02, 0xdc60 },
2484 { 0x01, 0x6340 },
2485 { 0x00, 0x007d },
2486 { 0x04, 0xd800 },
2487 { 0x04, 0xd000 },
2488
2489 { 0x03, 0xdf01 },
2490 { 0x02, 0xdf20 },
2491 { 0x01, 0x100a },
2492 { 0x00, 0xa0ff },
2493 { 0x04, 0xf800 },
2494 { 0x04, 0xf000 },
2495
2496 { 0x1f, 0x0000 },
2497 { 0x0b, 0x0000 },
2498 { 0x00, 0x9200 }
2499 };
2500
françois romieu4da19632011-01-03 15:07:55 +00002501 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502}
2503
françois romieu4da19632011-01-03 15:07:55 +00002504static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002505{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002506 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002507 { 0x1f, 0x0002 },
2508 { 0x01, 0x90d0 },
2509 { 0x1f, 0x0000 }
2510 };
2511
françois romieu4da19632011-01-03 15:07:55 +00002512 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002513}
2514
françois romieu4da19632011-01-03 15:07:55 +00002515static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002516{
2517 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002518
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002519 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2520 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002521 return;
2522
françois romieu4da19632011-01-03 15:07:55 +00002523 rtl_writephy(tp, 0x1f, 0x0001);
2524 rtl_writephy(tp, 0x10, 0xf01b);
2525 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002526}
2527
françois romieu4da19632011-01-03 15:07:55 +00002528static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002529{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002530 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002531 { 0x1f, 0x0001 },
2532 { 0x04, 0x0000 },
2533 { 0x03, 0x00a1 },
2534 { 0x02, 0x0008 },
2535 { 0x01, 0x0120 },
2536 { 0x00, 0x1000 },
2537 { 0x04, 0x0800 },
2538 { 0x04, 0x9000 },
2539 { 0x03, 0x802f },
2540 { 0x02, 0x4f02 },
2541 { 0x01, 0x0409 },
2542 { 0x00, 0xf099 },
2543 { 0x04, 0x9800 },
2544 { 0x04, 0xa000 },
2545 { 0x03, 0xdf01 },
2546 { 0x02, 0xdf20 },
2547 { 0x01, 0xff95 },
2548 { 0x00, 0xba00 },
2549 { 0x04, 0xa800 },
2550 { 0x04, 0xf000 },
2551 { 0x03, 0xdf01 },
2552 { 0x02, 0xdf20 },
2553 { 0x01, 0x101a },
2554 { 0x00, 0xa0ff },
2555 { 0x04, 0xf800 },
2556 { 0x04, 0x0000 },
2557 { 0x1f, 0x0000 },
2558
2559 { 0x1f, 0x0001 },
2560 { 0x10, 0xf41b },
2561 { 0x14, 0xfb54 },
2562 { 0x18, 0xf5c7 },
2563 { 0x1f, 0x0000 },
2564
2565 { 0x1f, 0x0001 },
2566 { 0x17, 0x0cc0 },
2567 { 0x1f, 0x0000 }
2568 };
2569
françois romieu4da19632011-01-03 15:07:55 +00002570 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002571
françois romieu4da19632011-01-03 15:07:55 +00002572 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002573}
2574
françois romieu4da19632011-01-03 15:07:55 +00002575static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002576{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002577 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002578 { 0x1f, 0x0001 },
2579 { 0x04, 0x0000 },
2580 { 0x03, 0x00a1 },
2581 { 0x02, 0x0008 },
2582 { 0x01, 0x0120 },
2583 { 0x00, 0x1000 },
2584 { 0x04, 0x0800 },
2585 { 0x04, 0x9000 },
2586 { 0x03, 0x802f },
2587 { 0x02, 0x4f02 },
2588 { 0x01, 0x0409 },
2589 { 0x00, 0xf099 },
2590 { 0x04, 0x9800 },
2591 { 0x04, 0xa000 },
2592 { 0x03, 0xdf01 },
2593 { 0x02, 0xdf20 },
2594 { 0x01, 0xff95 },
2595 { 0x00, 0xba00 },
2596 { 0x04, 0xa800 },
2597 { 0x04, 0xf000 },
2598 { 0x03, 0xdf01 },
2599 { 0x02, 0xdf20 },
2600 { 0x01, 0x101a },
2601 { 0x00, 0xa0ff },
2602 { 0x04, 0xf800 },
2603 { 0x04, 0x0000 },
2604 { 0x1f, 0x0000 },
2605
2606 { 0x1f, 0x0001 },
2607 { 0x0b, 0x8480 },
2608 { 0x1f, 0x0000 },
2609
2610 { 0x1f, 0x0001 },
2611 { 0x18, 0x67c7 },
2612 { 0x04, 0x2000 },
2613 { 0x03, 0x002f },
2614 { 0x02, 0x4360 },
2615 { 0x01, 0x0109 },
2616 { 0x00, 0x3022 },
2617 { 0x04, 0x2800 },
2618 { 0x1f, 0x0000 },
2619
2620 { 0x1f, 0x0001 },
2621 { 0x17, 0x0cc0 },
2622 { 0x1f, 0x0000 }
2623 };
2624
françois romieu4da19632011-01-03 15:07:55 +00002625 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002626}
2627
françois romieu4da19632011-01-03 15:07:55 +00002628static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002629{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002630 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002631 { 0x10, 0xf41b },
2632 { 0x1f, 0x0000 }
2633 };
2634
françois romieu4da19632011-01-03 15:07:55 +00002635 rtl_writephy(tp, 0x1f, 0x0001);
2636 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002637
françois romieu4da19632011-01-03 15:07:55 +00002638 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002639}
2640
françois romieu4da19632011-01-03 15:07:55 +00002641static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002642{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002643 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002644 { 0x1f, 0x0001 },
2645 { 0x10, 0xf41b },
2646 { 0x1f, 0x0000 }
2647 };
2648
françois romieu4da19632011-01-03 15:07:55 +00002649 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002650}
2651
françois romieu4da19632011-01-03 15:07:55 +00002652static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002653{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002654 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002655 { 0x1f, 0x0000 },
2656 { 0x1d, 0x0f00 },
2657 { 0x1f, 0x0002 },
2658 { 0x0c, 0x1ec8 },
2659 { 0x1f, 0x0000 }
2660 };
2661
françois romieu4da19632011-01-03 15:07:55 +00002662 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002663}
2664
françois romieu4da19632011-01-03 15:07:55 +00002665static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002666{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002667 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002668 { 0x1f, 0x0001 },
2669 { 0x1d, 0x3d98 },
2670 { 0x1f, 0x0000 }
2671 };
2672
françois romieu4da19632011-01-03 15:07:55 +00002673 rtl_writephy(tp, 0x1f, 0x0000);
2674 rtl_patchphy(tp, 0x14, 1 << 5);
2675 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002676
françois romieu4da19632011-01-03 15:07:55 +00002677 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002678}
2679
françois romieu4da19632011-01-03 15:07:55 +00002680static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002681{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002682 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002683 { 0x1f, 0x0001 },
2684 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002685 { 0x1f, 0x0002 },
2686 { 0x00, 0x88d4 },
2687 { 0x01, 0x82b1 },
2688 { 0x03, 0x7002 },
2689 { 0x08, 0x9e30 },
2690 { 0x09, 0x01f0 },
2691 { 0x0a, 0x5500 },
2692 { 0x0c, 0x00c8 },
2693 { 0x1f, 0x0003 },
2694 { 0x12, 0xc096 },
2695 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002696 { 0x1f, 0x0000 },
2697 { 0x1f, 0x0000 },
2698 { 0x09, 0x2000 },
2699 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002700 };
2701
françois romieu4da19632011-01-03 15:07:55 +00002702 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002703
françois romieu4da19632011-01-03 15:07:55 +00002704 rtl_patchphy(tp, 0x14, 1 << 5);
2705 rtl_patchphy(tp, 0x0d, 1 << 5);
2706 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002707}
2708
françois romieu4da19632011-01-03 15:07:55 +00002709static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002710{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002711 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002712 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002713 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002714 { 0x03, 0x802f },
2715 { 0x02, 0x4f02 },
2716 { 0x01, 0x0409 },
2717 { 0x00, 0xf099 },
2718 { 0x04, 0x9800 },
2719 { 0x04, 0x9000 },
2720 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002721 { 0x1f, 0x0002 },
2722 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002723 { 0x06, 0x0761 },
2724 { 0x1f, 0x0003 },
2725 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002726 { 0x1f, 0x0000 }
2727 };
2728
françois romieu4da19632011-01-03 15:07:55 +00002729 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002730
françois romieu4da19632011-01-03 15:07:55 +00002731 rtl_patchphy(tp, 0x16, 1 << 0);
2732 rtl_patchphy(tp, 0x14, 1 << 5);
2733 rtl_patchphy(tp, 0x0d, 1 << 5);
2734 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002735}
2736
françois romieu4da19632011-01-03 15:07:55 +00002737static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002738{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002739 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002740 { 0x1f, 0x0001 },
2741 { 0x12, 0x2300 },
2742 { 0x1d, 0x3d98 },
2743 { 0x1f, 0x0002 },
2744 { 0x0c, 0x7eb8 },
2745 { 0x06, 0x5461 },
2746 { 0x1f, 0x0003 },
2747 { 0x16, 0x0f0a },
2748 { 0x1f, 0x0000 }
2749 };
2750
françois romieu4da19632011-01-03 15:07:55 +00002751 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002752
françois romieu4da19632011-01-03 15:07:55 +00002753 rtl_patchphy(tp, 0x16, 1 << 0);
2754 rtl_patchphy(tp, 0x14, 1 << 5);
2755 rtl_patchphy(tp, 0x0d, 1 << 5);
2756 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002757}
2758
françois romieu4da19632011-01-03 15:07:55 +00002759static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002760{
françois romieu4da19632011-01-03 15:07:55 +00002761 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002762}
2763
françois romieubca03d52011-01-03 15:07:31 +00002764static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002765{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002766 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002767 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002768 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002769 { 0x06, 0x4064 },
2770 { 0x07, 0x2863 },
2771 { 0x08, 0x059c },
2772 { 0x09, 0x26b4 },
2773 { 0x0a, 0x6a19 },
2774 { 0x0b, 0xdcc8 },
2775 { 0x10, 0xf06d },
2776 { 0x14, 0x7f68 },
2777 { 0x18, 0x7fd9 },
2778 { 0x1c, 0xf0ff },
2779 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002780 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002781 { 0x12, 0xf49f },
2782 { 0x13, 0x070b },
2783 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002784 { 0x14, 0x94c0 },
2785
2786 /*
2787 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002788 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002789 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002790 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002791 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002792 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002793 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002794 { 0x06, 0x5561 },
2795
2796 /*
2797 * Can not link to 1Gbps with bad cable
2798 * Decrease SNR threshold form 21.07dB to 19.04dB
2799 */
2800 { 0x1f, 0x0001 },
2801 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002802
2803 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002804 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002805 };
2806
françois romieu4da19632011-01-03 15:07:55 +00002807 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002808
françois romieubca03d52011-01-03 15:07:31 +00002809 /*
2810 * Rx Error Issue
2811 * Fine Tune Switching regulator parameter
2812 */
françois romieu4da19632011-01-03 15:07:55 +00002813 rtl_writephy(tp, 0x1f, 0x0002);
2814 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2815 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002816
Francois Romieufdf6fc02012-07-06 22:40:38 +02002817 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002818 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002819 { 0x1f, 0x0002 },
2820 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002821 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002822 { 0x05, 0x8330 },
2823 { 0x06, 0x669a },
2824 { 0x1f, 0x0002 }
2825 };
2826 int val;
2827
françois romieu4da19632011-01-03 15:07:55 +00002828 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002829
françois romieu4da19632011-01-03 15:07:55 +00002830 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002831
2832 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002833 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002834 0x0065, 0x0066, 0x0067, 0x0068,
2835 0x0069, 0x006a, 0x006b, 0x006c
2836 };
2837 int i;
2838
françois romieu4da19632011-01-03 15:07:55 +00002839 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002840
2841 val &= 0xff00;
2842 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002843 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002844 }
2845 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002846 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002847 { 0x1f, 0x0002 },
2848 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002849 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002850 { 0x05, 0x8330 },
2851 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002852 };
2853
françois romieu4da19632011-01-03 15:07:55 +00002854 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002855 }
2856
françois romieubca03d52011-01-03 15:07:31 +00002857 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002858 rtl_writephy(tp, 0x1f, 0x0002);
2859 rtl_patchphy(tp, 0x0d, 0x0300);
2860 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002861
françois romieubca03d52011-01-03 15:07:31 +00002862 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002863 rtl_writephy(tp, 0x1f, 0x0002);
2864 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2865 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002866
françois romieu4da19632011-01-03 15:07:55 +00002867 rtl_writephy(tp, 0x1f, 0x0005);
2868 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002869
2870 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002871
françois romieu4da19632011-01-03 15:07:55 +00002872 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002873}
2874
françois romieubca03d52011-01-03 15:07:31 +00002875static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002876{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002877 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002878 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002879 { 0x1f, 0x0001 },
2880 { 0x06, 0x4064 },
2881 { 0x07, 0x2863 },
2882 { 0x08, 0x059c },
2883 { 0x09, 0x26b4 },
2884 { 0x0a, 0x6a19 },
2885 { 0x0b, 0xdcc8 },
2886 { 0x10, 0xf06d },
2887 { 0x14, 0x7f68 },
2888 { 0x18, 0x7fd9 },
2889 { 0x1c, 0xf0ff },
2890 { 0x1d, 0x3d9c },
2891 { 0x1f, 0x0003 },
2892 { 0x12, 0xf49f },
2893 { 0x13, 0x070b },
2894 { 0x1a, 0x05ad },
2895 { 0x14, 0x94c0 },
2896
françois romieubca03d52011-01-03 15:07:31 +00002897 /*
2898 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002899 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002900 */
françois romieudaf9df62009-10-07 12:44:20 +00002901 { 0x1f, 0x0002 },
2902 { 0x06, 0x5561 },
2903 { 0x1f, 0x0005 },
2904 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002905 { 0x06, 0x5561 },
2906
2907 /*
2908 * Can not link to 1Gbps with bad cable
2909 * Decrease SNR threshold form 21.07dB to 19.04dB
2910 */
2911 { 0x1f, 0x0001 },
2912 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002913
2914 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002915 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002916 };
2917
françois romieu4da19632011-01-03 15:07:55 +00002918 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002919
Francois Romieufdf6fc02012-07-06 22:40:38 +02002920 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002921 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002922 { 0x1f, 0x0002 },
2923 { 0x05, 0x669a },
2924 { 0x1f, 0x0005 },
2925 { 0x05, 0x8330 },
2926 { 0x06, 0x669a },
2927
2928 { 0x1f, 0x0002 }
2929 };
2930 int val;
2931
françois romieu4da19632011-01-03 15:07:55 +00002932 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002933
françois romieu4da19632011-01-03 15:07:55 +00002934 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002935 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002936 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002937 0x0065, 0x0066, 0x0067, 0x0068,
2938 0x0069, 0x006a, 0x006b, 0x006c
2939 };
2940 int i;
2941
françois romieu4da19632011-01-03 15:07:55 +00002942 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002943
2944 val &= 0xff00;
2945 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002946 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002947 }
2948 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002949 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002950 { 0x1f, 0x0002 },
2951 { 0x05, 0x2642 },
2952 { 0x1f, 0x0005 },
2953 { 0x05, 0x8330 },
2954 { 0x06, 0x2642 }
2955 };
2956
françois romieu4da19632011-01-03 15:07:55 +00002957 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002958 }
2959
françois romieubca03d52011-01-03 15:07:31 +00002960 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002961 rtl_writephy(tp, 0x1f, 0x0002);
2962 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2963 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002964
françois romieubca03d52011-01-03 15:07:31 +00002965 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002966 rtl_writephy(tp, 0x1f, 0x0002);
2967 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002968
françois romieu4da19632011-01-03 15:07:55 +00002969 rtl_writephy(tp, 0x1f, 0x0005);
2970 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002971
2972 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002973
françois romieu4da19632011-01-03 15:07:55 +00002974 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002975}
2976
françois romieu4da19632011-01-03 15:07:55 +00002977static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002978{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002979 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002980 { 0x1f, 0x0002 },
2981 { 0x10, 0x0008 },
2982 { 0x0d, 0x006c },
2983
2984 { 0x1f, 0x0000 },
2985 { 0x0d, 0xf880 },
2986
2987 { 0x1f, 0x0001 },
2988 { 0x17, 0x0cc0 },
2989
2990 { 0x1f, 0x0001 },
2991 { 0x0b, 0xa4d8 },
2992 { 0x09, 0x281c },
2993 { 0x07, 0x2883 },
2994 { 0x0a, 0x6b35 },
2995 { 0x1d, 0x3da4 },
2996 { 0x1c, 0xeffd },
2997 { 0x14, 0x7f52 },
2998 { 0x18, 0x7fc6 },
2999 { 0x08, 0x0601 },
3000 { 0x06, 0x4063 },
3001 { 0x10, 0xf074 },
3002 { 0x1f, 0x0003 },
3003 { 0x13, 0x0789 },
3004 { 0x12, 0xf4bd },
3005 { 0x1a, 0x04fd },
3006 { 0x14, 0x84b0 },
3007 { 0x1f, 0x0000 },
3008 { 0x00, 0x9200 },
3009
3010 { 0x1f, 0x0005 },
3011 { 0x01, 0x0340 },
3012 { 0x1f, 0x0001 },
3013 { 0x04, 0x4000 },
3014 { 0x03, 0x1d21 },
3015 { 0x02, 0x0c32 },
3016 { 0x01, 0x0200 },
3017 { 0x00, 0x5554 },
3018 { 0x04, 0x4800 },
3019 { 0x04, 0x4000 },
3020 { 0x04, 0xf000 },
3021 { 0x03, 0xdf01 },
3022 { 0x02, 0xdf20 },
3023 { 0x01, 0x101a },
3024 { 0x00, 0xa0ff },
3025 { 0x04, 0xf800 },
3026 { 0x04, 0xf000 },
3027 { 0x1f, 0x0000 },
3028
3029 { 0x1f, 0x0007 },
3030 { 0x1e, 0x0023 },
3031 { 0x16, 0x0000 },
3032 { 0x1f, 0x0000 }
3033 };
3034
françois romieu4da19632011-01-03 15:07:55 +00003035 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02003036}
3037
françois romieue6de30d2011-01-03 15:08:37 +00003038static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3039{
3040 static const struct phy_reg phy_reg_init[] = {
3041 { 0x1f, 0x0001 },
3042 { 0x17, 0x0cc0 },
3043
3044 { 0x1f, 0x0007 },
3045 { 0x1e, 0x002d },
3046 { 0x18, 0x0040 },
3047 { 0x1f, 0x0000 }
3048 };
3049
3050 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3051 rtl_patchphy(tp, 0x0d, 1 << 5);
3052}
3053
Hayes Wang70090422011-07-06 15:58:06 +08003054static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003055{
3056 static const struct phy_reg phy_reg_init[] = {
3057 /* Enable Delay cap */
3058 { 0x1f, 0x0005 },
3059 { 0x05, 0x8b80 },
3060 { 0x06, 0xc896 },
3061 { 0x1f, 0x0000 },
3062
3063 /* Channel estimation fine tune */
3064 { 0x1f, 0x0001 },
3065 { 0x0b, 0x6c20 },
3066 { 0x07, 0x2872 },
3067 { 0x1c, 0xefff },
3068 { 0x1f, 0x0003 },
3069 { 0x14, 0x6420 },
3070 { 0x1f, 0x0000 },
3071
3072 /* Update PFM & 10M TX idle timer */
3073 { 0x1f, 0x0007 },
3074 { 0x1e, 0x002f },
3075 { 0x15, 0x1919 },
3076 { 0x1f, 0x0000 },
3077
3078 { 0x1f, 0x0007 },
3079 { 0x1e, 0x00ac },
3080 { 0x18, 0x0006 },
3081 { 0x1f, 0x0000 }
3082 };
3083
Francois Romieu15ecd032011-04-27 13:52:22 -07003084 rtl_apply_firmware(tp);
3085
hayeswang01dc7fe2011-03-21 01:50:28 +00003086 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3087
3088 /* DCO enable for 10M IDLE Power */
3089 rtl_writephy(tp, 0x1f, 0x0007);
3090 rtl_writephy(tp, 0x1e, 0x0023);
3091 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3092 rtl_writephy(tp, 0x1f, 0x0000);
3093
3094 /* For impedance matching */
3095 rtl_writephy(tp, 0x1f, 0x0002);
3096 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003097 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003098
3099 /* PHY auto speed down */
3100 rtl_writephy(tp, 0x1f, 0x0007);
3101 rtl_writephy(tp, 0x1e, 0x002d);
3102 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3103 rtl_writephy(tp, 0x1f, 0x0000);
3104 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3105
3106 rtl_writephy(tp, 0x1f, 0x0005);
3107 rtl_writephy(tp, 0x05, 0x8b86);
3108 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3109 rtl_writephy(tp, 0x1f, 0x0000);
3110
3111 rtl_writephy(tp, 0x1f, 0x0005);
3112 rtl_writephy(tp, 0x05, 0x8b85);
3113 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3114 rtl_writephy(tp, 0x1f, 0x0007);
3115 rtl_writephy(tp, 0x1e, 0x0020);
3116 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3117 rtl_writephy(tp, 0x1f, 0x0006);
3118 rtl_writephy(tp, 0x00, 0x5a00);
3119 rtl_writephy(tp, 0x1f, 0x0000);
3120 rtl_writephy(tp, 0x0d, 0x0007);
3121 rtl_writephy(tp, 0x0e, 0x003c);
3122 rtl_writephy(tp, 0x0d, 0x4007);
3123 rtl_writephy(tp, 0x0e, 0x0000);
3124 rtl_writephy(tp, 0x0d, 0x0000);
3125}
3126
Hayes Wang70090422011-07-06 15:58:06 +08003127static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3128{
3129 static const struct phy_reg phy_reg_init[] = {
3130 /* Enable Delay cap */
3131 { 0x1f, 0x0004 },
3132 { 0x1f, 0x0007 },
3133 { 0x1e, 0x00ac },
3134 { 0x18, 0x0006 },
3135 { 0x1f, 0x0002 },
3136 { 0x1f, 0x0000 },
3137 { 0x1f, 0x0000 },
3138
3139 /* Channel estimation fine tune */
3140 { 0x1f, 0x0003 },
3141 { 0x09, 0xa20f },
3142 { 0x1f, 0x0000 },
3143 { 0x1f, 0x0000 },
3144
3145 /* Green Setting */
3146 { 0x1f, 0x0005 },
3147 { 0x05, 0x8b5b },
3148 { 0x06, 0x9222 },
3149 { 0x05, 0x8b6d },
3150 { 0x06, 0x8000 },
3151 { 0x05, 0x8b76 },
3152 { 0x06, 0x8000 },
3153 { 0x1f, 0x0000 }
3154 };
3155
3156 rtl_apply_firmware(tp);
3157
3158 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3159
3160 /* For 4-corner performance improve */
3161 rtl_writephy(tp, 0x1f, 0x0005);
3162 rtl_writephy(tp, 0x05, 0x8b80);
3163 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3164 rtl_writephy(tp, 0x1f, 0x0000);
3165
3166 /* PHY auto speed down */
3167 rtl_writephy(tp, 0x1f, 0x0004);
3168 rtl_writephy(tp, 0x1f, 0x0007);
3169 rtl_writephy(tp, 0x1e, 0x002d);
3170 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3171 rtl_writephy(tp, 0x1f, 0x0002);
3172 rtl_writephy(tp, 0x1f, 0x0000);
3173 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3174
3175 /* improve 10M EEE waveform */
3176 rtl_writephy(tp, 0x1f, 0x0005);
3177 rtl_writephy(tp, 0x05, 0x8b86);
3178 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3179 rtl_writephy(tp, 0x1f, 0x0000);
3180
3181 /* Improve 2-pair detection performance */
3182 rtl_writephy(tp, 0x1f, 0x0005);
3183 rtl_writephy(tp, 0x05, 0x8b85);
3184 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3185 rtl_writephy(tp, 0x1f, 0x0000);
3186
3187 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003188 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003189 rtl_writephy(tp, 0x1f, 0x0005);
3190 rtl_writephy(tp, 0x05, 0x8b85);
3191 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3192 rtl_writephy(tp, 0x1f, 0x0004);
3193 rtl_writephy(tp, 0x1f, 0x0007);
3194 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003195 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003196 rtl_writephy(tp, 0x1f, 0x0002);
3197 rtl_writephy(tp, 0x1f, 0x0000);
3198 rtl_writephy(tp, 0x0d, 0x0007);
3199 rtl_writephy(tp, 0x0e, 0x003c);
3200 rtl_writephy(tp, 0x0d, 0x4007);
3201 rtl_writephy(tp, 0x0e, 0x0000);
3202 rtl_writephy(tp, 0x0d, 0x0000);
3203
3204 /* Green feature */
3205 rtl_writephy(tp, 0x1f, 0x0003);
3206 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3207 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3208 rtl_writephy(tp, 0x1f, 0x0000);
hayeswange0c07552012-10-23 20:24:03 +00003209
3210 r8168_aldps_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08003211}
3212
Hayes Wang5f886e02012-03-30 14:33:03 +08003213static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3214{
3215 /* For 4-corner performance improve */
3216 rtl_writephy(tp, 0x1f, 0x0005);
3217 rtl_writephy(tp, 0x05, 0x8b80);
3218 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3219 rtl_writephy(tp, 0x1f, 0x0000);
3220
3221 /* PHY auto speed down */
3222 rtl_writephy(tp, 0x1f, 0x0007);
3223 rtl_writephy(tp, 0x1e, 0x002d);
3224 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3225 rtl_writephy(tp, 0x1f, 0x0000);
3226 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3227
3228 /* Improve 10M EEE waveform */
3229 rtl_writephy(tp, 0x1f, 0x0005);
3230 rtl_writephy(tp, 0x05, 0x8b86);
3231 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3232 rtl_writephy(tp, 0x1f, 0x0000);
3233}
3234
Hayes Wangc2218922011-09-06 16:55:18 +08003235static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3236{
3237 static const struct phy_reg phy_reg_init[] = {
3238 /* Channel estimation fine tune */
3239 { 0x1f, 0x0003 },
3240 { 0x09, 0xa20f },
3241 { 0x1f, 0x0000 },
3242
3243 /* Modify green table for giga & fnet */
3244 { 0x1f, 0x0005 },
3245 { 0x05, 0x8b55 },
3246 { 0x06, 0x0000 },
3247 { 0x05, 0x8b5e },
3248 { 0x06, 0x0000 },
3249 { 0x05, 0x8b67 },
3250 { 0x06, 0x0000 },
3251 { 0x05, 0x8b70 },
3252 { 0x06, 0x0000 },
3253 { 0x1f, 0x0000 },
3254 { 0x1f, 0x0007 },
3255 { 0x1e, 0x0078 },
3256 { 0x17, 0x0000 },
3257 { 0x19, 0x00fb },
3258 { 0x1f, 0x0000 },
3259
3260 /* Modify green table for 10M */
3261 { 0x1f, 0x0005 },
3262 { 0x05, 0x8b79 },
3263 { 0x06, 0xaa00 },
3264 { 0x1f, 0x0000 },
3265
3266 /* Disable hiimpedance detection (RTCT) */
3267 { 0x1f, 0x0003 },
3268 { 0x01, 0x328a },
3269 { 0x1f, 0x0000 }
3270 };
3271
3272 rtl_apply_firmware(tp);
3273
3274 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3275
Hayes Wang5f886e02012-03-30 14:33:03 +08003276 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003277
3278 /* Improve 2-pair detection performance */
3279 rtl_writephy(tp, 0x1f, 0x0005);
3280 rtl_writephy(tp, 0x05, 0x8b85);
3281 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3282 rtl_writephy(tp, 0x1f, 0x0000);
hayeswange0c07552012-10-23 20:24:03 +00003283
3284 r8168_aldps_enable_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003285}
3286
3287static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3288{
3289 rtl_apply_firmware(tp);
3290
Hayes Wang5f886e02012-03-30 14:33:03 +08003291 rtl8168f_hw_phy_config(tp);
hayeswange0c07552012-10-23 20:24:03 +00003292
3293 r8168_aldps_enable_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003294}
3295
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003296static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3297{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003298 static const struct phy_reg phy_reg_init[] = {
3299 /* Channel estimation fine tune */
3300 { 0x1f, 0x0003 },
3301 { 0x09, 0xa20f },
3302 { 0x1f, 0x0000 },
3303
3304 /* Modify green table for giga & fnet */
3305 { 0x1f, 0x0005 },
3306 { 0x05, 0x8b55 },
3307 { 0x06, 0x0000 },
3308 { 0x05, 0x8b5e },
3309 { 0x06, 0x0000 },
3310 { 0x05, 0x8b67 },
3311 { 0x06, 0x0000 },
3312 { 0x05, 0x8b70 },
3313 { 0x06, 0x0000 },
3314 { 0x1f, 0x0000 },
3315 { 0x1f, 0x0007 },
3316 { 0x1e, 0x0078 },
3317 { 0x17, 0x0000 },
3318 { 0x19, 0x00aa },
3319 { 0x1f, 0x0000 },
3320
3321 /* Modify green table for 10M */
3322 { 0x1f, 0x0005 },
3323 { 0x05, 0x8b79 },
3324 { 0x06, 0xaa00 },
3325 { 0x1f, 0x0000 },
3326
3327 /* Disable hiimpedance detection (RTCT) */
3328 { 0x1f, 0x0003 },
3329 { 0x01, 0x328a },
3330 { 0x1f, 0x0000 }
3331 };
3332
3333
3334 rtl_apply_firmware(tp);
3335
3336 rtl8168f_hw_phy_config(tp);
3337
3338 /* Improve 2-pair detection performance */
3339 rtl_writephy(tp, 0x1f, 0x0005);
3340 rtl_writephy(tp, 0x05, 0x8b85);
3341 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3342 rtl_writephy(tp, 0x1f, 0x0000);
3343
3344 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3345
3346 /* Modify green table for giga */
3347 rtl_writephy(tp, 0x1f, 0x0005);
3348 rtl_writephy(tp, 0x05, 0x8b54);
3349 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3350 rtl_writephy(tp, 0x05, 0x8b5d);
3351 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3352 rtl_writephy(tp, 0x05, 0x8a7c);
3353 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3354 rtl_writephy(tp, 0x05, 0x8a7f);
3355 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3356 rtl_writephy(tp, 0x05, 0x8a82);
3357 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3358 rtl_writephy(tp, 0x05, 0x8a85);
3359 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3360 rtl_writephy(tp, 0x05, 0x8a88);
3361 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3362 rtl_writephy(tp, 0x1f, 0x0000);
3363
3364 /* uc same-seed solution */
3365 rtl_writephy(tp, 0x1f, 0x0005);
3366 rtl_writephy(tp, 0x05, 0x8b85);
3367 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3368 rtl_writephy(tp, 0x1f, 0x0000);
3369
3370 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003371 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003372 rtl_writephy(tp, 0x1f, 0x0005);
3373 rtl_writephy(tp, 0x05, 0x8b85);
3374 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3375 rtl_writephy(tp, 0x1f, 0x0004);
3376 rtl_writephy(tp, 0x1f, 0x0007);
3377 rtl_writephy(tp, 0x1e, 0x0020);
3378 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3379 rtl_writephy(tp, 0x1f, 0x0000);
3380 rtl_writephy(tp, 0x0d, 0x0007);
3381 rtl_writephy(tp, 0x0e, 0x003c);
3382 rtl_writephy(tp, 0x0d, 0x4007);
3383 rtl_writephy(tp, 0x0e, 0x0000);
3384 rtl_writephy(tp, 0x0d, 0x0000);
3385
3386 /* Green feature */
3387 rtl_writephy(tp, 0x1f, 0x0003);
3388 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3389 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3390 rtl_writephy(tp, 0x1f, 0x0000);
hayeswange0c07552012-10-23 20:24:03 +00003391
3392 r8168_aldps_enable_1(tp);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003393}
3394
Hayes Wangc5583862012-07-02 17:23:22 +08003395static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3396{
3397 static const u16 mac_ocp_patch[] = {
3398 0xe008, 0xe01b, 0xe01d, 0xe01f,
3399 0xe021, 0xe023, 0xe025, 0xe027,
3400 0x49d2, 0xf10d, 0x766c, 0x49e2,
3401 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3402
3403 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3404 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3405 0xbe00, 0xb416, 0x0076, 0xe86c,
3406 0xc602, 0xbe00, 0x0000, 0xc602,
3407
3408 0xbe00, 0x0000, 0xc602, 0xbe00,
3409 0x0000, 0xc602, 0xbe00, 0x0000,
3410 0xc602, 0xbe00, 0x0000, 0xc602,
3411 0xbe00, 0x0000, 0xc602, 0xbe00,
3412
3413 0x0000, 0x0000, 0x0000, 0x0000
3414 };
3415 u32 i;
3416
3417 /* Patch code for GPHY reset */
3418 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3419 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3420 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3421 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3422
3423 rtl_apply_firmware(tp);
3424
3425 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3426 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3427 else
3428 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3429
3430 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3431 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3432 else
3433 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3434
3435 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3436 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3437
3438 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3439 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3440
3441 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3442}
3443
françois romieu4da19632011-01-03 15:07:55 +00003444static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003445{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003446 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003447 { 0x1f, 0x0003 },
3448 { 0x08, 0x441d },
3449 { 0x01, 0x9100 },
3450 { 0x1f, 0x0000 }
3451 };
3452
françois romieu4da19632011-01-03 15:07:55 +00003453 rtl_writephy(tp, 0x1f, 0x0000);
3454 rtl_patchphy(tp, 0x11, 1 << 12);
3455 rtl_patchphy(tp, 0x19, 1 << 13);
3456 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003457
françois romieu4da19632011-01-03 15:07:55 +00003458 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003459}
3460
Hayes Wang5a5e4442011-02-22 17:26:21 +08003461static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3462{
3463 static const struct phy_reg phy_reg_init[] = {
3464 { 0x1f, 0x0005 },
3465 { 0x1a, 0x0000 },
3466 { 0x1f, 0x0000 },
3467
3468 { 0x1f, 0x0004 },
3469 { 0x1c, 0x0000 },
3470 { 0x1f, 0x0000 },
3471
3472 { 0x1f, 0x0001 },
3473 { 0x15, 0x7701 },
3474 { 0x1f, 0x0000 }
3475 };
3476
3477 /* Disable ALDPS before ram code */
hayeswange0c07552012-10-23 20:24:03 +00003478 r810x_aldps_disable(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003479
François Romieu953a12c2011-04-24 17:38:48 +02003480 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003481
3482 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
hayeswange0c07552012-10-23 20:24:03 +00003483
3484 r810x_aldps_enable(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003485}
3486
Hayes Wang7e18dca2012-03-30 14:33:02 +08003487static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3488{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003489 /* Disable ALDPS before setting firmware */
hayeswange0c07552012-10-23 20:24:03 +00003490 r810x_aldps_disable(tp);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003491
3492 rtl_apply_firmware(tp);
3493
3494 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003495 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003496 rtl_writephy(tp, 0x1f, 0x0004);
3497 rtl_writephy(tp, 0x10, 0x401f);
3498 rtl_writephy(tp, 0x19, 0x7030);
3499 rtl_writephy(tp, 0x1f, 0x0000);
hayeswange0c07552012-10-23 20:24:03 +00003500
3501 r810x_aldps_enable(tp);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003502}
3503
Hayes Wang5598bfe2012-07-02 17:23:21 +08003504static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3505{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003506 static const struct phy_reg phy_reg_init[] = {
3507 { 0x1f, 0x0004 },
3508 { 0x10, 0xc07f },
3509 { 0x19, 0x7030 },
3510 { 0x1f, 0x0000 }
3511 };
3512
3513 /* Disable ALDPS before ram code */
hayeswange0c07552012-10-23 20:24:03 +00003514 r810x_aldps_disable(tp);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003515
3516 rtl_apply_firmware(tp);
3517
Francois Romieufdf6fc02012-07-06 22:40:38 +02003518 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003519 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3520
Francois Romieufdf6fc02012-07-06 22:40:38 +02003521 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
hayeswange0c07552012-10-23 20:24:03 +00003522
3523 r810x_aldps_enable(tp);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003524}
3525
Francois Romieu5615d9f2007-08-17 17:50:46 +02003526static void rtl_hw_phy_config(struct net_device *dev)
3527{
3528 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003529
3530 rtl8169_print_mac_version(tp);
3531
3532 switch (tp->mac_version) {
3533 case RTL_GIGA_MAC_VER_01:
3534 break;
3535 case RTL_GIGA_MAC_VER_02:
3536 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003537 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003538 break;
3539 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003540 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003541 break;
françois romieu2e9558562009-08-10 19:44:19 +00003542 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003543 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003544 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003545 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003546 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003547 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003548 case RTL_GIGA_MAC_VER_07:
3549 case RTL_GIGA_MAC_VER_08:
3550 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003551 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003552 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003553 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003554 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003555 break;
3556 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003557 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003558 break;
3559 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003560 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003561 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003562 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003563 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003564 break;
3565 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003566 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003567 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003568 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003569 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003570 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003571 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003572 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003573 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003574 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003575 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003576 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003577 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003578 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003579 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003580 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003581 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003582 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003583 break;
3584 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003585 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003586 break;
3587 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003588 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003589 break;
françois romieue6de30d2011-01-03 15:08:37 +00003590 case RTL_GIGA_MAC_VER_28:
3591 rtl8168d_4_hw_phy_config(tp);
3592 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003593 case RTL_GIGA_MAC_VER_29:
3594 case RTL_GIGA_MAC_VER_30:
3595 rtl8105e_hw_phy_config(tp);
3596 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003597 case RTL_GIGA_MAC_VER_31:
3598 /* None. */
3599 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003600 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003601 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003602 rtl8168e_1_hw_phy_config(tp);
3603 break;
3604 case RTL_GIGA_MAC_VER_34:
3605 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003606 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003607 case RTL_GIGA_MAC_VER_35:
3608 rtl8168f_1_hw_phy_config(tp);
3609 break;
3610 case RTL_GIGA_MAC_VER_36:
3611 rtl8168f_2_hw_phy_config(tp);
3612 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003613
Hayes Wang7e18dca2012-03-30 14:33:02 +08003614 case RTL_GIGA_MAC_VER_37:
3615 rtl8402_hw_phy_config(tp);
3616 break;
3617
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003618 case RTL_GIGA_MAC_VER_38:
3619 rtl8411_hw_phy_config(tp);
3620 break;
3621
Hayes Wang5598bfe2012-07-02 17:23:21 +08003622 case RTL_GIGA_MAC_VER_39:
3623 rtl8106e_hw_phy_config(tp);
3624 break;
3625
Hayes Wangc5583862012-07-02 17:23:22 +08003626 case RTL_GIGA_MAC_VER_40:
3627 rtl8168g_1_hw_phy_config(tp);
3628 break;
3629
3630 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003631 default:
3632 break;
3633 }
3634}
3635
Francois Romieuda78dbf2012-01-26 14:18:23 +01003636static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 struct timer_list *timer = &tp->timer;
3639 void __iomem *ioaddr = tp->mmio_addr;
3640 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3641
Francois Romieubcf0bf92006-07-26 23:14:13 +02003642 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643
françois romieu4da19632011-01-03 15:07:55 +00003644 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003645 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 * A busy loop could burn quite a few cycles on nowadays CPU.
3647 * Let's delay the execution of the timer for a few ticks.
3648 */
3649 timeout = HZ/10;
3650 goto out_mod_timer;
3651 }
3652
3653 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003654 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
Francois Romieuda78dbf2012-01-26 14:18:23 +01003656 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
françois romieu4da19632011-01-03 15:07:55 +00003658 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
3660out_mod_timer:
3661 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003662}
3663
3664static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3665{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003666 if (!test_and_set_bit(flag, tp->wk.flags))
3667 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003668}
3669
3670static void rtl8169_phy_timer(unsigned long __opaque)
3671{
3672 struct net_device *dev = (struct net_device *)__opaque;
3673 struct rtl8169_private *tp = netdev_priv(dev);
3674
Francois Romieu98ddf982012-01-31 10:47:34 +01003675 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676}
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3679 void __iomem *ioaddr)
3680{
3681 iounmap(ioaddr);
3682 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003683 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 pci_disable_device(pdev);
3685 free_netdev(dev);
3686}
3687
Francois Romieuffc46952012-07-06 14:19:23 +02003688DECLARE_RTL_COND(rtl_phy_reset_cond)
3689{
3690 return tp->phy_reset_pending(tp);
3691}
3692
Francois Romieubf793292006-11-01 00:53:05 +01003693static void rtl8169_phy_reset(struct net_device *dev,
3694 struct rtl8169_private *tp)
3695{
françois romieu4da19632011-01-03 15:07:55 +00003696 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003697 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003698}
3699
David S. Miller8decf862011-09-22 03:23:13 -04003700static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3701{
3702 void __iomem *ioaddr = tp->mmio_addr;
3703
3704 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3705 (RTL_R8(PHYstatus) & TBI_Enable);
3706}
3707
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003708static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003710 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003711
Francois Romieu5615d9f2007-08-17 17:50:46 +02003712 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003713
Marcus Sundberg773328942008-07-10 21:28:08 +02003714 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3715 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3716 RTL_W8(0x82, 0x01);
3717 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003718
Francois Romieu6dccd162007-02-13 23:38:05 +01003719 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3720
3721 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3722 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003723
Francois Romieubcf0bf92006-07-26 23:14:13 +02003724 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003725 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3726 RTL_W8(0x82, 0x01);
3727 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003728 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003729 }
3730
Francois Romieubf793292006-11-01 00:53:05 +01003731 rtl8169_phy_reset(dev, tp);
3732
Oliver Neukum54405cd2011-01-06 21:55:13 +01003733 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003734 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3735 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3736 (tp->mii.supports_gmii ?
3737 ADVERTISED_1000baseT_Half |
3738 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003739
David S. Miller8decf862011-09-22 03:23:13 -04003740 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003741 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003742}
3743
Francois Romieu773d2022007-01-31 23:47:43 +01003744static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3745{
3746 void __iomem *ioaddr = tp->mmio_addr;
3747 u32 high;
3748 u32 low;
3749
3750 low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
3751 high = addr[4] | (addr[5] << 8);
3752
Francois Romieuda78dbf2012-01-26 14:18:23 +01003753 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003754
3755 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2b2010-04-26 11:42:58 +00003756
Francois Romieu773d2022007-01-31 23:47:43 +01003757 RTL_W32(MAC4, high);
françois romieu908ba2b2010-04-26 11:42:58 +00003758 RTL_R32(MAC4);
3759
Francois Romieu78f1cd02010-03-27 19:35:46 -07003760 RTL_W32(MAC0, low);
françois romieu908ba2b2010-04-26 11:42:58 +00003761 RTL_R32(MAC0);
3762
françois romieuc28aa382011-08-02 03:53:43 +00003763 if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
3764 const struct exgmac_reg e[] = {
3765 { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
3766 { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
3767 { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
3768 { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
3769 low >> 16 },
3770 };
3771
Francois Romieufdf6fc02012-07-06 22:40:38 +02003772 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
françois romieuc28aa382011-08-02 03:53:43 +00003773 }
3774
Francois Romieu773d2022007-01-31 23:47:43 +01003775 RTL_W8(Cfg9346, Cfg9346_Lock);
3776
Francois Romieuda78dbf2012-01-26 14:18:23 +01003777 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003778}
3779
3780static int rtl_set_mac_address(struct net_device *dev, void *p)
3781{
3782 struct rtl8169_private *tp = netdev_priv(dev);
3783 struct sockaddr *addr = p;
3784
3785 if (!is_valid_ether_addr(addr->sa_data))
3786 return -EADDRNOTAVAIL;
3787
3788 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3789
3790 rtl_rar_set(tp, dev->dev_addr);
3791
3792 return 0;
3793}
3794
Francois Romieu5f787a12006-08-17 13:02:36 +02003795static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3796{
3797 struct rtl8169_private *tp = netdev_priv(dev);
3798 struct mii_ioctl_data *data = if_mii(ifr);
3799
Francois Romieu8b4ab282008-11-19 22:05:25 -08003800 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3801}
Francois Romieu5f787a12006-08-17 13:02:36 +02003802
Francois Romieucecb5fd2011-04-01 10:21:07 +02003803static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3804 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003805{
Francois Romieu5f787a12006-08-17 13:02:36 +02003806 switch (cmd) {
3807 case SIOCGMIIPHY:
3808 data->phy_id = 32; /* Internal PHY */
3809 return 0;
3810
3811 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003812 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003813 return 0;
3814
3815 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003816 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003817 return 0;
3818 }
3819 return -EOPNOTSUPP;
3820}
3821
Francois Romieu8b4ab282008-11-19 22:05:25 -08003822static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3823{
3824 return -EOPNOTSUPP;
3825}
3826
Francois Romieufbac58f2007-10-04 22:51:38 +02003827static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3828{
3829 if (tp->features & RTL_FEATURE_MSI) {
3830 pci_disable_msi(pdev);
3831 tp->features &= ~RTL_FEATURE_MSI;
3832 }
3833}
3834
françois romieuc0e45c12011-01-03 15:08:04 +00003835static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
3836{
3837 struct mdio_ops *ops = &tp->mdio_ops;
3838
3839 switch (tp->mac_version) {
3840 case RTL_GIGA_MAC_VER_27:
3841 ops->write = r8168dp_1_mdio_write;
3842 ops->read = r8168dp_1_mdio_read;
3843 break;
françois romieue6de30d2011-01-03 15:08:37 +00003844 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003845 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003846 ops->write = r8168dp_2_mdio_write;
3847 ops->read = r8168dp_2_mdio_read;
3848 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003849 case RTL_GIGA_MAC_VER_40:
3850 case RTL_GIGA_MAC_VER_41:
3851 ops->write = r8168g_mdio_write;
3852 ops->read = r8168g_mdio_read;
3853 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003854 default:
3855 ops->write = r8169_mdio_write;
3856 ops->read = r8169_mdio_read;
3857 break;
3858 }
3859}
3860
David S. Miller1805b2f2011-10-24 18:18:09 -04003861static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3862{
3863 void __iomem *ioaddr = tp->mmio_addr;
3864
3865 switch (tp->mac_version) {
3866 case RTL_GIGA_MAC_VER_29:
3867 case RTL_GIGA_MAC_VER_30:
3868 case RTL_GIGA_MAC_VER_32:
3869 case RTL_GIGA_MAC_VER_33:
3870 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003871 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003872 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003873 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003874 case RTL_GIGA_MAC_VER_40:
3875 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003876 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3877 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3878 break;
3879 default:
3880 break;
3881 }
3882}
3883
3884static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3885{
3886 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3887 return false;
3888
3889 rtl_writephy(tp, 0x1f, 0x0000);
3890 rtl_writephy(tp, MII_BMCR, 0x0000);
3891
3892 rtl_wol_suspend_quirk(tp);
3893
3894 return true;
3895}
3896
françois romieu065c27c2011-01-03 15:08:12 +00003897static void r810x_phy_power_down(struct rtl8169_private *tp)
3898{
3899 rtl_writephy(tp, 0x1f, 0x0000);
3900 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3901}
3902
3903static void r810x_phy_power_up(struct rtl8169_private *tp)
3904{
3905 rtl_writephy(tp, 0x1f, 0x0000);
3906 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3907}
3908
3909static void r810x_pll_power_down(struct rtl8169_private *tp)
3910{
Hayes Wang00042992012-03-30 14:33:00 +08003911 void __iomem *ioaddr = tp->mmio_addr;
3912
David S. Miller1805b2f2011-10-24 18:18:09 -04003913 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003914 return;
françois romieu065c27c2011-01-03 15:08:12 +00003915
3916 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003917
3918 switch (tp->mac_version) {
3919 case RTL_GIGA_MAC_VER_07:
3920 case RTL_GIGA_MAC_VER_08:
3921 case RTL_GIGA_MAC_VER_09:
3922 case RTL_GIGA_MAC_VER_10:
3923 case RTL_GIGA_MAC_VER_13:
3924 case RTL_GIGA_MAC_VER_16:
3925 break;
3926 default:
3927 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3928 break;
3929 }
françois romieu065c27c2011-01-03 15:08:12 +00003930}
3931
3932static void r810x_pll_power_up(struct rtl8169_private *tp)
3933{
Hayes Wang00042992012-03-30 14:33:00 +08003934 void __iomem *ioaddr = tp->mmio_addr;
3935
françois romieu065c27c2011-01-03 15:08:12 +00003936 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003937
3938 switch (tp->mac_version) {
3939 case RTL_GIGA_MAC_VER_07:
3940 case RTL_GIGA_MAC_VER_08:
3941 case RTL_GIGA_MAC_VER_09:
3942 case RTL_GIGA_MAC_VER_10:
3943 case RTL_GIGA_MAC_VER_13:
3944 case RTL_GIGA_MAC_VER_16:
3945 break;
3946 default:
3947 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3948 break;
3949 }
françois romieu065c27c2011-01-03 15:08:12 +00003950}
3951
3952static void r8168_phy_power_up(struct rtl8169_private *tp)
3953{
3954 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003955 switch (tp->mac_version) {
3956 case RTL_GIGA_MAC_VER_11:
3957 case RTL_GIGA_MAC_VER_12:
3958 case RTL_GIGA_MAC_VER_17:
3959 case RTL_GIGA_MAC_VER_18:
3960 case RTL_GIGA_MAC_VER_19:
3961 case RTL_GIGA_MAC_VER_20:
3962 case RTL_GIGA_MAC_VER_21:
3963 case RTL_GIGA_MAC_VER_22:
3964 case RTL_GIGA_MAC_VER_23:
3965 case RTL_GIGA_MAC_VER_24:
3966 case RTL_GIGA_MAC_VER_25:
3967 case RTL_GIGA_MAC_VER_26:
3968 case RTL_GIGA_MAC_VER_27:
3969 case RTL_GIGA_MAC_VER_28:
3970 case RTL_GIGA_MAC_VER_31:
3971 rtl_writephy(tp, 0x0e, 0x0000);
3972 break;
3973 default:
3974 break;
3975 }
françois romieu065c27c2011-01-03 15:08:12 +00003976 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3977}
3978
3979static void r8168_phy_power_down(struct rtl8169_private *tp)
3980{
3981 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003982 switch (tp->mac_version) {
3983 case RTL_GIGA_MAC_VER_32:
3984 case RTL_GIGA_MAC_VER_33:
3985 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3986 break;
3987
3988 case RTL_GIGA_MAC_VER_11:
3989 case RTL_GIGA_MAC_VER_12:
3990 case RTL_GIGA_MAC_VER_17:
3991 case RTL_GIGA_MAC_VER_18:
3992 case RTL_GIGA_MAC_VER_19:
3993 case RTL_GIGA_MAC_VER_20:
3994 case RTL_GIGA_MAC_VER_21:
3995 case RTL_GIGA_MAC_VER_22:
3996 case RTL_GIGA_MAC_VER_23:
3997 case RTL_GIGA_MAC_VER_24:
3998 case RTL_GIGA_MAC_VER_25:
3999 case RTL_GIGA_MAC_VER_26:
4000 case RTL_GIGA_MAC_VER_27:
4001 case RTL_GIGA_MAC_VER_28:
4002 case RTL_GIGA_MAC_VER_31:
4003 rtl_writephy(tp, 0x0e, 0x0200);
4004 default:
4005 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
4006 break;
4007 }
françois romieu065c27c2011-01-03 15:08:12 +00004008}
4009
4010static void r8168_pll_power_down(struct rtl8169_private *tp)
4011{
4012 void __iomem *ioaddr = tp->mmio_addr;
4013
Francois Romieucecb5fd2011-04-01 10:21:07 +02004014 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
4015 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4016 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00004017 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00004018 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08004019 }
françois romieu065c27c2011-01-03 15:08:12 +00004020
Francois Romieucecb5fd2011-04-01 10:21:07 +02004021 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
4022 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00004023 (RTL_R16(CPlusCmd) & ASF)) {
4024 return;
4025 }
4026
hayeswang01dc7fe2011-03-21 01:50:28 +00004027 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
4028 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02004029 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00004030
David S. Miller1805b2f2011-10-24 18:18:09 -04004031 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00004032 return;
françois romieu065c27c2011-01-03 15:08:12 +00004033
4034 r8168_phy_power_down(tp);
4035
4036 switch (tp->mac_version) {
4037 case RTL_GIGA_MAC_VER_25:
4038 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004039 case RTL_GIGA_MAC_VER_27:
4040 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004041 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004042 case RTL_GIGA_MAC_VER_32:
4043 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004044 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4045 break;
4046 }
4047}
4048
4049static void r8168_pll_power_up(struct rtl8169_private *tp)
4050{
4051 void __iomem *ioaddr = tp->mmio_addr;
4052
françois romieu065c27c2011-01-03 15:08:12 +00004053 switch (tp->mac_version) {
4054 case RTL_GIGA_MAC_VER_25:
4055 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004056 case RTL_GIGA_MAC_VER_27:
4057 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004058 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004059 case RTL_GIGA_MAC_VER_32:
4060 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004061 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4062 break;
4063 }
4064
4065 r8168_phy_power_up(tp);
4066}
4067
Francois Romieud58d46b2011-05-03 16:38:29 +02004068static void rtl_generic_op(struct rtl8169_private *tp,
4069 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004070{
4071 if (op)
4072 op(tp);
4073}
4074
4075static void rtl_pll_power_down(struct rtl8169_private *tp)
4076{
Francois Romieud58d46b2011-05-03 16:38:29 +02004077 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004078}
4079
4080static void rtl_pll_power_up(struct rtl8169_private *tp)
4081{
Francois Romieud58d46b2011-05-03 16:38:29 +02004082 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004083}
4084
4085static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
4086{
4087 struct pll_power_ops *ops = &tp->pll_power_ops;
4088
4089 switch (tp->mac_version) {
4090 case RTL_GIGA_MAC_VER_07:
4091 case RTL_GIGA_MAC_VER_08:
4092 case RTL_GIGA_MAC_VER_09:
4093 case RTL_GIGA_MAC_VER_10:
4094 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004095 case RTL_GIGA_MAC_VER_29:
4096 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004097 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004098 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004099 ops->down = r810x_pll_power_down;
4100 ops->up = r810x_pll_power_up;
4101 break;
4102
4103 case RTL_GIGA_MAC_VER_11:
4104 case RTL_GIGA_MAC_VER_12:
4105 case RTL_GIGA_MAC_VER_17:
4106 case RTL_GIGA_MAC_VER_18:
4107 case RTL_GIGA_MAC_VER_19:
4108 case RTL_GIGA_MAC_VER_20:
4109 case RTL_GIGA_MAC_VER_21:
4110 case RTL_GIGA_MAC_VER_22:
4111 case RTL_GIGA_MAC_VER_23:
4112 case RTL_GIGA_MAC_VER_24:
4113 case RTL_GIGA_MAC_VER_25:
4114 case RTL_GIGA_MAC_VER_26:
4115 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004116 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004117 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004118 case RTL_GIGA_MAC_VER_32:
4119 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004120 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004121 case RTL_GIGA_MAC_VER_35:
4122 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004123 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004124 case RTL_GIGA_MAC_VER_40:
4125 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004126 ops->down = r8168_pll_power_down;
4127 ops->up = r8168_pll_power_up;
4128 break;
4129
4130 default:
4131 ops->down = NULL;
4132 ops->up = NULL;
4133 break;
4134 }
4135}
4136
Hayes Wange542a222011-07-06 15:58:04 +08004137static void rtl_init_rxcfg(struct rtl8169_private *tp)
4138{
4139 void __iomem *ioaddr = tp->mmio_addr;
4140
4141 switch (tp->mac_version) {
4142 case RTL_GIGA_MAC_VER_01:
4143 case RTL_GIGA_MAC_VER_02:
4144 case RTL_GIGA_MAC_VER_03:
4145 case RTL_GIGA_MAC_VER_04:
4146 case RTL_GIGA_MAC_VER_05:
4147 case RTL_GIGA_MAC_VER_06:
4148 case RTL_GIGA_MAC_VER_10:
4149 case RTL_GIGA_MAC_VER_11:
4150 case RTL_GIGA_MAC_VER_12:
4151 case RTL_GIGA_MAC_VER_13:
4152 case RTL_GIGA_MAC_VER_14:
4153 case RTL_GIGA_MAC_VER_15:
4154 case RTL_GIGA_MAC_VER_16:
4155 case RTL_GIGA_MAC_VER_17:
4156 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4157 break;
4158 case RTL_GIGA_MAC_VER_18:
4159 case RTL_GIGA_MAC_VER_19:
4160 case RTL_GIGA_MAC_VER_20:
4161 case RTL_GIGA_MAC_VER_21:
4162 case RTL_GIGA_MAC_VER_22:
4163 case RTL_GIGA_MAC_VER_23:
4164 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004165 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004166 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4167 break;
4168 default:
4169 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4170 break;
4171 }
4172}
4173
Hayes Wang92fc43b2011-07-06 15:58:03 +08004174static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4175{
4176 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4177}
4178
Francois Romieud58d46b2011-05-03 16:38:29 +02004179static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4180{
françois romieu9c5028e2012-03-02 04:43:14 +00004181 void __iomem *ioaddr = tp->mmio_addr;
4182
4183 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004184 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004185 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004186}
4187
4188static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
4189{
françois romieu9c5028e2012-03-02 04:43:14 +00004190 void __iomem *ioaddr = tp->mmio_addr;
4191
4192 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004193 rtl_generic_op(tp, tp->jumbo_ops.disable);
françois romieu9c5028e2012-03-02 04:43:14 +00004194 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004195}
4196
4197static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4198{
4199 void __iomem *ioaddr = tp->mmio_addr;
4200
4201 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4202 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4203 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4204}
4205
4206static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
4207{
4208 void __iomem *ioaddr = tp->mmio_addr;
4209
4210 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4211 RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
4212 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
4213}
4214
4215static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
4216{
4217 void __iomem *ioaddr = tp->mmio_addr;
4218
4219 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4220}
4221
4222static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4223{
4224 void __iomem *ioaddr = tp->mmio_addr;
4225
4226 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4227}
4228
4229static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4230{
4231 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004232
4233 RTL_W8(MaxTxPacketSize, 0x3f);
4234 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4235 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004236 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004237}
4238
4239static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4240{
4241 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004242
4243 RTL_W8(MaxTxPacketSize, 0x0c);
4244 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4245 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004246 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004247}
4248
4249static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4250{
4251 rtl_tx_performance_tweak(tp->pci_dev,
4252 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4253}
4254
4255static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4256{
4257 rtl_tx_performance_tweak(tp->pci_dev,
4258 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4259}
4260
4261static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4262{
4263 void __iomem *ioaddr = tp->mmio_addr;
4264
4265 r8168b_0_hw_jumbo_enable(tp);
4266
4267 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4268}
4269
4270static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4271{
4272 void __iomem *ioaddr = tp->mmio_addr;
4273
4274 r8168b_0_hw_jumbo_disable(tp);
4275
4276 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4277}
4278
4279static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
4280{
4281 struct jumbo_ops *ops = &tp->jumbo_ops;
4282
4283 switch (tp->mac_version) {
4284 case RTL_GIGA_MAC_VER_11:
4285 ops->disable = r8168b_0_hw_jumbo_disable;
4286 ops->enable = r8168b_0_hw_jumbo_enable;
4287 break;
4288 case RTL_GIGA_MAC_VER_12:
4289 case RTL_GIGA_MAC_VER_17:
4290 ops->disable = r8168b_1_hw_jumbo_disable;
4291 ops->enable = r8168b_1_hw_jumbo_enable;
4292 break;
4293 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4294 case RTL_GIGA_MAC_VER_19:
4295 case RTL_GIGA_MAC_VER_20:
4296 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4297 case RTL_GIGA_MAC_VER_22:
4298 case RTL_GIGA_MAC_VER_23:
4299 case RTL_GIGA_MAC_VER_24:
4300 case RTL_GIGA_MAC_VER_25:
4301 case RTL_GIGA_MAC_VER_26:
4302 ops->disable = r8168c_hw_jumbo_disable;
4303 ops->enable = r8168c_hw_jumbo_enable;
4304 break;
4305 case RTL_GIGA_MAC_VER_27:
4306 case RTL_GIGA_MAC_VER_28:
4307 ops->disable = r8168dp_hw_jumbo_disable;
4308 ops->enable = r8168dp_hw_jumbo_enable;
4309 break;
4310 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4311 case RTL_GIGA_MAC_VER_32:
4312 case RTL_GIGA_MAC_VER_33:
4313 case RTL_GIGA_MAC_VER_34:
4314 ops->disable = r8168e_hw_jumbo_disable;
4315 ops->enable = r8168e_hw_jumbo_enable;
4316 break;
4317
4318 /*
4319 * No action needed for jumbo frames with 8169.
4320 * No jumbo for 810x at all.
4321 */
Hayes Wangc5583862012-07-02 17:23:22 +08004322 case RTL_GIGA_MAC_VER_40:
4323 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004324 default:
4325 ops->disable = NULL;
4326 ops->enable = NULL;
4327 break;
4328 }
4329}
4330
Francois Romieuffc46952012-07-06 14:19:23 +02004331DECLARE_RTL_COND(rtl_chipcmd_cond)
4332{
4333 void __iomem *ioaddr = tp->mmio_addr;
4334
4335 return RTL_R8(ChipCmd) & CmdReset;
4336}
4337
Francois Romieu6f43adc2011-04-29 15:05:51 +02004338static void rtl_hw_reset(struct rtl8169_private *tp)
4339{
4340 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004341
Francois Romieu6f43adc2011-04-29 15:05:51 +02004342 RTL_W8(ChipCmd, CmdReset);
4343
Francois Romieuffc46952012-07-06 14:19:23 +02004344 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004345}
4346
Francois Romieub6ffd972011-06-17 17:00:05 +02004347static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4348{
4349 struct rtl_fw *rtl_fw;
4350 const char *name;
4351 int rc = -ENOMEM;
4352
4353 name = rtl_lookup_firmware_name(tp);
4354 if (!name)
4355 goto out_no_firmware;
4356
4357 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4358 if (!rtl_fw)
4359 goto err_warn;
4360
4361 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4362 if (rc < 0)
4363 goto err_free;
4364
Francois Romieufd112f22011-06-18 00:10:29 +02004365 rc = rtl_check_firmware(tp, rtl_fw);
4366 if (rc < 0)
4367 goto err_release_firmware;
4368
Francois Romieub6ffd972011-06-17 17:00:05 +02004369 tp->rtl_fw = rtl_fw;
4370out:
4371 return;
4372
Francois Romieufd112f22011-06-18 00:10:29 +02004373err_release_firmware:
4374 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004375err_free:
4376 kfree(rtl_fw);
4377err_warn:
4378 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4379 name, rc);
4380out_no_firmware:
4381 tp->rtl_fw = NULL;
4382 goto out;
4383}
4384
François Romieu953a12c2011-04-24 17:38:48 +02004385static void rtl_request_firmware(struct rtl8169_private *tp)
4386{
Francois Romieub6ffd972011-06-17 17:00:05 +02004387 if (IS_ERR(tp->rtl_fw))
4388 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004389}
4390
Hayes Wang92fc43b2011-07-06 15:58:03 +08004391static void rtl_rx_close(struct rtl8169_private *tp)
4392{
4393 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004394
Francois Romieu1687b562011-07-19 17:21:29 +02004395 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004396}
4397
Francois Romieuffc46952012-07-06 14:19:23 +02004398DECLARE_RTL_COND(rtl_npq_cond)
4399{
4400 void __iomem *ioaddr = tp->mmio_addr;
4401
4402 return RTL_R8(TxPoll) & NPQ;
4403}
4404
4405DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4406{
4407 void __iomem *ioaddr = tp->mmio_addr;
4408
4409 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4410}
4411
françois romieue6de30d2011-01-03 15:08:37 +00004412static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413{
françois romieue6de30d2011-01-03 15:08:37 +00004414 void __iomem *ioaddr = tp->mmio_addr;
4415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004417 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Hayes Wang92fc43b2011-07-06 15:58:03 +08004419 rtl_rx_close(tp);
4420
Hayes Wang5d2e1952011-02-22 17:26:22 +08004421 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004422 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4423 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004424 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004425 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4426 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004427 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004428 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004429 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4430 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004431 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004432 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004433 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004434 } else {
4435 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4436 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004437 }
4438
Hayes Wang92fc43b2011-07-06 15:58:03 +08004439 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440}
4441
Francois Romieu7f796d832007-06-11 23:04:41 +02004442static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004443{
4444 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004445
4446 /* Set DMA burst size and Interframe Gap Time */
4447 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4448 (InterFrameGap << TxInterFrameGapShift));
4449}
4450
Francois Romieu07ce4062007-02-23 23:36:39 +01004451static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452{
4453 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Francois Romieu07ce4062007-02-23 23:36:39 +01004455 tp->hw_start(dev);
4456
Francois Romieuda78dbf2012-01-26 14:18:23 +01004457 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004458}
4459
Francois Romieu7f796d832007-06-11 23:04:41 +02004460static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4461 void __iomem *ioaddr)
4462{
4463 /*
4464 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4465 * register to be written before TxDescAddrLow to work.
4466 * Switching from MMIO to I/O access fixes the issue as well.
4467 */
4468 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004469 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004470 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004471 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004472}
4473
4474static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4475{
4476 u16 cmd;
4477
4478 cmd = RTL_R16(CPlusCmd);
4479 RTL_W16(CPlusCmd, cmd);
4480 return cmd;
4481}
4482
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004483static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004484{
4485 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e82009-10-26 10:52:37 +00004486 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004487}
4488
Francois Romieu6dccd162007-02-13 23:38:05 +01004489static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4490{
Francois Romieu37441002011-06-17 22:58:54 +02004491 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004492 u32 mac_version;
4493 u32 clk;
4494 u32 val;
4495 } cfg2_info [] = {
4496 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4497 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4498 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4499 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004500 };
4501 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004502 unsigned int i;
4503 u32 clk;
4504
4505 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004506 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004507 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4508 RTL_W32(0x7c, p->val);
4509 break;
4510 }
4511 }
4512}
4513
Francois Romieue6b763e2012-03-08 09:35:39 +01004514static void rtl_set_rx_mode(struct net_device *dev)
4515{
4516 struct rtl8169_private *tp = netdev_priv(dev);
4517 void __iomem *ioaddr = tp->mmio_addr;
4518 u32 mc_filter[2]; /* Multicast hash filter */
4519 int rx_mode;
4520 u32 tmp = 0;
4521
4522 if (dev->flags & IFF_PROMISC) {
4523 /* Unconditionally log net taps. */
4524 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4525 rx_mode =
4526 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4527 AcceptAllPhys;
4528 mc_filter[1] = mc_filter[0] = 0xffffffff;
4529 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4530 (dev->flags & IFF_ALLMULTI)) {
4531 /* Too many to filter perfectly -- accept all multicasts. */
4532 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4533 mc_filter[1] = mc_filter[0] = 0xffffffff;
4534 } else {
4535 struct netdev_hw_addr *ha;
4536
4537 rx_mode = AcceptBroadcast | AcceptMyPhys;
4538 mc_filter[1] = mc_filter[0] = 0;
4539 netdev_for_each_mc_addr(ha, dev) {
4540 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4541 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4542 rx_mode |= AcceptMulticast;
4543 }
4544 }
4545
4546 if (dev->features & NETIF_F_RXALL)
4547 rx_mode |= (AcceptErr | AcceptRunt);
4548
4549 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4550
4551 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4552 u32 data = mc_filter[0];
4553
4554 mc_filter[0] = swab32(mc_filter[1]);
4555 mc_filter[1] = swab32(data);
4556 }
4557
4558 RTL_W32(MAR0 + 4, mc_filter[1]);
4559 RTL_W32(MAR0 + 0, mc_filter[0]);
4560
4561 RTL_W32(RxConfig, tmp);
4562}
4563
Francois Romieu07ce4062007-02-23 23:36:39 +01004564static void rtl_hw_start_8169(struct net_device *dev)
4565{
4566 struct rtl8169_private *tp = netdev_priv(dev);
4567 void __iomem *ioaddr = tp->mmio_addr;
4568 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004569
Francois Romieu9cb427b2006-11-02 00:10:16 +01004570 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4571 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4572 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4573 }
4574
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004576 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4577 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4578 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4579 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004580 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4581
Hayes Wange542a222011-07-06 15:58:04 +08004582 rtl_init_rxcfg(tp);
4583
françois romieuf0298f82011-01-03 15:07:42 +00004584 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004586 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587
Francois Romieucecb5fd2011-04-01 10:21:07 +02004588 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4589 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4590 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4591 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004592 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593
Francois Romieu7f796d832007-06-11 23:04:41 +02004594 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004595
Francois Romieucecb5fd2011-04-01 10:21:07 +02004596 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4597 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004598 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004600 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 }
4602
Francois Romieubcf0bf92006-07-26 23:14:13 +02004603 RTL_W16(CPlusCmd, tp->cp_cmd);
4604
Francois Romieu6dccd162007-02-13 23:38:05 +01004605 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4606
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 /*
4608 * Undocumented corner. Supposedly:
4609 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4610 */
4611 RTL_W16(IntrMitigate, 0x0000);
4612
Francois Romieu7f796d832007-06-11 23:04:41 +02004613 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004614
Francois Romieucecb5fd2011-04-01 10:21:07 +02004615 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4616 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4617 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4618 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004619 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4620 rtl_set_rx_tx_config_registers(tp);
4621 }
4622
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004624
4625 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4626 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
4628 RTL_W32(RxMissed, 0);
4629
Francois Romieu07ce4062007-02-23 23:36:39 +01004630 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
4632 /* no early-rx interrupts */
4633 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004636static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4637{
4638 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004639 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004640}
4641
4642static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4643{
Francois Romieu52989f02012-07-06 13:37:00 +02004644 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004645}
4646
4647static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004648{
4649 u32 csi;
4650
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004651 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4652 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004653}
4654
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004655static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004656{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004657 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004658}
4659
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004660static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004661{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004662 rtl_csi_access_enable(tp, 0x27000000);
4663}
4664
Francois Romieuffc46952012-07-06 14:19:23 +02004665DECLARE_RTL_COND(rtl_csiar_cond)
4666{
4667 void __iomem *ioaddr = tp->mmio_addr;
4668
4669 return RTL_R32(CSIAR) & CSIAR_FLAG;
4670}
4671
Francois Romieu52989f02012-07-06 13:37:00 +02004672static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004673{
Francois Romieu52989f02012-07-06 13:37:00 +02004674 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004675
4676 RTL_W32(CSIDR, value);
4677 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4678 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4679
Francois Romieuffc46952012-07-06 14:19:23 +02004680 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004681}
4682
Francois Romieu52989f02012-07-06 13:37:00 +02004683static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004684{
Francois Romieu52989f02012-07-06 13:37:00 +02004685 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004686
4687 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4688 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4689
Francois Romieuffc46952012-07-06 14:19:23 +02004690 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4691 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004692}
4693
Francois Romieu52989f02012-07-06 13:37:00 +02004694static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004695{
Francois Romieu52989f02012-07-06 13:37:00 +02004696 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004697
4698 RTL_W32(CSIDR, value);
4699 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4700 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4701 CSIAR_FUNC_NIC);
4702
Francois Romieuffc46952012-07-06 14:19:23 +02004703 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004704}
4705
Francois Romieu52989f02012-07-06 13:37:00 +02004706static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004707{
Francois Romieu52989f02012-07-06 13:37:00 +02004708 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004709
4710 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4711 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4712
Francois Romieuffc46952012-07-06 14:19:23 +02004713 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4714 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004715}
4716
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004717static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
4718{
4719 struct csi_ops *ops = &tp->csi_ops;
4720
4721 switch (tp->mac_version) {
4722 case RTL_GIGA_MAC_VER_01:
4723 case RTL_GIGA_MAC_VER_02:
4724 case RTL_GIGA_MAC_VER_03:
4725 case RTL_GIGA_MAC_VER_04:
4726 case RTL_GIGA_MAC_VER_05:
4727 case RTL_GIGA_MAC_VER_06:
4728 case RTL_GIGA_MAC_VER_10:
4729 case RTL_GIGA_MAC_VER_11:
4730 case RTL_GIGA_MAC_VER_12:
4731 case RTL_GIGA_MAC_VER_13:
4732 case RTL_GIGA_MAC_VER_14:
4733 case RTL_GIGA_MAC_VER_15:
4734 case RTL_GIGA_MAC_VER_16:
4735 case RTL_GIGA_MAC_VER_17:
4736 ops->write = NULL;
4737 ops->read = NULL;
4738 break;
4739
Hayes Wang7e18dca2012-03-30 14:33:02 +08004740 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004741 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004742 ops->write = r8402_csi_write;
4743 ops->read = r8402_csi_read;
4744 break;
4745
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004746 default:
4747 ops->write = r8169_csi_write;
4748 ops->read = r8169_csi_read;
4749 break;
4750 }
Francois Romieudacf8152008-08-02 20:44:13 +02004751}
4752
4753struct ephy_info {
4754 unsigned int offset;
4755 u16 mask;
4756 u16 bits;
4757};
4758
Francois Romieufdf6fc02012-07-06 22:40:38 +02004759static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4760 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004761{
4762 u16 w;
4763
4764 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004765 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4766 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004767 e++;
4768 }
4769}
4770
Francois Romieub726e492008-06-28 12:22:59 +02004771static void rtl_disable_clock_request(struct pci_dev *pdev)
4772{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004773 pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
4774 PCI_EXP_LNKCTL_CLKREQ_EN);
Francois Romieub726e492008-06-28 12:22:59 +02004775}
4776
françois romieue6de30d2011-01-03 15:08:37 +00004777static void rtl_enable_clock_request(struct pci_dev *pdev)
4778{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004779 pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
4780 PCI_EXP_LNKCTL_CLKREQ_EN);
françois romieue6de30d2011-01-03 15:08:37 +00004781}
4782
Francois Romieub726e492008-06-28 12:22:59 +02004783#define R8168_CPCMD_QUIRK_MASK (\
4784 EnableBist | \
4785 Mac_dbgo_oe | \
4786 Force_half_dup | \
4787 Force_rxflow_en | \
4788 Force_txflow_en | \
4789 Cxpl_dbg_sel | \
4790 ASF | \
4791 PktCntrDisable | \
4792 Mac_dbgo_sel)
4793
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004794static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004795{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004796 void __iomem *ioaddr = tp->mmio_addr;
4797 struct pci_dev *pdev = tp->pci_dev;
4798
Francois Romieub726e492008-06-28 12:22:59 +02004799 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4800
4801 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4802
Francois Romieu2e68ae42008-06-28 12:00:55 +02004803 rtl_tx_performance_tweak(pdev,
4804 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004805}
4806
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004807static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004808{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004809 void __iomem *ioaddr = tp->mmio_addr;
4810
4811 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004812
françois romieuf0298f82011-01-03 15:07:42 +00004813 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004814
4815 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004816}
4817
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004818static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004819{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004820 void __iomem *ioaddr = tp->mmio_addr;
4821 struct pci_dev *pdev = tp->pci_dev;
4822
Francois Romieub726e492008-06-28 12:22:59 +02004823 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4824
4825 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4826
Francois Romieu219a1e92008-06-28 11:58:39 +02004827 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004828
4829 rtl_disable_clock_request(pdev);
4830
4831 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004832}
4833
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004834static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004835{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004836 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004837 { 0x01, 0, 0x0001 },
4838 { 0x02, 0x0800, 0x1000 },
4839 { 0x03, 0, 0x0042 },
4840 { 0x06, 0x0080, 0x0000 },
4841 { 0x07, 0, 0x2000 }
4842 };
4843
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004844 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004845
Francois Romieufdf6fc02012-07-06 22:40:38 +02004846 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004847
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004848 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004849}
4850
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004851static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004852{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004853 void __iomem *ioaddr = tp->mmio_addr;
4854 struct pci_dev *pdev = tp->pci_dev;
4855
4856 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004857
4858 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4859
4860 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4861
4862 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4863}
4864
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004865static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004866{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004867 void __iomem *ioaddr = tp->mmio_addr;
4868 struct pci_dev *pdev = tp->pci_dev;
4869
4870 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004871
4872 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4873
4874 /* Magic. */
4875 RTL_W8(DBG_REG, 0x20);
4876
françois romieuf0298f82011-01-03 15:07:42 +00004877 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004878
4879 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4880
4881 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4882}
4883
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004884static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004885{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004886 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004887 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004888 { 0x02, 0x0800, 0x1000 },
4889 { 0x03, 0, 0x0002 },
4890 { 0x06, 0x0080, 0x0000 }
4891 };
4892
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004893 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004894
4895 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4896
Francois Romieufdf6fc02012-07-06 22:40:38 +02004897 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004898
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004899 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004900}
4901
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004902static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004903{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004904 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004905 { 0x01, 0, 0x0001 },
4906 { 0x03, 0x0400, 0x0220 }
4907 };
4908
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004909 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004910
Francois Romieufdf6fc02012-07-06 22:40:38 +02004911 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004912
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004913 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004914}
4915
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004916static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004917{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004918 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004919}
4920
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004921static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004922{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004923 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004924
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004925 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004926}
4927
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004928static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004929{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004930 void __iomem *ioaddr = tp->mmio_addr;
4931 struct pci_dev *pdev = tp->pci_dev;
4932
4933 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004934
4935 rtl_disable_clock_request(pdev);
4936
françois romieuf0298f82011-01-03 15:07:42 +00004937 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004938
4939 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4940
4941 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4942}
4943
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004944static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004945{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004946 void __iomem *ioaddr = tp->mmio_addr;
4947 struct pci_dev *pdev = tp->pci_dev;
4948
4949 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004950
4951 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4952
4953 RTL_W8(MaxTxPacketSize, TxPacketMax);
4954
4955 rtl_disable_clock_request(pdev);
4956}
4957
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004958static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004959{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004960 void __iomem *ioaddr = tp->mmio_addr;
4961 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004962 static const struct ephy_info e_info_8168d_4[] = {
4963 { 0x0b, ~0, 0x48 },
4964 { 0x19, 0x20, 0x50 },
4965 { 0x0c, ~0, 0x20 }
4966 };
4967 int i;
4968
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004969 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004970
4971 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4972
4973 RTL_W8(MaxTxPacketSize, TxPacketMax);
4974
4975 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4976 const struct ephy_info *e = e_info_8168d_4 + i;
4977 u16 w;
4978
Francois Romieufdf6fc02012-07-06 22:40:38 +02004979 w = rtl_ephy_read(tp, e->offset);
4980 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004981 }
4982
4983 rtl_enable_clock_request(pdev);
4984}
4985
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004986static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004987{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004988 void __iomem *ioaddr = tp->mmio_addr;
4989 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004990 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004991 { 0x00, 0x0200, 0x0100 },
4992 { 0x00, 0x0000, 0x0004 },
4993 { 0x06, 0x0002, 0x0001 },
4994 { 0x06, 0x0000, 0x0030 },
4995 { 0x07, 0x0000, 0x2000 },
4996 { 0x00, 0x0000, 0x0020 },
4997 { 0x03, 0x5800, 0x2000 },
4998 { 0x03, 0x0000, 0x0001 },
4999 { 0x01, 0x0800, 0x1000 },
5000 { 0x07, 0x0000, 0x4000 },
5001 { 0x1e, 0x0000, 0x2000 },
5002 { 0x19, 0xffff, 0xfe6c },
5003 { 0x0a, 0x0000, 0x0040 }
5004 };
5005
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005006 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005007
Francois Romieufdf6fc02012-07-06 22:40:38 +02005008 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00005009
5010 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5011
5012 RTL_W8(MaxTxPacketSize, TxPacketMax);
5013
5014 rtl_disable_clock_request(pdev);
5015
5016 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02005017 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
5018 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00005019
Francois Romieucecb5fd2011-04-01 10:21:07 +02005020 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00005021}
5022
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005023static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08005024{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005025 void __iomem *ioaddr = tp->mmio_addr;
5026 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08005027 static const struct ephy_info e_info_8168e_2[] = {
5028 { 0x09, 0x0000, 0x0080 },
5029 { 0x19, 0x0000, 0x0224 }
5030 };
5031
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005032 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005033
Francois Romieufdf6fc02012-07-06 22:40:38 +02005034 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08005035
5036 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5037
Francois Romieufdf6fc02012-07-06 22:40:38 +02005038 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5039 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5040 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5041 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5042 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5043 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5044 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5045 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005046
Hayes Wang3090bd92011-09-06 16:55:15 +08005047 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005048
5049 rtl_disable_clock_request(pdev);
5050
5051 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5052 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5053
5054 /* Adjust EEE LED frequency */
5055 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5056
5057 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5058 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5059 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5060}
5061
Hayes Wang5f886e02012-03-30 14:33:03 +08005062static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005063{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005064 void __iomem *ioaddr = tp->mmio_addr;
5065 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005066
Hayes Wang5f886e02012-03-30 14:33:03 +08005067 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005068
5069 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5070
Francois Romieufdf6fc02012-07-06 22:40:38 +02005071 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5072 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5073 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5074 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5075 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5076 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5077 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5078 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5079 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5080 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005081
5082 RTL_W8(MaxTxPacketSize, EarlySize);
5083
5084 rtl_disable_clock_request(pdev);
5085
5086 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5087 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005088 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5089 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5090 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5091}
5092
Hayes Wang5f886e02012-03-30 14:33:03 +08005093static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5094{
5095 void __iomem *ioaddr = tp->mmio_addr;
5096 static const struct ephy_info e_info_8168f_1[] = {
5097 { 0x06, 0x00c0, 0x0020 },
5098 { 0x08, 0x0001, 0x0002 },
5099 { 0x09, 0x0000, 0x0080 },
5100 { 0x19, 0x0000, 0x0224 }
5101 };
5102
5103 rtl_hw_start_8168f(tp);
5104
Francois Romieufdf6fc02012-07-06 22:40:38 +02005105 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005106
Francois Romieufdf6fc02012-07-06 22:40:38 +02005107 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005108
5109 /* Adjust EEE LED frequency */
5110 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5111}
5112
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005113static void rtl_hw_start_8411(struct rtl8169_private *tp)
5114{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005115 static const struct ephy_info e_info_8168f_1[] = {
5116 { 0x06, 0x00c0, 0x0020 },
5117 { 0x0f, 0xffff, 0x5200 },
5118 { 0x1e, 0x0000, 0x4000 },
5119 { 0x19, 0x0000, 0x0224 }
5120 };
5121
5122 rtl_hw_start_8168f(tp);
5123
Francois Romieufdf6fc02012-07-06 22:40:38 +02005124 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005125
Francois Romieufdf6fc02012-07-06 22:40:38 +02005126 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005127}
5128
Hayes Wangc5583862012-07-02 17:23:22 +08005129static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5130{
5131 void __iomem *ioaddr = tp->mmio_addr;
5132 struct pci_dev *pdev = tp->pci_dev;
5133
5134 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5135 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5136 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5137 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5138
5139 rtl_csi_access_enable_1(tp);
5140
5141 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5142
5143 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5144 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5145
5146 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5147 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
5148 RTL_W8(MaxTxPacketSize, EarlySize);
5149
5150 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5151 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5152
5153 /* Adjust EEE LED frequency */
5154 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5155
5156 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5157}
5158
Francois Romieu07ce4062007-02-23 23:36:39 +01005159static void rtl_hw_start_8168(struct net_device *dev)
5160{
Francois Romieu2dd99532007-06-11 23:22:52 +02005161 struct rtl8169_private *tp = netdev_priv(dev);
5162 void __iomem *ioaddr = tp->mmio_addr;
5163
5164 RTL_W8(Cfg9346, Cfg9346_Unlock);
5165
françois romieuf0298f82011-01-03 15:07:42 +00005166 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005167
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005168 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005169
Francois Romieu0e485152007-02-20 00:00:26 +01005170 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005171
5172 RTL_W16(CPlusCmd, tp->cp_cmd);
5173
Francois Romieu0e485152007-02-20 00:00:26 +01005174 RTL_W16(IntrMitigate, 0x5151);
5175
5176 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005177 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005178 tp->event_slow |= RxFIFOOver | PCSTimeout;
5179 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005180 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005181
5182 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5183
Francois Romieub8363902008-06-01 12:31:57 +02005184 rtl_set_rx_mode(dev);
5185
5186 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5187 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005188
5189 RTL_R8(IntrMask);
5190
Francois Romieu219a1e92008-06-28 11:58:39 +02005191 switch (tp->mac_version) {
5192 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005193 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005194 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005195
5196 case RTL_GIGA_MAC_VER_12:
5197 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005198 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005199 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005200
5201 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005202 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005203 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005204
5205 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005206 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005207 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005208
5209 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005210 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005211 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005212
Francois Romieu197ff762008-06-28 13:16:02 +02005213 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005214 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005215 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005216
Francois Romieu6fb07052008-06-29 11:54:28 +02005217 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005218 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005219 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005220
Francois Romieuef3386f2008-06-29 12:24:30 +02005221 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005222 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005223 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005224
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005225 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005226 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005227 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005228
Francois Romieu5b538df2008-07-20 16:22:45 +02005229 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005230 case RTL_GIGA_MAC_VER_26:
5231 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005232 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005233 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005234
françois romieue6de30d2011-01-03 15:08:37 +00005235 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005236 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005237 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005238
hayeswang4804b3b2011-03-21 01:50:29 +00005239 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005240 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005241 break;
5242
hayeswang01dc7fe2011-03-21 01:50:28 +00005243 case RTL_GIGA_MAC_VER_32:
5244 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005245 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005246 break;
5247 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005248 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005249 break;
françois romieue6de30d2011-01-03 15:08:37 +00005250
Hayes Wangc2218922011-09-06 16:55:18 +08005251 case RTL_GIGA_MAC_VER_35:
5252 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005253 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005254 break;
5255
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005256 case RTL_GIGA_MAC_VER_38:
5257 rtl_hw_start_8411(tp);
5258 break;
5259
Hayes Wangc5583862012-07-02 17:23:22 +08005260 case RTL_GIGA_MAC_VER_40:
5261 case RTL_GIGA_MAC_VER_41:
5262 rtl_hw_start_8168g_1(tp);
5263 break;
5264
Francois Romieu219a1e92008-06-28 11:58:39 +02005265 default:
5266 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5267 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005268 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005269 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005270
Francois Romieu0e485152007-02-20 00:00:26 +01005271 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5272
Francois Romieub8363902008-06-01 12:31:57 +02005273 RTL_W8(Cfg9346, Cfg9346_Lock);
5274
Francois Romieu2dd99532007-06-11 23:22:52 +02005275 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005276}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
Francois Romieu2857ffb2008-08-02 21:08:49 +02005278#define R810X_CPCMD_QUIRK_MASK (\
5279 EnableBist | \
5280 Mac_dbgo_oe | \
5281 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005282 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005283 Force_txflow_en | \
5284 Cxpl_dbg_sel | \
5285 ASF | \
5286 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005287 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005288
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005289static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005290{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005291 void __iomem *ioaddr = tp->mmio_addr;
5292 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005293 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005294 { 0x01, 0, 0x6e65 },
5295 { 0x02, 0, 0x091f },
5296 { 0x03, 0, 0xc2f9 },
5297 { 0x06, 0, 0xafb5 },
5298 { 0x07, 0, 0x0e00 },
5299 { 0x19, 0, 0xec80 },
5300 { 0x01, 0, 0x2e65 },
5301 { 0x01, 0, 0x6e65 }
5302 };
5303 u8 cfg1;
5304
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005305 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005306
5307 RTL_W8(DBG_REG, FIX_NAK_1);
5308
5309 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5310
5311 RTL_W8(Config1,
5312 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5313 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5314
5315 cfg1 = RTL_R8(Config1);
5316 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5317 RTL_W8(Config1, cfg1 & ~LEDS0);
5318
Francois Romieufdf6fc02012-07-06 22:40:38 +02005319 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005320}
5321
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005322static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005323{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005324 void __iomem *ioaddr = tp->mmio_addr;
5325 struct pci_dev *pdev = tp->pci_dev;
5326
5327 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005328
5329 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5330
5331 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5332 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005333}
5334
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005335static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005336{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005337 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005338
Francois Romieufdf6fc02012-07-06 22:40:38 +02005339 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005340}
5341
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005342static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005343{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005344 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005345 static const struct ephy_info e_info_8105e_1[] = {
5346 { 0x07, 0, 0x4000 },
5347 { 0x19, 0, 0x0200 },
5348 { 0x19, 0, 0x0020 },
5349 { 0x1e, 0, 0x2000 },
5350 { 0x03, 0, 0x0001 },
5351 { 0x19, 0, 0x0100 },
5352 { 0x19, 0, 0x0004 },
5353 { 0x0a, 0, 0x0020 }
5354 };
5355
Francois Romieucecb5fd2011-04-01 10:21:07 +02005356 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005357 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5358
Francois Romieucecb5fd2011-04-01 10:21:07 +02005359 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005360 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5361
5362 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e2011-07-06 15:58:02 +08005363 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005364
Francois Romieufdf6fc02012-07-06 22:40:38 +02005365 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005366}
5367
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005368static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005369{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005370 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005371 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005372}
5373
Hayes Wang7e18dca2012-03-30 14:33:02 +08005374static void rtl_hw_start_8402(struct rtl8169_private *tp)
5375{
5376 void __iomem *ioaddr = tp->mmio_addr;
5377 static const struct ephy_info e_info_8402[] = {
5378 { 0x19, 0xffff, 0xff64 },
5379 { 0x1e, 0, 0x4000 }
5380 };
5381
5382 rtl_csi_access_enable_2(tp);
5383
5384 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5385 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5386
5387 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5388 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5389
Francois Romieufdf6fc02012-07-06 22:40:38 +02005390 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005391
5392 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5393
Francois Romieufdf6fc02012-07-06 22:40:38 +02005394 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5395 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5396 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5397 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5398 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5399 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5400 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005401}
5402
Hayes Wang5598bfe2012-07-02 17:23:21 +08005403static void rtl_hw_start_8106(struct rtl8169_private *tp)
5404{
5405 void __iomem *ioaddr = tp->mmio_addr;
5406
5407 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5408 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5409
5410 RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
5411 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5412 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5413}
5414
Francois Romieu07ce4062007-02-23 23:36:39 +01005415static void rtl_hw_start_8101(struct net_device *dev)
5416{
Francois Romieucdf1a602007-06-11 23:29:50 +02005417 struct rtl8169_private *tp = netdev_priv(dev);
5418 void __iomem *ioaddr = tp->mmio_addr;
5419 struct pci_dev *pdev = tp->pci_dev;
5420
Francois Romieuda78dbf2012-01-26 14:18:23 +01005421 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5422 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005423
Francois Romieucecb5fd2011-04-01 10:21:07 +02005424 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
Jiang Liu7d7903b2012-07-24 17:20:16 +08005425 tp->mac_version == RTL_GIGA_MAC_VER_16)
Bjorn Helgaas8200bc72012-08-22 10:29:42 -06005426 pcie_capability_set_word(pdev, PCI_EXP_DEVCTL,
5427 PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieucdf1a602007-06-11 23:29:50 +02005428
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005429 RTL_W8(Cfg9346, Cfg9346_Unlock);
5430
Francois Romieu2857ffb2008-08-02 21:08:49 +02005431 switch (tp->mac_version) {
5432 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005433 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005434 break;
5435
5436 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005437 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005438 break;
5439
5440 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005441 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005442 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005443
5444 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005445 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005446 break;
5447 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005448 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005449 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005450
5451 case RTL_GIGA_MAC_VER_37:
5452 rtl_hw_start_8402(tp);
5453 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005454
5455 case RTL_GIGA_MAC_VER_39:
5456 rtl_hw_start_8106(tp);
5457 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005458 }
5459
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005460 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005461
françois romieuf0298f82011-01-03 15:07:42 +00005462 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005463
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005464 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005465
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005466 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005467 RTL_W16(CPlusCmd, tp->cp_cmd);
5468
5469 RTL_W16(IntrMitigate, 0x0000);
5470
5471 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5472
5473 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5474 rtl_set_rx_tx_config_registers(tp);
5475
Francois Romieucdf1a602007-06-11 23:29:50 +02005476 RTL_R8(IntrMask);
5477
Francois Romieucdf1a602007-06-11 23:29:50 +02005478 rtl_set_rx_mode(dev);
5479
5480 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481}
5482
5483static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5484{
Francois Romieud58d46b2011-05-03 16:38:29 +02005485 struct rtl8169_private *tp = netdev_priv(dev);
5486
5487 if (new_mtu < ETH_ZLEN ||
5488 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 return -EINVAL;
5490
Francois Romieud58d46b2011-05-03 16:38:29 +02005491 if (new_mtu > ETH_DATA_LEN)
5492 rtl_hw_jumbo_enable(tp);
5493 else
5494 rtl_hw_jumbo_disable(tp);
5495
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005497 netdev_update_features(dev);
5498
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005499 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500}
5501
5502static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5503{
Al Viro95e09182007-12-22 18:55:39 +00005504 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5506}
5507
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005508static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5509 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005511 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005512 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005513
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005514 kfree(*data_buff);
5515 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 rtl8169_make_unusable_by_asic(desc);
5517}
5518
5519static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5520{
5521 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5522
5523 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5524}
5525
5526static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5527 u32 rx_buf_sz)
5528{
5529 desc->addr = cpu_to_le64(mapping);
5530 wmb();
5531 rtl8169_mark_to_asic(desc, rx_buf_sz);
5532}
5533
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005534static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005536 return (void *)ALIGN((long)data, 16);
5537}
5538
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005539static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5540 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005541{
5542 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005544 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005545 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005546 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005548 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5549 if (!data)
5550 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005551
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005552 if (rtl8169_align(data) != data) {
5553 kfree(data);
5554 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5555 if (!data)
5556 return NULL;
5557 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005558
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005559 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005560 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005561 if (unlikely(dma_mapping_error(d, mapping))) {
5562 if (net_ratelimit())
5563 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005564 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
5567 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005568 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005569
5570err_out:
5571 kfree(data);
5572 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573}
5574
5575static void rtl8169_rx_clear(struct rtl8169_private *tp)
5576{
Francois Romieu07d3f512007-02-21 22:40:46 +01005577 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
5579 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005580 if (tp->Rx_databuff[i]) {
5581 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 tp->RxDescArray + i);
5583 }
5584 }
5585}
5586
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005587static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005589 desc->opts1 |= cpu_to_le32(RingEnd);
5590}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005591
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005592static int rtl8169_rx_fill(struct rtl8169_private *tp)
5593{
5594 unsigned int i;
5595
5596 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005597 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005598
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005599 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005601
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005602 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005603 if (!data) {
5604 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005605 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005606 }
5607 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005610 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5611 return 0;
5612
5613err_out:
5614 rtl8169_rx_clear(tp);
5615 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616}
5617
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618static int rtl8169_init_ring(struct net_device *dev)
5619{
5620 struct rtl8169_private *tp = netdev_priv(dev);
5621
5622 rtl8169_init_ring_indexes(tp);
5623
5624 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005625 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005627 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628}
5629
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005630static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 struct TxDesc *desc)
5632{
5633 unsigned int len = tx_skb->len;
5634
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005635 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5636
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 desc->opts1 = 0x00;
5638 desc->opts2 = 0x00;
5639 desc->addr = 0x00;
5640 tx_skb->len = 0;
5641}
5642
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005643static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5644 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645{
5646 unsigned int i;
5647
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005648 for (i = 0; i < n; i++) {
5649 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 struct ring_info *tx_skb = tp->tx_skb + entry;
5651 unsigned int len = tx_skb->len;
5652
5653 if (len) {
5654 struct sk_buff *skb = tx_skb->skb;
5655
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005656 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 tp->TxDescArray + entry);
5658 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005659 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 dev_kfree_skb(skb);
5661 tx_skb->skb = NULL;
5662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 }
5664 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005665}
5666
5667static void rtl8169_tx_clear(struct rtl8169_private *tp)
5668{
5669 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 tp->cur_tx = tp->dirty_tx = 0;
5671}
5672
Francois Romieu4422bcd2012-01-26 11:23:32 +01005673static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674{
David Howellsc4028952006-11-22 14:57:56 +00005675 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005676 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677
Francois Romieuda78dbf2012-01-26 14:18:23 +01005678 napi_disable(&tp->napi);
5679 netif_stop_queue(dev);
5680 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
françois romieuc7c2c392011-12-04 20:30:52 +00005682 rtl8169_hw_reset(tp);
5683
Francois Romieu56de4142011-03-15 17:29:31 +01005684 for (i = 0; i < NUM_RX_DESC; i++)
5685 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5686
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005688 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
Francois Romieuda78dbf2012-01-26 14:18:23 +01005690 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005691 rtl_hw_start(dev);
5692 netif_wake_queue(dev);
5693 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694}
5695
5696static void rtl8169_tx_timeout(struct net_device *dev)
5697{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005698 struct rtl8169_private *tp = netdev_priv(dev);
5699
5700 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701}
5702
5703static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005704 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705{
5706 struct skb_shared_info *info = skb_shinfo(skb);
5707 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005708 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005709 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710
5711 entry = tp->cur_tx;
5712 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005713 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714 dma_addr_t mapping;
5715 u32 status, len;
5716 void *addr;
5717
5718 entry = (entry + 1) % NUM_TX_DESC;
5719
5720 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005721 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005722 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005723 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005724 if (unlikely(dma_mapping_error(d, mapping))) {
5725 if (net_ratelimit())
5726 netif_err(tp, drv, tp->dev,
5727 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005728 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730
Francois Romieucecb5fd2011-04-01 10:21:07 +02005731 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005732 status = opts[0] | len |
5733 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734
5735 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005736 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 txd->addr = cpu_to_le64(mapping);
5738
5739 tp->tx_skb[entry].len = len;
5740 }
5741
5742 if (cur_frag) {
5743 tp->tx_skb[entry].skb = skb;
5744 txd->opts1 |= cpu_to_le32(LastFrag);
5745 }
5746
5747 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005748
5749err_out:
5750 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5751 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752}
5753
Francois Romieu2b7b4312011-04-18 22:53:24 -07005754static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5755 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005757 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005758 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005759 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
Francois Romieu2b7b4312011-04-18 22:53:24 -07005761 if (mss) {
5762 opts[0] |= TD_LSO;
5763 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5764 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005765 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
5767 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005768 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005770 opts[offset] |= info->checksum.udp;
5771 else
5772 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774}
5775
Stephen Hemminger613573252009-08-31 19:50:58 +00005776static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5777 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778{
5779 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005780 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 struct TxDesc *txd = tp->TxDescArray + entry;
5782 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005783 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 dma_addr_t mapping;
5785 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005786 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005787 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005788
Julien Ducourthial477206a2012-05-09 00:00:06 +02005789 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005790 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005791 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 }
5793
5794 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005795 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005797 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005798 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005799 if (unlikely(dma_mapping_error(d, mapping))) {
5800 if (net_ratelimit())
5801 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005802 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
5805 tp->tx_skb[entry].len = len;
5806 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
Francois Romieu2b7b4312011-04-18 22:53:24 -07005808 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
5809 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005810
Francois Romieu2b7b4312011-04-18 22:53:24 -07005811 rtl8169_tso_csum(tp, skb, opts);
5812
5813 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005814 if (frags < 0)
5815 goto err_dma_1;
5816 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005817 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005818 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005819 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005820 tp->tx_skb[entry].skb = skb;
5821 }
5822
Francois Romieu2b7b4312011-04-18 22:53:24 -07005823 txd->opts2 = cpu_to_le32(opts[1]);
5824
Richard Cochran5047fb52012-03-10 07:29:42 +00005825 skb_tx_timestamp(skb);
5826
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 wmb();
5828
Francois Romieucecb5fd2011-04-01 10:21:07 +02005829 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005830 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 txd->opts1 = cpu_to_le32(status);
5832
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 tp->cur_tx += frags + 1;
5834
David Dillow4c020a92010-03-03 16:33:10 +00005835 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836
Francois Romieucecb5fd2011-04-01 10:21:07 +02005837 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838
Francois Romieuda78dbf2012-01-26 14:18:23 +01005839 mmiowb();
5840
Julien Ducourthial477206a2012-05-09 00:00:06 +02005841 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005842 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5843 * not miss a ring update when it notices a stopped queue.
5844 */
5845 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005847 /* Sync with rtl_tx:
5848 * - publish queue status and cur_tx ring index (write barrier)
5849 * - refresh dirty_tx ring index (read barrier).
5850 * May the current thread have a pessimistic view of the ring
5851 * status and forget to wake up queue, a racing rtl_tx thread
5852 * can't.
5853 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005854 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005855 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 netif_wake_queue(dev);
5857 }
5858
Stephen Hemminger613573252009-08-31 19:50:58 +00005859 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005861err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005862 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005863err_dma_0:
5864 dev_kfree_skb(skb);
5865 dev->stats.tx_dropped++;
5866 return NETDEV_TX_OK;
5867
5868err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005870 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005871 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872}
5873
5874static void rtl8169_pcierr_interrupt(struct net_device *dev)
5875{
5876 struct rtl8169_private *tp = netdev_priv(dev);
5877 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 u16 pci_status, pci_cmd;
5879
5880 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5881 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5882
Joe Perchesbf82c182010-02-09 11:49:50 +00005883 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5884 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885
5886 /*
5887 * The recovery sequence below admits a very elaborated explanation:
5888 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005889 * - I did not see what else could be done;
5890 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 *
5892 * Feel free to adjust to your needs.
5893 */
Francois Romieua27993f2006-12-18 00:04:19 +01005894 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005895 pci_cmd &= ~PCI_COMMAND_PARITY;
5896 else
5897 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5898
5899 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
5901 pci_write_config_word(pdev, PCI_STATUS,
5902 pci_status & (PCI_STATUS_DETECTED_PARITY |
5903 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5904 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5905
5906 /* The infamous DAC f*ckup only happens at boot time */
5907 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005908 void __iomem *ioaddr = tp->mmio_addr;
5909
Joe Perchesbf82c182010-02-09 11:49:50 +00005910 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 tp->cp_cmd &= ~PCIDAC;
5912 RTL_W16(CPlusCmd, tp->cp_cmd);
5913 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 }
5915
françois romieue6de30d2011-01-03 15:08:37 +00005916 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005917
Francois Romieu98ddf982012-01-31 10:47:34 +01005918 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919}
5920
Francois Romieuda78dbf2012-01-26 14:18:23 +01005921static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922{
5923 unsigned int dirty_tx, tx_left;
5924
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 dirty_tx = tp->dirty_tx;
5926 smp_rmb();
5927 tx_left = tp->cur_tx - dirty_tx;
5928
5929 while (tx_left > 0) {
5930 unsigned int entry = dirty_tx % NUM_TX_DESC;
5931 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 u32 status;
5933
5934 rmb();
5935 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5936 if (status & DescOwn)
5937 break;
5938
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005939 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5940 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005942 u64_stats_update_begin(&tp->tx_stats.syncp);
5943 tp->tx_stats.packets++;
5944 tp->tx_stats.bytes += tx_skb->skb->len;
5945 u64_stats_update_end(&tp->tx_stats.syncp);
5946 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 tx_skb->skb = NULL;
5948 }
5949 dirty_tx++;
5950 tx_left--;
5951 }
5952
5953 if (tp->dirty_tx != dirty_tx) {
5954 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005955 /* Sync with rtl8169_start_xmit:
5956 * - publish dirty_tx ring index (write barrier)
5957 * - refresh cur_tx ring index and queue status (read barrier)
5958 * May the current thread miss the stopped queue condition,
5959 * a racing xmit thread can only have a right view of the
5960 * ring status.
5961 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005962 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005964 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 netif_wake_queue(dev);
5966 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005967 /*
5968 * 8168 hack: TxPoll requests are lost when the Tx packets are
5969 * too close. Let's kick an extra TxPoll request when a burst
5970 * of start_xmit activity is detected (if it is not detected,
5971 * it is slow enough). -- FR
5972 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005973 if (tp->cur_tx != dirty_tx) {
5974 void __iomem *ioaddr = tp->mmio_addr;
5975
Francois Romieud78ae2d2007-08-26 20:08:19 +02005976 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 }
5979}
5980
Francois Romieu126fa4b2005-05-12 20:09:17 -04005981static inline int rtl8169_fragmented_frame(u32 status)
5982{
5983 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5984}
5985
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005986static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 u32 status = opts1 & RxProtoMask;
5989
5990 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005991 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 skb->ip_summed = CHECKSUM_UNNECESSARY;
5993 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005994 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995}
5996
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005997static struct sk_buff *rtl8169_try_rx_copy(void *data,
5998 struct rtl8169_private *tp,
5999 int pkt_size,
6000 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02006002 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00006003 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006005 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00006006 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006007 prefetch(data);
6008 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
6009 if (skb)
6010 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00006011 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
6012
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006013 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014}
6015
Francois Romieuda78dbf2012-01-26 14:18:23 +01006016static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017{
6018 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006019 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 cur_rx = tp->cur_rx;
6022 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02006023 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006024
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006025 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006027 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 u32 status;
6029
6030 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04006031 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
6033 if (status & DescOwn)
6034 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006035 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00006036 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
6037 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006038 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006040 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006042 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006043 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006044 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006045 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006046 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006047 if ((status & (RxRUNT | RxCRC)) &&
6048 !(status & (RxRWT | RxFOVF)) &&
6049 (dev->features & NETIF_F_RXALL))
6050 goto process_pkt;
6051
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006052 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006054 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006055 dma_addr_t addr;
6056 int pkt_size;
6057
6058process_pkt:
6059 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006060 if (likely(!(dev->features & NETIF_F_RXFCS)))
6061 pkt_size = (status & 0x00003fff) - 4;
6062 else
6063 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Francois Romieu126fa4b2005-05-12 20:09:17 -04006065 /*
6066 * The driver does not support incoming fragmented
6067 * frames. They are seen as a symptom of over-mtu
6068 * sized frames.
6069 */
6070 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006071 dev->stats.rx_dropped++;
6072 dev->stats.rx_length_errors++;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006073 rtl8169_mark_to_asic(desc, rx_buf_sz);
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006074 continue;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006075 }
6076
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006077 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6078 tp, pkt_size, addr);
6079 rtl8169_mark_to_asic(desc, rx_buf_sz);
6080 if (!skb) {
6081 dev->stats.rx_dropped++;
6082 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 }
6084
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006085 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 skb_put(skb, pkt_size);
6087 skb->protocol = eth_type_trans(skb, dev);
6088
Francois Romieu7a8fc772011-03-01 17:18:33 +01006089 rtl8169_rx_vlan_tag(desc, skb);
6090
Francois Romieu56de4142011-03-15 17:29:31 +01006091 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Junchang Wang8027aa22012-03-04 23:30:32 +01006093 u64_stats_update_begin(&tp->rx_stats.syncp);
6094 tp->rx_stats.packets++;
6095 tp->rx_stats.bytes += pkt_size;
6096 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 }
Francois Romieu6dccd162007-02-13 23:38:05 +01006098
6099 /* Work around for AMD plateform. */
Al Viro95e09182007-12-22 18:55:39 +00006100 if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
Francois Romieu6dccd162007-02-13 23:38:05 +01006101 (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
6102 desc->opts2 = 0;
6103 cur_rx++;
6104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 }
6106
6107 count = cur_rx - tp->cur_rx;
6108 tp->cur_rx = cur_rx;
6109
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006110 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111
6112 return count;
6113}
6114
Francois Romieu07d3f512007-02-21 22:40:46 +01006115static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116{
Francois Romieu07d3f512007-02-21 22:40:46 +01006117 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006120 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006122 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006123 if (status && status != 0xffff) {
6124 status &= RTL_EVENT_NAPI | tp->event_slow;
6125 if (status) {
6126 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006127
Francois Romieuda78dbf2012-01-26 14:18:23 +01006128 rtl_irq_disable(tp);
6129 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 return IRQ_RETVAL(handled);
6133}
6134
Francois Romieuda78dbf2012-01-26 14:18:23 +01006135/*
6136 * Workqueue context.
6137 */
6138static void rtl_slow_event_work(struct rtl8169_private *tp)
6139{
6140 struct net_device *dev = tp->dev;
6141 u16 status;
6142
6143 status = rtl_get_events(tp) & tp->event_slow;
6144 rtl_ack_events(tp, status);
6145
6146 if (unlikely(status & RxFIFOOver)) {
6147 switch (tp->mac_version) {
6148 /* Work around for rx fifo overflow */
6149 case RTL_GIGA_MAC_VER_11:
6150 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006151 /* XXX - Hack alert. See rtl_task(). */
6152 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006153 default:
6154 break;
6155 }
6156 }
6157
6158 if (unlikely(status & SYSErr))
6159 rtl8169_pcierr_interrupt(dev);
6160
6161 if (status & LinkChg)
6162 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6163
françois romieu7dbb4912012-06-09 10:53:16 +00006164 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006165}
6166
Francois Romieu4422bcd2012-01-26 11:23:32 +01006167static void rtl_task(struct work_struct *work)
6168{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006169 static const struct {
6170 int bitnr;
6171 void (*action)(struct rtl8169_private *);
6172 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006173 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006174 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6175 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6176 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6177 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006178 struct rtl8169_private *tp =
6179 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006180 struct net_device *dev = tp->dev;
6181 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006182
Francois Romieuda78dbf2012-01-26 14:18:23 +01006183 rtl_lock_work(tp);
6184
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006185 if (!netif_running(dev) ||
6186 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006187 goto out_unlock;
6188
6189 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6190 bool pending;
6191
Francois Romieuda78dbf2012-01-26 14:18:23 +01006192 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006193 if (pending)
6194 rtl_work[i].action(tp);
6195 }
6196
6197out_unlock:
6198 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006199}
6200
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006201static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006203 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6204 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006205 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6206 int work_done= 0;
6207 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Francois Romieuda78dbf2012-01-26 14:18:23 +01006209 status = rtl_get_events(tp);
6210 rtl_ack_events(tp, status & ~tp->event_slow);
6211
6212 if (status & RTL_EVENT_NAPI_RX)
6213 work_done = rtl_rx(dev, tp, (u32) budget);
6214
6215 if (status & RTL_EVENT_NAPI_TX)
6216 rtl_tx(dev, tp);
6217
6218 if (status & tp->event_slow) {
6219 enable_mask &= ~tp->event_slow;
6220
6221 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006224 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006225 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006226
Francois Romieuda78dbf2012-01-26 14:18:23 +01006227 rtl_irq_enable(tp, enable_mask);
6228 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229 }
6230
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006231 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233
Francois Romieu523a6092008-09-10 22:28:56 +02006234static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6235{
6236 struct rtl8169_private *tp = netdev_priv(dev);
6237
6238 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6239 return;
6240
6241 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6242 RTL_W32(RxMissed, 0);
6243}
6244
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245static void rtl8169_down(struct net_device *dev)
6246{
6247 struct rtl8169_private *tp = netdev_priv(dev);
6248 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249
Francois Romieu4876cc12011-03-11 21:07:11 +01006250 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006252 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006253 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Hayes Wang92fc43b2011-07-06 15:58:03 +08006255 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006256 /*
6257 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006258 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6259 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006260 */
Francois Romieu523a6092008-09-10 22:28:56 +02006261 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006264 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 rtl8169_tx_clear(tp);
6267
6268 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006269
6270 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271}
6272
6273static int rtl8169_close(struct net_device *dev)
6274{
6275 struct rtl8169_private *tp = netdev_priv(dev);
6276 struct pci_dev *pdev = tp->pci_dev;
6277
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006278 pm_runtime_get_sync(&pdev->dev);
6279
Francois Romieucecb5fd2011-04-01 10:21:07 +02006280 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006281 rtl8169_update_counters(dev);
6282
Francois Romieuda78dbf2012-01-26 14:18:23 +01006283 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006284 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006285
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006287 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006289 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006291 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6292 tp->RxPhyAddr);
6293 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6294 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295 tp->TxDescArray = NULL;
6296 tp->RxDescArray = NULL;
6297
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006298 pm_runtime_put_sync(&pdev->dev);
6299
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 return 0;
6301}
6302
Francois Romieudc1c00c2012-03-08 10:06:18 +01006303#ifdef CONFIG_NET_POLL_CONTROLLER
6304static void rtl8169_netpoll(struct net_device *dev)
6305{
6306 struct rtl8169_private *tp = netdev_priv(dev);
6307
6308 rtl8169_interrupt(tp->pci_dev->irq, dev);
6309}
6310#endif
6311
Francois Romieudf43ac72012-03-08 09:48:40 +01006312static int rtl_open(struct net_device *dev)
6313{
6314 struct rtl8169_private *tp = netdev_priv(dev);
6315 void __iomem *ioaddr = tp->mmio_addr;
6316 struct pci_dev *pdev = tp->pci_dev;
6317 int retval = -ENOMEM;
6318
6319 pm_runtime_get_sync(&pdev->dev);
6320
6321 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006322 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006323 * dma_alloc_coherent provides more.
6324 */
6325 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6326 &tp->TxPhyAddr, GFP_KERNEL);
6327 if (!tp->TxDescArray)
6328 goto err_pm_runtime_put;
6329
6330 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6331 &tp->RxPhyAddr, GFP_KERNEL);
6332 if (!tp->RxDescArray)
6333 goto err_free_tx_0;
6334
6335 retval = rtl8169_init_ring(dev);
6336 if (retval < 0)
6337 goto err_free_rx_1;
6338
6339 INIT_WORK(&tp->wk.work, rtl_task);
6340
6341 smp_mb();
6342
6343 rtl_request_firmware(tp);
6344
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006345 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006346 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6347 dev->name, dev);
6348 if (retval < 0)
6349 goto err_release_fw_2;
6350
6351 rtl_lock_work(tp);
6352
6353 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6354
6355 napi_enable(&tp->napi);
6356
6357 rtl8169_init_phy(dev, tp);
6358
6359 __rtl8169_set_features(dev, dev->features);
6360
6361 rtl_pll_power_up(tp);
6362
6363 rtl_hw_start(dev);
6364
6365 netif_start_queue(dev);
6366
6367 rtl_unlock_work(tp);
6368
6369 tp->saved_wolopts = 0;
6370 pm_runtime_put_noidle(&pdev->dev);
6371
6372 rtl8169_check_link_status(dev, tp, ioaddr);
6373out:
6374 return retval;
6375
6376err_release_fw_2:
6377 rtl_release_firmware(tp);
6378 rtl8169_rx_clear(tp);
6379err_free_rx_1:
6380 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6381 tp->RxPhyAddr);
6382 tp->RxDescArray = NULL;
6383err_free_tx_0:
6384 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6385 tp->TxPhyAddr);
6386 tp->TxDescArray = NULL;
6387err_pm_runtime_put:
6388 pm_runtime_put_noidle(&pdev->dev);
6389 goto out;
6390}
6391
Junchang Wang8027aa22012-03-04 23:30:32 +01006392static struct rtnl_link_stats64 *
6393rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394{
6395 struct rtl8169_private *tp = netdev_priv(dev);
6396 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006397 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398
Francois Romieuda78dbf2012-01-26 14:18:23 +01006399 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006400 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006401
Junchang Wang8027aa22012-03-04 23:30:32 +01006402 do {
6403 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6404 stats->rx_packets = tp->rx_stats.packets;
6405 stats->rx_bytes = tp->rx_stats.bytes;
6406 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6407
6408
6409 do {
6410 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6411 stats->tx_packets = tp->tx_stats.packets;
6412 stats->tx_bytes = tp->tx_stats.bytes;
6413 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6414
6415 stats->rx_dropped = dev->stats.rx_dropped;
6416 stats->tx_dropped = dev->stats.tx_dropped;
6417 stats->rx_length_errors = dev->stats.rx_length_errors;
6418 stats->rx_errors = dev->stats.rx_errors;
6419 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6420 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6421 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6422
6423 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424}
6425
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006426static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006427{
françois romieu065c27c2011-01-03 15:08:12 +00006428 struct rtl8169_private *tp = netdev_priv(dev);
6429
Francois Romieu5d06a992006-02-23 00:47:58 +01006430 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006431 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006432
6433 netif_device_detach(dev);
6434 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006435
6436 rtl_lock_work(tp);
6437 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006438 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006439 rtl_unlock_work(tp);
6440
6441 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006442}
Francois Romieu5d06a992006-02-23 00:47:58 +01006443
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006444#ifdef CONFIG_PM
6445
6446static int rtl8169_suspend(struct device *device)
6447{
6448 struct pci_dev *pdev = to_pci_dev(device);
6449 struct net_device *dev = pci_get_drvdata(pdev);
6450
6451 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006452
Francois Romieu5d06a992006-02-23 00:47:58 +01006453 return 0;
6454}
6455
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006456static void __rtl8169_resume(struct net_device *dev)
6457{
françois romieu065c27c2011-01-03 15:08:12 +00006458 struct rtl8169_private *tp = netdev_priv(dev);
6459
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006460 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006461
6462 rtl_pll_power_up(tp);
6463
Artem Savkovcff4c162012-04-03 10:29:11 +00006464 rtl_lock_work(tp);
6465 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006466 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006467 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006468
Francois Romieu98ddf982012-01-31 10:47:34 +01006469 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006470}
6471
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006472static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006473{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006474 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006475 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006476 struct rtl8169_private *tp = netdev_priv(dev);
6477
6478 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006479
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006480 if (netif_running(dev))
6481 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006482
Francois Romieu5d06a992006-02-23 00:47:58 +01006483 return 0;
6484}
6485
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006486static int rtl8169_runtime_suspend(struct device *device)
6487{
6488 struct pci_dev *pdev = to_pci_dev(device);
6489 struct net_device *dev = pci_get_drvdata(pdev);
6490 struct rtl8169_private *tp = netdev_priv(dev);
6491
6492 if (!tp->TxDescArray)
6493 return 0;
6494
Francois Romieuda78dbf2012-01-26 14:18:23 +01006495 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006496 tp->saved_wolopts = __rtl8169_get_wol(tp);
6497 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006498 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006499
6500 rtl8169_net_suspend(dev);
6501
6502 return 0;
6503}
6504
6505static int rtl8169_runtime_resume(struct device *device)
6506{
6507 struct pci_dev *pdev = to_pci_dev(device);
6508 struct net_device *dev = pci_get_drvdata(pdev);
6509 struct rtl8169_private *tp = netdev_priv(dev);
6510
6511 if (!tp->TxDescArray)
6512 return 0;
6513
Francois Romieuda78dbf2012-01-26 14:18:23 +01006514 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006515 __rtl8169_set_wol(tp, tp->saved_wolopts);
6516 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006517 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006518
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006519 rtl8169_init_phy(dev, tp);
6520
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006521 __rtl8169_resume(dev);
6522
6523 return 0;
6524}
6525
6526static int rtl8169_runtime_idle(struct device *device)
6527{
6528 struct pci_dev *pdev = to_pci_dev(device);
6529 struct net_device *dev = pci_get_drvdata(pdev);
6530 struct rtl8169_private *tp = netdev_priv(dev);
6531
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006532 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006533}
6534
Alexey Dobriyan47145212009-12-14 18:00:08 -08006535static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006536 .suspend = rtl8169_suspend,
6537 .resume = rtl8169_resume,
6538 .freeze = rtl8169_suspend,
6539 .thaw = rtl8169_resume,
6540 .poweroff = rtl8169_suspend,
6541 .restore = rtl8169_resume,
6542 .runtime_suspend = rtl8169_runtime_suspend,
6543 .runtime_resume = rtl8169_runtime_resume,
6544 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006545};
6546
6547#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6548
6549#else /* !CONFIG_PM */
6550
6551#define RTL8169_PM_OPS NULL
6552
6553#endif /* !CONFIG_PM */
6554
David S. Miller1805b2f2011-10-24 18:18:09 -04006555static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6556{
6557 void __iomem *ioaddr = tp->mmio_addr;
6558
6559 /* WoL fails with 8168b when the receiver is disabled. */
6560 switch (tp->mac_version) {
6561 case RTL_GIGA_MAC_VER_11:
6562 case RTL_GIGA_MAC_VER_12:
6563 case RTL_GIGA_MAC_VER_17:
6564 pci_clear_master(tp->pci_dev);
6565
6566 RTL_W8(ChipCmd, CmdRxEnb);
6567 /* PCI commit */
6568 RTL_R8(ChipCmd);
6569 break;
6570 default:
6571 break;
6572 }
6573}
6574
Francois Romieu1765f952008-09-13 17:21:40 +02006575static void rtl_shutdown(struct pci_dev *pdev)
6576{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006577 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006578 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006579 struct device *d = &pdev->dev;
6580
6581 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006582
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006583 rtl8169_net_suspend(dev);
6584
Francois Romieucecb5fd2011-04-01 10:21:07 +02006585 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006586 rtl_rar_set(tp, dev->perm_addr);
6587
Hayes Wang92fc43b2011-07-06 15:58:03 +08006588 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006589
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006590 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006591 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6592 rtl_wol_suspend_quirk(tp);
6593 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006594 }
6595
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006596 pci_wake_from_d3(pdev, true);
6597 pci_set_power_state(pdev, PCI_D3hot);
6598 }
françois romieu2a15cd22012-03-06 01:14:12 +00006599
6600 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006601}
Francois Romieu5d06a992006-02-23 00:47:58 +01006602
Francois Romieue27566e2012-03-08 09:54:01 +01006603static void __devexit rtl_remove_one(struct pci_dev *pdev)
6604{
6605 struct net_device *dev = pci_get_drvdata(pdev);
6606 struct rtl8169_private *tp = netdev_priv(dev);
6607
6608 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6609 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6610 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6611 rtl8168_driver_stop(tp);
6612 }
6613
6614 cancel_work_sync(&tp->wk.work);
6615
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006616 netif_napi_del(&tp->napi);
6617
Francois Romieue27566e2012-03-08 09:54:01 +01006618 unregister_netdev(dev);
6619
6620 rtl_release_firmware(tp);
6621
6622 if (pci_dev_run_wake(pdev))
6623 pm_runtime_get_noresume(&pdev->dev);
6624
6625 /* restore original MAC address */
6626 rtl_rar_set(tp, dev->perm_addr);
6627
6628 rtl_disable_msi(pdev, tp);
6629 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6630 pci_set_drvdata(pdev, NULL);
6631}
6632
Francois Romieufa9c3852012-03-08 10:01:50 +01006633static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006634 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006635 .ndo_stop = rtl8169_close,
6636 .ndo_get_stats64 = rtl8169_get_stats64,
6637 .ndo_start_xmit = rtl8169_start_xmit,
6638 .ndo_tx_timeout = rtl8169_tx_timeout,
6639 .ndo_validate_addr = eth_validate_addr,
6640 .ndo_change_mtu = rtl8169_change_mtu,
6641 .ndo_fix_features = rtl8169_fix_features,
6642 .ndo_set_features = rtl8169_set_features,
6643 .ndo_set_mac_address = rtl_set_mac_address,
6644 .ndo_do_ioctl = rtl8169_ioctl,
6645 .ndo_set_rx_mode = rtl_set_rx_mode,
6646#ifdef CONFIG_NET_POLL_CONTROLLER
6647 .ndo_poll_controller = rtl8169_netpoll,
6648#endif
6649
6650};
6651
Francois Romieu31fa8b12012-03-08 10:09:40 +01006652static const struct rtl_cfg_info {
6653 void (*hw_start)(struct net_device *);
6654 unsigned int region;
6655 unsigned int align;
6656 u16 event_slow;
6657 unsigned features;
6658 u8 default_ver;
6659} rtl_cfg_infos [] = {
6660 [RTL_CFG_0] = {
6661 .hw_start = rtl_hw_start_8169,
6662 .region = 1,
6663 .align = 0,
6664 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6665 .features = RTL_FEATURE_GMII,
6666 .default_ver = RTL_GIGA_MAC_VER_01,
6667 },
6668 [RTL_CFG_1] = {
6669 .hw_start = rtl_hw_start_8168,
6670 .region = 2,
6671 .align = 8,
6672 .event_slow = SYSErr | LinkChg | RxOverflow,
6673 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6674 .default_ver = RTL_GIGA_MAC_VER_11,
6675 },
6676 [RTL_CFG_2] = {
6677 .hw_start = rtl_hw_start_8101,
6678 .region = 2,
6679 .align = 8,
6680 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6681 PCSTimeout,
6682 .features = RTL_FEATURE_MSI,
6683 .default_ver = RTL_GIGA_MAC_VER_13,
6684 }
6685};
6686
6687/* Cfg9346_Unlock assumed. */
6688static unsigned rtl_try_msi(struct rtl8169_private *tp,
6689 const struct rtl_cfg_info *cfg)
6690{
6691 void __iomem *ioaddr = tp->mmio_addr;
6692 unsigned msi = 0;
6693 u8 cfg2;
6694
6695 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6696 if (cfg->features & RTL_FEATURE_MSI) {
6697 if (pci_enable_msi(tp->pci_dev)) {
6698 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6699 } else {
6700 cfg2 |= MSIEnable;
6701 msi = RTL_FEATURE_MSI;
6702 }
6703 }
6704 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6705 RTL_W8(Config2, cfg2);
6706 return msi;
6707}
6708
Hayes Wangc5583862012-07-02 17:23:22 +08006709DECLARE_RTL_COND(rtl_link_list_ready_cond)
6710{
6711 void __iomem *ioaddr = tp->mmio_addr;
6712
6713 return RTL_R8(MCU) & LINK_LIST_RDY;
6714}
6715
6716DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6717{
6718 void __iomem *ioaddr = tp->mmio_addr;
6719
6720 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6721}
6722
6723static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
6724{
6725 void __iomem *ioaddr = tp->mmio_addr;
6726 u32 data;
6727
6728 tp->ocp_base = OCP_STD_PHY_BASE;
6729
6730 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6731
6732 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6733 return;
6734
6735 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6736 return;
6737
6738 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6739 msleep(1);
6740 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6741
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006742 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006743 data &= ~(1 << 14);
6744 r8168_mac_ocp_write(tp, 0xe8de, data);
6745
6746 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6747 return;
6748
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006749 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006750 data |= (1 << 15);
6751 r8168_mac_ocp_write(tp, 0xe8de, data);
6752
6753 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6754 return;
6755}
6756
6757static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
6758{
6759 switch (tp->mac_version) {
6760 case RTL_GIGA_MAC_VER_40:
6761 case RTL_GIGA_MAC_VER_41:
6762 rtl_hw_init_8168g(tp);
6763 break;
6764
6765 default:
6766 break;
6767 }
6768}
6769
Francois Romieu3b6cf252012-03-08 09:59:04 +01006770static int __devinit
6771rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6772{
6773 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6774 const unsigned int region = cfg->region;
6775 struct rtl8169_private *tp;
6776 struct mii_if_info *mii;
6777 struct net_device *dev;
6778 void __iomem *ioaddr;
6779 int chipset, i;
6780 int rc;
6781
6782 if (netif_msg_drv(&debug)) {
6783 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6784 MODULENAME, RTL8169_VERSION);
6785 }
6786
6787 dev = alloc_etherdev(sizeof (*tp));
6788 if (!dev) {
6789 rc = -ENOMEM;
6790 goto out;
6791 }
6792
6793 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006794 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006795 tp = netdev_priv(dev);
6796 tp->dev = dev;
6797 tp->pci_dev = pdev;
6798 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6799
6800 mii = &tp->mii;
6801 mii->dev = dev;
6802 mii->mdio_read = rtl_mdio_read;
6803 mii->mdio_write = rtl_mdio_write;
6804 mii->phy_id_mask = 0x1f;
6805 mii->reg_num_mask = 0x1f;
6806 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6807
6808 /* disable ASPM completely as that cause random device stop working
6809 * problems as well as full system hangs for some PCIe devices users */
6810 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6811 PCIE_LINK_STATE_CLKPM);
6812
6813 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6814 rc = pci_enable_device(pdev);
6815 if (rc < 0) {
6816 netif_err(tp, probe, dev, "enable failure\n");
6817 goto err_out_free_dev_1;
6818 }
6819
6820 if (pci_set_mwi(pdev) < 0)
6821 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6822
6823 /* make sure PCI base addr 1 is MMIO */
6824 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6825 netif_err(tp, probe, dev,
6826 "region #%d not an MMIO resource, aborting\n",
6827 region);
6828 rc = -ENODEV;
6829 goto err_out_mwi_2;
6830 }
6831
6832 /* check for weird/broken PCI region reporting */
6833 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6834 netif_err(tp, probe, dev,
6835 "Invalid PCI region size(s), aborting\n");
6836 rc = -ENODEV;
6837 goto err_out_mwi_2;
6838 }
6839
6840 rc = pci_request_regions(pdev, MODULENAME);
6841 if (rc < 0) {
6842 netif_err(tp, probe, dev, "could not request regions\n");
6843 goto err_out_mwi_2;
6844 }
6845
6846 tp->cp_cmd = RxChkSum;
6847
6848 if ((sizeof(dma_addr_t) > 4) &&
6849 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6850 tp->cp_cmd |= PCIDAC;
6851 dev->features |= NETIF_F_HIGHDMA;
6852 } else {
6853 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6854 if (rc < 0) {
6855 netif_err(tp, probe, dev, "DMA configuration failed\n");
6856 goto err_out_free_res_3;
6857 }
6858 }
6859
6860 /* ioremap MMIO region */
6861 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6862 if (!ioaddr) {
6863 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6864 rc = -EIO;
6865 goto err_out_free_res_3;
6866 }
6867 tp->mmio_addr = ioaddr;
6868
6869 if (!pci_is_pcie(pdev))
6870 netif_info(tp, probe, dev, "not PCI Express\n");
6871
6872 /* Identify chip attached to board */
6873 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6874
6875 rtl_init_rxcfg(tp);
6876
6877 rtl_irq_disable(tp);
6878
Hayes Wangc5583862012-07-02 17:23:22 +08006879 rtl_hw_initialize(tp);
6880
Francois Romieu3b6cf252012-03-08 09:59:04 +01006881 rtl_hw_reset(tp);
6882
6883 rtl_ack_events(tp, 0xffff);
6884
6885 pci_set_master(pdev);
6886
6887 /*
6888 * Pretend we are using VLANs; This bypasses a nasty bug where
6889 * Interrupts stop flowing on high load on 8110SCd controllers.
6890 */
6891 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6892 tp->cp_cmd |= RxVlan;
6893
6894 rtl_init_mdio_ops(tp);
6895 rtl_init_pll_power_ops(tp);
6896 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006897 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006898
6899 rtl8169_print_mac_version(tp);
6900
6901 chipset = tp->mac_version;
6902 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6903
6904 RTL_W8(Cfg9346, Cfg9346_Unlock);
6905 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6906 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6907 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6908 tp->features |= RTL_FEATURE_WOL;
6909 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6910 tp->features |= RTL_FEATURE_WOL;
6911 tp->features |= rtl_try_msi(tp, cfg);
6912 RTL_W8(Cfg9346, Cfg9346_Lock);
6913
6914 if (rtl_tbi_enabled(tp)) {
6915 tp->set_speed = rtl8169_set_speed_tbi;
6916 tp->get_settings = rtl8169_gset_tbi;
6917 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6918 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6919 tp->link_ok = rtl8169_tbi_link_ok;
6920 tp->do_ioctl = rtl_tbi_ioctl;
6921 } else {
6922 tp->set_speed = rtl8169_set_speed_xmii;
6923 tp->get_settings = rtl8169_gset_xmii;
6924 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6925 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6926 tp->link_ok = rtl8169_xmii_link_ok;
6927 tp->do_ioctl = rtl_xmii_ioctl;
6928 }
6929
6930 mutex_init(&tp->wk.mutex);
6931
6932 /* Get MAC address */
6933 for (i = 0; i < ETH_ALEN; i++)
6934 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6935 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6936
6937 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6938 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006939
6940 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6941
6942 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6943 * properly for all devices */
6944 dev->features |= NETIF_F_RXCSUM |
6945 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6946
6947 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6948 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6949 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6950 NETIF_F_HIGHDMA;
6951
6952 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6953 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6954 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6955
6956 dev->hw_features |= NETIF_F_RXALL;
6957 dev->hw_features |= NETIF_F_RXFCS;
6958
6959 tp->hw_start = cfg->hw_start;
6960 tp->event_slow = cfg->event_slow;
6961
6962 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6963 ~(RxBOVF | RxFOVF) : ~0;
6964
6965 init_timer(&tp->timer);
6966 tp->timer.data = (unsigned long) dev;
6967 tp->timer.function = rtl8169_phy_timer;
6968
6969 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6970
6971 rc = register_netdev(dev);
6972 if (rc < 0)
6973 goto err_out_msi_4;
6974
6975 pci_set_drvdata(pdev, dev);
6976
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006977 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6978 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6979 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006980 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6981 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6982 "tx checksumming: %s]\n",
6983 rtl_chip_infos[chipset].jumbo_max,
6984 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6985 }
6986
6987 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6988 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6989 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6990 rtl8168_driver_start(tp);
6991 }
6992
6993 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6994
6995 if (pci_dev_run_wake(pdev))
6996 pm_runtime_put_noidle(&pdev->dev);
6997
6998 netif_carrier_off(dev);
6999
7000out:
7001 return rc;
7002
7003err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00007004 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01007005 rtl_disable_msi(pdev, tp);
7006 iounmap(ioaddr);
7007err_out_free_res_3:
7008 pci_release_regions(pdev);
7009err_out_mwi_2:
7010 pci_clear_mwi(pdev);
7011 pci_disable_device(pdev);
7012err_out_free_dev_1:
7013 free_netdev(dev);
7014 goto out;
7015}
7016
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017static struct pci_driver rtl8169_pci_driver = {
7018 .name = MODULENAME,
7019 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01007020 .probe = rtl_init_one,
Francois Romieue27566e2012-03-08 09:54:01 +01007021 .remove = __devexit_p(rtl_remove_one),
Francois Romieu1765f952008-09-13 17:21:40 +02007022 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00007023 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024};
7025
Devendra Naga3eeb7da2012-10-26 09:27:42 +00007026module_pci_driver(rtl8169_pci_driver);