blob: 0c96604e624665628921421219e40237787daa8a [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 Romieuf0e837d92005-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
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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 Wang4f6b00e52011-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),
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200690};
691
Ivan Vecera355423d2009-02-06 21:49:57 -0800692struct rtl8169_counters {
693 __le64 tx_packets;
694 __le64 rx_packets;
695 __le64 tx_errors;
696 __le32 rx_errors;
697 __le16 rx_missed;
698 __le16 align_errors;
699 __le32 tx_one_collision;
700 __le32 tx_multi_collision;
701 __le64 rx_unicast;
702 __le64 rx_broadcast;
703 __le32 rx_multicast;
704 __le16 tx_aborted;
705 __le16 tx_underun;
706};
707
Francois Romieuda78dbf2012-01-26 14:18:23 +0100708enum rtl_flag {
Francois Romieu6c4a70c2012-01-31 10:56:44 +0100709 RTL_FLAG_TASK_ENABLED,
Francois Romieuda78dbf2012-01-26 14:18:23 +0100710 RTL_FLAG_TASK_SLOW_PENDING,
711 RTL_FLAG_TASK_RESET_PENDING,
712 RTL_FLAG_TASK_PHY_PENDING,
713 RTL_FLAG_MAX
714};
715
Junchang Wang8027aa22012-03-04 23:30:32 +0100716struct rtl8169_stats {
717 u64 packets;
718 u64 bytes;
719 struct u64_stats_sync syncp;
720};
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722struct rtl8169_private {
723 void __iomem *mmio_addr; /* memory map physical address */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200724 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000725 struct net_device *dev;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700726 struct napi_struct napi;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200727 u32 msg_enable;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700728 u16 txd_version;
729 u16 mac_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
731 u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
732 u32 dirty_rx;
733 u32 dirty_tx;
Junchang Wang8027aa22012-03-04 23:30:32 +0100734 struct rtl8169_stats rx_stats;
735 struct rtl8169_stats tx_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
737 struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
738 dma_addr_t TxPhyAddr;
739 dma_addr_t RxPhyAddr;
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000740 void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct timer_list timer;
743 u16 cp_cmd;
Francois Romieuda78dbf2012-01-26 14:18:23 +0100744
745 u16 event_slow;
françois romieuc0e45c12011-01-03 15:08:04 +0000746
747 struct mdio_ops {
Francois Romieu24192212012-07-06 20:19:42 +0200748 void (*write)(struct rtl8169_private *, int, int);
749 int (*read)(struct rtl8169_private *, int);
françois romieuc0e45c12011-01-03 15:08:04 +0000750 } mdio_ops;
751
françois romieu065c27c2011-01-03 15:08:12 +0000752 struct pll_power_ops {
753 void (*down)(struct rtl8169_private *);
754 void (*up)(struct rtl8169_private *);
755 } pll_power_ops;
756
Francois Romieud58d46b2011-05-03 16:38:29 +0200757 struct jumbo_ops {
758 void (*enable)(struct rtl8169_private *);
759 void (*disable)(struct rtl8169_private *);
760 } jumbo_ops;
761
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800762 struct csi_ops {
Francois Romieu52989f02012-07-06 13:37:00 +0200763 void (*write)(struct rtl8169_private *, int, int);
764 u32 (*read)(struct rtl8169_private *, int);
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800765 } csi_ops;
766
Oliver Neukum54405cd2011-01-06 21:55:13 +0100767 int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
Francois Romieuccdffb92008-07-26 14:26:06 +0200768 int (*get_settings)(struct net_device *, struct ethtool_cmd *);
françois romieu4da19632011-01-03 15:07:55 +0000769 void (*phy_reset_enable)(struct rtl8169_private *tp);
Francois Romieu07ce4062007-02-23 23:36:39 +0100770 void (*hw_start)(struct net_device *);
françois romieu4da19632011-01-03 15:07:55 +0000771 unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 unsigned int (*link_ok)(void __iomem *);
Francois Romieu8b4ab282008-11-19 22:05:25 -0800773 int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
Francois Romieu4422bcd2012-01-26 11:23:32 +0100774
775 struct {
Francois Romieuda78dbf2012-01-26 14:18:23 +0100776 DECLARE_BITMAP(flags, RTL_FLAG_MAX);
777 struct mutex mutex;
Francois Romieu4422bcd2012-01-26 11:23:32 +0100778 struct work_struct work;
779 } wk;
780
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200781 unsigned features;
Francois Romieuccdffb92008-07-26 14:26:06 +0200782
783 struct mii_if_info mii;
Ivan Vecera355423d2009-02-06 21:49:57 -0800784 struct rtl8169_counters counters;
Rafael J. Wysockie1759442010-03-14 14:33:51 +0000785 u32 saved_wolopts;
David S. Miller8decf862011-09-22 03:23:13 -0400786 u32 opts1_mask;
françois romieuf1e02ed2011-01-13 13:07:53 +0000787
Francois Romieub6ffd972011-06-17 17:00:05 +0200788 struct rtl_fw {
789 const struct firmware *fw;
Francois Romieu1c361ef2011-06-17 17:16:24 +0200790
791#define RTL_VER_SIZE 32
792
793 char version[RTL_VER_SIZE];
794
795 struct rtl_fw_phy_action {
796 __le32 *code;
797 size_t size;
798 } phy_action;
Francois Romieub6ffd972011-06-17 17:00:05 +0200799 } *rtl_fw;
Phil Carmody497888c2011-07-14 15:07:13 +0300800#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
Hayes Wangc5583862012-07-02 17:23:22 +0800801
802 u32 ocp_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803};
804
Ralf Baechle979b6c12005-06-13 14:30:40 -0700805MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807module_param(use_dac, int, 0);
David S. Miller4300e8c2010-03-26 10:23:30 -0700808MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200809module_param_named(debug, debug.msg_enable, int, 0);
810MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811MODULE_LICENSE("GPL");
812MODULE_VERSION(RTL8169_VERSION);
françois romieubca03d52011-01-03 15:07:31 +0000813MODULE_FIRMWARE(FIRMWARE_8168D_1);
814MODULE_FIRMWARE(FIRMWARE_8168D_2);
hayeswang01dc7fe2011-03-21 01:50:28 +0000815MODULE_FIRMWARE(FIRMWARE_8168E_1);
816MODULE_FIRMWARE(FIRMWARE_8168E_2);
David S. Miller8decf862011-09-22 03:23:13 -0400817MODULE_FIRMWARE(FIRMWARE_8168E_3);
Hayes Wang5a5e4442011-02-22 17:26:21 +0800818MODULE_FIRMWARE(FIRMWARE_8105E_1);
Hayes Wangc2218922011-09-06 16:55:18 +0800819MODULE_FIRMWARE(FIRMWARE_8168F_1);
820MODULE_FIRMWARE(FIRMWARE_8168F_2);
Hayes Wang7e18dca2012-03-30 14:33:02 +0800821MODULE_FIRMWARE(FIRMWARE_8402_1);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800822MODULE_FIRMWARE(FIRMWARE_8411_1);
Hayes Wang5598bfe2012-07-02 17:23:21 +0800823MODULE_FIRMWARE(FIRMWARE_8106E_1);
Hayes Wangc5583862012-07-02 17:23:22 +0800824MODULE_FIRMWARE(FIRMWARE_8168G_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Francois Romieuda78dbf2012-01-26 14:18:23 +0100826static void rtl_lock_work(struct rtl8169_private *tp)
827{
828 mutex_lock(&tp->wk.mutex);
829}
830
831static void rtl_unlock_work(struct rtl8169_private *tp)
832{
833 mutex_unlock(&tp->wk.mutex);
834}
835
Francois Romieud58d46b2011-05-03 16:38:29 +0200836static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
837{
838 int cap = pci_pcie_cap(pdev);
839
840 if (cap) {
841 u16 ctl;
842
843 pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
844 ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
845 pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
846 }
847}
848
Francois Romieuffc46952012-07-06 14:19:23 +0200849struct rtl_cond {
850 bool (*check)(struct rtl8169_private *);
851 const char *msg;
852};
853
854static void rtl_udelay(unsigned int d)
855{
856 udelay(d);
857}
858
859static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
860 void (*delay)(unsigned int), unsigned int d, int n,
861 bool high)
862{
863 int i;
864
865 for (i = 0; i < n; i++) {
866 delay(d);
867 if (c->check(tp) == high)
868 return true;
869 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200870 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
871 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200872 return false;
873}
874
875static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
876 const struct rtl_cond *c,
877 unsigned int d, int n)
878{
879 return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
880}
881
882static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
883 const struct rtl_cond *c,
884 unsigned int d, int n)
885{
886 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
887}
888
889static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
890 const struct rtl_cond *c,
891 unsigned int d, int n)
892{
893 return rtl_loop_wait(tp, c, msleep, d, n, true);
894}
895
896static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
897 const struct rtl_cond *c,
898 unsigned int d, int n)
899{
900 return rtl_loop_wait(tp, c, msleep, d, n, false);
901}
902
903#define DECLARE_RTL_COND(name) \
904static bool name ## _check(struct rtl8169_private *); \
905 \
906static const struct rtl_cond name = { \
907 .check = name ## _check, \
908 .msg = #name \
909}; \
910 \
911static bool name ## _check(struct rtl8169_private *tp)
912
913DECLARE_RTL_COND(rtl_ocpar_cond)
914{
915 void __iomem *ioaddr = tp->mmio_addr;
916
917 return RTL_R32(OCPAR) & OCPAR_FLAG;
918}
919
françois romieub646d902011-01-03 15:08:21 +0000920static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
921{
922 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000923
924 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200925
926 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
927 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000928}
929
930static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
931{
932 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000933
934 RTL_W32(OCPDR, data);
935 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200936
937 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
938}
939
940DECLARE_RTL_COND(rtl_eriar_cond)
941{
942 void __iomem *ioaddr = tp->mmio_addr;
943
944 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000945}
946
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800947static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000948{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800949 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000950
951 RTL_W8(ERIDR, cmd);
952 RTL_W32(ERIAR, 0x800010e8);
953 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200954
955 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
956 return;
françois romieub646d902011-01-03 15:08:21 +0000957
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800958 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000959}
960
961#define OOB_CMD_RESET 0x00
962#define OOB_CMD_DRIVER_START 0x05
963#define OOB_CMD_DRIVER_STOP 0x06
964
Francois Romieucecb5fd2011-04-01 10:21:07 +0200965static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
966{
967 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
968}
969
Francois Romieuffc46952012-07-06 14:19:23 +0200970DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000971{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200972 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000973
Francois Romieucecb5fd2011-04-01 10:21:07 +0200974 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000975
Francois Romieuffc46952012-07-06 14:19:23 +0200976 return ocp_read(tp, 0x0f, reg) & 0x00000800;
977}
978
979static void rtl8168_driver_start(struct rtl8169_private *tp)
980{
981 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
982
983 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000984}
985
986static void rtl8168_driver_stop(struct rtl8169_private *tp)
987{
françois romieub646d902011-01-03 15:08:21 +0000988 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
989
Francois Romieuffc46952012-07-06 14:19:23 +0200990 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000991}
992
hayeswang4804b3b2011-03-21 01:50:29 +0000993static int r8168dp_check_dash(struct rtl8169_private *tp)
994{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200995 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000996
Francois Romieucecb5fd2011-04-01 10:21:07 +0200997 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000998}
françois romieub646d902011-01-03 15:08:21 +0000999
Hayes Wangc5583862012-07-02 17:23:22 +08001000static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
1001{
1002 if (reg & 0xffff0001) {
1003 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
1004 return true;
1005 }
1006 return false;
1007}
1008
1009DECLARE_RTL_COND(rtl_ocp_gphy_cond)
1010{
1011 void __iomem *ioaddr = tp->mmio_addr;
1012
1013 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1014}
1015
1016static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1017{
1018 void __iomem *ioaddr = tp->mmio_addr;
1019
1020 if (rtl_ocp_reg_failure(tp, reg))
1021 return;
1022
1023 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1024
1025 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1026}
1027
1028static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1029{
1030 void __iomem *ioaddr = tp->mmio_addr;
1031
1032 if (rtl_ocp_reg_failure(tp, reg))
1033 return 0;
1034
1035 RTL_W32(GPHY_OCP, reg << 15);
1036
1037 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1038 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1039}
1040
1041static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1042{
1043 int val;
1044
1045 val = r8168_phy_ocp_read(tp, reg);
1046 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1047}
1048
Hayes Wangc5583862012-07-02 17:23:22 +08001049static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1050{
1051 void __iomem *ioaddr = tp->mmio_addr;
1052
1053 if (rtl_ocp_reg_failure(tp, reg))
1054 return;
1055
1056 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001057}
1058
1059static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1060{
1061 void __iomem *ioaddr = tp->mmio_addr;
1062
1063 if (rtl_ocp_reg_failure(tp, reg))
1064 return 0;
1065
1066 RTL_W32(OCPDR, reg << 15);
1067
Hayes Wang3a83ad12012-07-11 20:31:56 +08001068 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001069}
1070
1071#define OCP_STD_PHY_BASE 0xa400
1072
1073static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1074{
1075 if (reg == 0x1f) {
1076 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1077 return;
1078 }
1079
1080 if (tp->ocp_base != OCP_STD_PHY_BASE)
1081 reg -= 0x10;
1082
1083 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1084}
1085
1086static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1087{
1088 if (tp->ocp_base != OCP_STD_PHY_BASE)
1089 reg -= 0x10;
1090
1091 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1092}
1093
Francois Romieuffc46952012-07-06 14:19:23 +02001094DECLARE_RTL_COND(rtl_phyar_cond)
1095{
1096 void __iomem *ioaddr = tp->mmio_addr;
1097
1098 return RTL_R32(PHYAR) & 0x80000000;
1099}
1100
Francois Romieu24192212012-07-06 20:19:42 +02001101static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
Francois Romieu24192212012-07-06 20:19:42 +02001103 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Francois Romieu24192212012-07-06 20:19:42 +02001105 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Francois Romieuffc46952012-07-06 14:19:23 +02001107 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001108 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001109 * According to hardware specs a 20us delay is required after write
1110 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001111 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001112 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113}
1114
Francois Romieu24192212012-07-06 20:19:42 +02001115static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Francois Romieu24192212012-07-06 20:19:42 +02001117 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001118 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Francois Romieu24192212012-07-06 20:19:42 +02001120 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Francois Romieuffc46952012-07-06 14:19:23 +02001122 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1123 RTL_R32(PHYAR) & 0xffff : ~0;
1124
Timo Teräs81a95f02010-06-09 17:31:48 -07001125 /*
1126 * According to hardware specs a 20us delay is required after read
1127 * complete indication, but before sending next command.
1128 */
1129 udelay(20);
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 return value;
1132}
1133
Francois Romieu24192212012-07-06 20:19:42 +02001134static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001135{
Francois Romieu24192212012-07-06 20:19:42 +02001136 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001137
Francois Romieu24192212012-07-06 20:19:42 +02001138 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001139 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1140 RTL_W32(EPHY_RXER_NUM, 0);
1141
Francois Romieuffc46952012-07-06 14:19:23 +02001142 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001143}
1144
Francois Romieu24192212012-07-06 20:19:42 +02001145static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001146{
Francois Romieu24192212012-07-06 20:19:42 +02001147 r8168dp_1_mdio_access(tp, reg,
1148 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001149}
1150
Francois Romieu24192212012-07-06 20:19:42 +02001151static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001152{
Francois Romieu24192212012-07-06 20:19:42 +02001153 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001154
Francois Romieu24192212012-07-06 20:19:42 +02001155 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001156
1157 mdelay(1);
1158 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1159 RTL_W32(EPHY_RXER_NUM, 0);
1160
Francois Romieuffc46952012-07-06 14:19:23 +02001161 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1162 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001163}
1164
françois romieue6de30d2011-01-03 15:08:37 +00001165#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1166
1167static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1168{
1169 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1170}
1171
1172static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1173{
1174 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1175}
1176
Francois Romieu24192212012-07-06 20:19:42 +02001177static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001178{
Francois Romieu24192212012-07-06 20:19:42 +02001179 void __iomem *ioaddr = tp->mmio_addr;
1180
françois romieue6de30d2011-01-03 15:08:37 +00001181 r8168dp_2_mdio_start(ioaddr);
1182
Francois Romieu24192212012-07-06 20:19:42 +02001183 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001184
1185 r8168dp_2_mdio_stop(ioaddr);
1186}
1187
Francois Romieu24192212012-07-06 20:19:42 +02001188static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001189{
Francois Romieu24192212012-07-06 20:19:42 +02001190 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001191 int value;
1192
1193 r8168dp_2_mdio_start(ioaddr);
1194
Francois Romieu24192212012-07-06 20:19:42 +02001195 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001196
1197 r8168dp_2_mdio_stop(ioaddr);
1198
1199 return value;
1200}
1201
françois romieu4da19632011-01-03 15:07:55 +00001202static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001203{
Francois Romieu24192212012-07-06 20:19:42 +02001204 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001205}
1206
françois romieu4da19632011-01-03 15:07:55 +00001207static int rtl_readphy(struct rtl8169_private *tp, int location)
1208{
Francois Romieu24192212012-07-06 20:19:42 +02001209 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001210}
1211
1212static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1213{
1214 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1215}
1216
1217static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001218{
1219 int val;
1220
françois romieu4da19632011-01-03 15:07:55 +00001221 val = rtl_readphy(tp, reg_addr);
1222 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001223}
1224
Francois Romieuccdffb92008-07-26 14:26:06 +02001225static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1226 int val)
1227{
1228 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001229
françois romieu4da19632011-01-03 15:07:55 +00001230 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001231}
1232
1233static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1234{
1235 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001236
françois romieu4da19632011-01-03 15:07:55 +00001237 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001238}
1239
Francois Romieuffc46952012-07-06 14:19:23 +02001240DECLARE_RTL_COND(rtl_ephyar_cond)
1241{
1242 void __iomem *ioaddr = tp->mmio_addr;
1243
1244 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1245}
1246
Francois Romieufdf6fc02012-07-06 22:40:38 +02001247static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001248{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001249 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001250
1251 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1252 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1253
Francois Romieuffc46952012-07-06 14:19:23 +02001254 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1255
1256 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001257}
1258
Francois Romieufdf6fc02012-07-06 22:40:38 +02001259static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001260{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001261 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001262
1263 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1264
Francois Romieuffc46952012-07-06 14:19:23 +02001265 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1266 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001267}
1268
Francois Romieufdf6fc02012-07-06 22:40:38 +02001269static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1270 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001271{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001272 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001273
1274 BUG_ON((addr & 3) || (mask == 0));
1275 RTL_W32(ERIDR, val);
1276 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1277
Francois Romieuffc46952012-07-06 14:19:23 +02001278 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001279}
1280
Francois Romieufdf6fc02012-07-06 22:40:38 +02001281static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001282{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001283 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001284
1285 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1286
Francois Romieuffc46952012-07-06 14:19:23 +02001287 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1288 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001289}
1290
Francois Romieufdf6fc02012-07-06 22:40:38 +02001291static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1292 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001293{
1294 u32 val;
1295
Francois Romieufdf6fc02012-07-06 22:40:38 +02001296 val = rtl_eri_read(tp, addr, type);
1297 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001298}
1299
françois romieuc28aa382011-08-02 03:53:43 +00001300struct exgmac_reg {
1301 u16 addr;
1302 u16 mask;
1303 u32 val;
1304};
1305
Francois Romieufdf6fc02012-07-06 22:40:38 +02001306static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001307 const struct exgmac_reg *r, int len)
1308{
1309 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001310 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001311 r++;
1312 }
1313}
1314
Francois Romieuffc46952012-07-06 14:19:23 +02001315DECLARE_RTL_COND(rtl_efusear_cond)
1316{
1317 void __iomem *ioaddr = tp->mmio_addr;
1318
1319 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1320}
1321
Francois Romieufdf6fc02012-07-06 22:40:38 +02001322static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001323{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001324 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001325
1326 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1327
Francois Romieuffc46952012-07-06 14:19:23 +02001328 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1329 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001330}
1331
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001332static u16 rtl_get_events(struct rtl8169_private *tp)
1333{
1334 void __iomem *ioaddr = tp->mmio_addr;
1335
1336 return RTL_R16(IntrStatus);
1337}
1338
1339static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1340{
1341 void __iomem *ioaddr = tp->mmio_addr;
1342
1343 RTL_W16(IntrStatus, bits);
1344 mmiowb();
1345}
1346
1347static void rtl_irq_disable(struct rtl8169_private *tp)
1348{
1349 void __iomem *ioaddr = tp->mmio_addr;
1350
1351 RTL_W16(IntrMask, 0);
1352 mmiowb();
1353}
1354
Francois Romieu3e990ff2012-01-26 12:50:01 +01001355static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1356{
1357 void __iomem *ioaddr = tp->mmio_addr;
1358
1359 RTL_W16(IntrMask, bits);
1360}
1361
Francois Romieuda78dbf2012-01-26 14:18:23 +01001362#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1363#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1364#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1365
1366static void rtl_irq_enable_all(struct rtl8169_private *tp)
1367{
1368 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1369}
1370
françois romieu811fd302011-12-04 20:30:45 +00001371static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
françois romieu811fd302011-12-04 20:30:45 +00001373 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001375 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001376 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001377 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378}
1379
françois romieu4da19632011-01-03 15:07:55 +00001380static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
françois romieu4da19632011-01-03 15:07:55 +00001382 void __iomem *ioaddr = tp->mmio_addr;
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return RTL_R32(TBICSR) & TBIReset;
1385}
1386
françois romieu4da19632011-01-03 15:07:55 +00001387static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388{
françois romieu4da19632011-01-03 15:07:55 +00001389 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390}
1391
1392static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1393{
1394 return RTL_R32(TBICSR) & TBILinkOk;
1395}
1396
1397static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1398{
1399 return RTL_R8(PHYstatus) & LinkStatus;
1400}
1401
françois romieu4da19632011-01-03 15:07:55 +00001402static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
françois romieu4da19632011-01-03 15:07:55 +00001404 void __iomem *ioaddr = tp->mmio_addr;
1405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1407}
1408
françois romieu4da19632011-01-03 15:07:55 +00001409static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
1411 unsigned int val;
1412
françois romieu4da19632011-01-03 15:07:55 +00001413 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1414 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415}
1416
Hayes Wang70090422011-07-06 15:58:06 +08001417static void rtl_link_chg_patch(struct rtl8169_private *tp)
1418{
1419 void __iomem *ioaddr = tp->mmio_addr;
1420 struct net_device *dev = tp->dev;
1421
1422 if (!netif_running(dev))
1423 return;
1424
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001425 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1426 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001427 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001428 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1429 ERIAR_EXGMAC);
1430 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1431 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001432 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001433 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1434 ERIAR_EXGMAC);
1435 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1436 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001437 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001438 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1439 ERIAR_EXGMAC);
1440 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1441 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001442 }
1443 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001444 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001445 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001446 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001447 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001448 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1449 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1450 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001451 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1452 ERIAR_EXGMAC);
1453 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1454 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001455 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001456 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1457 ERIAR_EXGMAC);
1458 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1459 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001460 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001461 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1462 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001463 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1464 ERIAR_EXGMAC);
1465 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1466 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001467 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001468 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1469 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001470 }
Hayes Wang70090422011-07-06 15:58:06 +08001471 }
1472}
1473
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001474static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001475 struct rtl8169_private *tp,
1476 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001479 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001480 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001481 if (pm)
1482 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001484 if (net_ratelimit())
1485 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001486 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001488 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001489 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001490 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492}
1493
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001494static void rtl8169_check_link_status(struct net_device *dev,
1495 struct rtl8169_private *tp,
1496 void __iomem *ioaddr)
1497{
1498 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1499}
1500
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001501#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1502
1503static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1504{
1505 void __iomem *ioaddr = tp->mmio_addr;
1506 u8 options;
1507 u32 wolopts = 0;
1508
1509 options = RTL_R8(Config1);
1510 if (!(options & PMEnable))
1511 return 0;
1512
1513 options = RTL_R8(Config3);
1514 if (options & LinkUp)
1515 wolopts |= WAKE_PHY;
1516 if (options & MagicPacket)
1517 wolopts |= WAKE_MAGIC;
1518
1519 options = RTL_R8(Config5);
1520 if (options & UWF)
1521 wolopts |= WAKE_UCAST;
1522 if (options & BWF)
1523 wolopts |= WAKE_BCAST;
1524 if (options & MWF)
1525 wolopts |= WAKE_MCAST;
1526
1527 return wolopts;
1528}
1529
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001530static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1531{
1532 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001533
Francois Romieuda78dbf2012-01-26 14:18:23 +01001534 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001535
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001536 wol->supported = WAKE_ANY;
1537 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001538
Francois Romieuda78dbf2012-01-26 14:18:23 +01001539 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001540}
1541
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001542static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001543{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001544 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001545 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001546 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001547 u32 opt;
1548 u16 reg;
1549 u8 mask;
1550 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001551 { WAKE_PHY, Config3, LinkUp },
1552 { WAKE_MAGIC, Config3, MagicPacket },
1553 { WAKE_UCAST, Config5, UWF },
1554 { WAKE_BCAST, Config5, BWF },
1555 { WAKE_MCAST, Config5, MWF },
1556 { WAKE_ANY, Config5, LanWake }
1557 };
Francois Romieu851e6022012-04-17 11:10:11 +02001558 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001559
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001560 RTL_W8(Cfg9346, Cfg9346_Unlock);
1561
1562 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001563 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001564 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001565 options |= cfg[i].mask;
1566 RTL_W8(cfg[i].reg, options);
1567 }
1568
Francois Romieu851e6022012-04-17 11:10:11 +02001569 switch (tp->mac_version) {
1570 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1571 options = RTL_R8(Config1) & ~PMEnable;
1572 if (wolopts)
1573 options |= PMEnable;
1574 RTL_W8(Config1, options);
1575 break;
1576 default:
Francois Romieud387b422012-04-17 11:12:01 +02001577 options = RTL_R8(Config2) & ~PME_SIGNAL;
1578 if (wolopts)
1579 options |= PME_SIGNAL;
1580 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001581 break;
1582 }
1583
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001584 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001585}
1586
1587static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1588{
1589 struct rtl8169_private *tp = netdev_priv(dev);
1590
Francois Romieuda78dbf2012-01-26 14:18:23 +01001591 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001592
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001593 if (wol->wolopts)
1594 tp->features |= RTL_FEATURE_WOL;
1595 else
1596 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001597 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001598
1599 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001600
françois romieuea809072010-11-08 13:23:58 +00001601 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1602
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001603 return 0;
1604}
1605
Francois Romieu31bd2042011-04-26 18:58:59 +02001606static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1607{
Francois Romieu85bffe62011-04-27 08:22:39 +02001608 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001609}
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611static void rtl8169_get_drvinfo(struct net_device *dev,
1612 struct ethtool_drvinfo *info)
1613{
1614 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001615 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Rick Jones68aad782011-11-07 13:29:27 +00001617 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1618 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1619 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001620 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001621 if (!IS_ERR_OR_NULL(rtl_fw))
1622 strlcpy(info->fw_version, rtl_fw->version,
1623 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624}
1625
1626static int rtl8169_get_regs_len(struct net_device *dev)
1627{
1628 return R8169_REGS_SIZE;
1629}
1630
1631static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001632 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633{
1634 struct rtl8169_private *tp = netdev_priv(dev);
1635 void __iomem *ioaddr = tp->mmio_addr;
1636 int ret = 0;
1637 u32 reg;
1638
1639 reg = RTL_R32(TBICSR);
1640 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1641 (duplex == DUPLEX_FULL)) {
1642 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1643 } else if (autoneg == AUTONEG_ENABLE)
1644 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1645 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001646 netif_warn(tp, link, dev,
1647 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 ret = -EOPNOTSUPP;
1649 }
1650
1651 return ret;
1652}
1653
1654static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001655 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001658 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001659 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Hayes Wang716b50a2011-02-22 17:26:18 +08001661 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001664 int auto_nego;
1665
françois romieu4da19632011-01-03 15:07:55 +00001666 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001667 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1668 ADVERTISE_100HALF | ADVERTISE_100FULL);
1669
1670 if (adv & ADVERTISED_10baseT_Half)
1671 auto_nego |= ADVERTISE_10HALF;
1672 if (adv & ADVERTISED_10baseT_Full)
1673 auto_nego |= ADVERTISE_10FULL;
1674 if (adv & ADVERTISED_100baseT_Half)
1675 auto_nego |= ADVERTISE_100HALF;
1676 if (adv & ADVERTISED_100baseT_Full)
1677 auto_nego |= ADVERTISE_100FULL;
1678
françois romieu3577aa12009-05-19 10:46:48 +00001679 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1680
françois romieu4da19632011-01-03 15:07:55 +00001681 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001682 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1683
1684 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001685 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001686 if (adv & ADVERTISED_1000baseT_Half)
1687 giga_ctrl |= ADVERTISE_1000HALF;
1688 if (adv & ADVERTISED_1000baseT_Full)
1689 giga_ctrl |= ADVERTISE_1000FULL;
1690 } else if (adv & (ADVERTISED_1000baseT_Half |
1691 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001692 netif_info(tp, link, dev,
1693 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001694 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
françois romieu3577aa12009-05-19 10:46:48 +00001697 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001698
françois romieu4da19632011-01-03 15:07:55 +00001699 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1700 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001701 } else {
1702 giga_ctrl = 0;
1703
1704 if (speed == SPEED_10)
1705 bmcr = 0;
1706 else if (speed == SPEED_100)
1707 bmcr = BMCR_SPEED100;
1708 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001709 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001710
1711 if (duplex == DUPLEX_FULL)
1712 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001713 }
1714
françois romieu4da19632011-01-03 15:07:55 +00001715 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001716
Francois Romieucecb5fd2011-04-01 10:21:07 +02001717 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1718 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001719 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001720 rtl_writephy(tp, 0x17, 0x2138);
1721 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001722 } else {
françois romieu4da19632011-01-03 15:07:55 +00001723 rtl_writephy(tp, 0x17, 0x2108);
1724 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001725 }
1726 }
1727
Oliver Neukum54405cd2011-01-06 21:55:13 +01001728 rc = 0;
1729out:
1730 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731}
1732
1733static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001734 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
1736 struct rtl8169_private *tp = netdev_priv(dev);
1737 int ret;
1738
Oliver Neukum54405cd2011-01-06 21:55:13 +01001739 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001740 if (ret < 0)
1741 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
Francois Romieu4876cc12011-03-11 21:07:11 +01001743 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1744 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001746 }
1747out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 return ret;
1749}
1750
1751static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1752{
1753 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 int ret;
1755
Francois Romieu4876cc12011-03-11 21:07:11 +01001756 del_timer_sync(&tp->timer);
1757
Francois Romieuda78dbf2012-01-26 14:18:23 +01001758 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001759 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001760 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001761 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 return ret;
1764}
1765
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001766static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1767 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
Francois Romieud58d46b2011-05-03 16:38:29 +02001769 struct rtl8169_private *tp = netdev_priv(dev);
1770
Francois Romieu2b7b4312011-04-18 22:53:24 -07001771 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001772 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
Francois Romieud58d46b2011-05-03 16:38:29 +02001774 if (dev->mtu > JUMBO_1K &&
1775 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1776 features &= ~NETIF_F_IP_CSUM;
1777
Michał Mirosław350fb322011-04-08 06:35:56 +00001778 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779}
1780
Francois Romieuda78dbf2012-01-26 14:18:23 +01001781static void __rtl8169_set_features(struct net_device *dev,
1782 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783{
1784 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001785 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001786 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Ben Greear6bbe0212012-02-10 15:04:33 +00001788 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1789 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Ben Greear6bbe0212012-02-10 15:04:33 +00001791 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1792 if (features & NETIF_F_RXCSUM)
1793 tp->cp_cmd |= RxChkSum;
1794 else
1795 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001796
Ben Greear6bbe0212012-02-10 15:04:33 +00001797 if (dev->features & NETIF_F_HW_VLAN_RX)
1798 tp->cp_cmd |= RxVlan;
1799 else
1800 tp->cp_cmd &= ~RxVlan;
1801
1802 RTL_W16(CPlusCmd, tp->cp_cmd);
1803 RTL_R16(CPlusCmd);
1804 }
1805 if (changed & NETIF_F_RXALL) {
1806 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1807 if (features & NETIF_F_RXALL)
1808 tmp |= (AcceptErr | AcceptRunt);
1809 RTL_W32(RxConfig, tmp);
1810 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001811}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Francois Romieuda78dbf2012-01-26 14:18:23 +01001813static int rtl8169_set_features(struct net_device *dev,
1814 netdev_features_t features)
1815{
1816 struct rtl8169_private *tp = netdev_priv(dev);
1817
1818 rtl_lock_work(tp);
1819 __rtl8169_set_features(dev, features);
1820 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822 return 0;
1823}
1824
Francois Romieuda78dbf2012-01-26 14:18:23 +01001825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1827 struct sk_buff *skb)
1828{
Jesse Grosseab6d182010-10-20 13:56:03 +00001829 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1831}
1832
Francois Romieu7a8fc772011-03-01 17:18:33 +01001833static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
1835 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
Francois Romieu7a8fc772011-03-01 17:18:33 +01001837 if (opts2 & RxVlanTag)
1838 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Eric Dumazet2edae082010-09-06 18:46:39 +00001839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 desc->opts2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841}
1842
Francois Romieuccdffb92008-07-26 14:26:06 +02001843static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844{
1845 struct rtl8169_private *tp = netdev_priv(dev);
1846 void __iomem *ioaddr = tp->mmio_addr;
1847 u32 status;
1848
1849 cmd->supported =
1850 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1851 cmd->port = PORT_FIBRE;
1852 cmd->transceiver = XCVR_INTERNAL;
1853
1854 status = RTL_R32(TBICSR);
1855 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1856 cmd->autoneg = !!(status & TBINwEnable);
1857
David Decotigny70739492011-04-27 18:32:40 +00001858 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001860
1861 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
Francois Romieuccdffb92008-07-26 14:26:06 +02001864static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865{
1866 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
Francois Romieuccdffb92008-07-26 14:26:06 +02001868 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869}
1870
1871static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1872{
1873 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001874 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
Francois Romieuda78dbf2012-01-26 14:18:23 +01001876 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001877 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001878 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Francois Romieuccdffb92008-07-26 14:26:06 +02001880 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881}
1882
1883static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1884 void *p)
1885{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001886 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Francois Romieu5b0384f2006-08-16 16:00:01 +02001888 if (regs->len > R8169_REGS_SIZE)
1889 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Francois Romieuda78dbf2012-01-26 14:18:23 +01001891 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001892 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001893 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894}
1895
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001896static u32 rtl8169_get_msglevel(struct net_device *dev)
1897{
1898 struct rtl8169_private *tp = netdev_priv(dev);
1899
1900 return tp->msg_enable;
1901}
1902
1903static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1904{
1905 struct rtl8169_private *tp = netdev_priv(dev);
1906
1907 tp->msg_enable = value;
1908}
1909
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001910static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1911 "tx_packets",
1912 "rx_packets",
1913 "tx_errors",
1914 "rx_errors",
1915 "rx_missed",
1916 "align_errors",
1917 "tx_single_collisions",
1918 "tx_multi_collisions",
1919 "unicast",
1920 "broadcast",
1921 "multicast",
1922 "tx_aborted",
1923 "tx_underrun",
1924};
1925
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001926static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001927{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001928 switch (sset) {
1929 case ETH_SS_STATS:
1930 return ARRAY_SIZE(rtl8169_gstrings);
1931 default:
1932 return -EOPNOTSUPP;
1933 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001934}
1935
Francois Romieuffc46952012-07-06 14:19:23 +02001936DECLARE_RTL_COND(rtl_counters_cond)
1937{
1938 void __iomem *ioaddr = tp->mmio_addr;
1939
1940 return RTL_R32(CounterAddrLow) & CounterDump;
1941}
1942
Ivan Vecera355423d2009-02-06 21:49:57 -08001943static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001944{
1945 struct rtl8169_private *tp = netdev_priv(dev);
1946 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001947 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001948 struct rtl8169_counters *counters;
1949 dma_addr_t paddr;
1950 u32 cmd;
1951
Ivan Vecera355423d2009-02-06 21:49:57 -08001952 /*
1953 * Some chips are unable to dump tally counters when the receiver
1954 * is disabled.
1955 */
1956 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1957 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001958
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001959 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001960 if (!counters)
1961 return;
1962
1963 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001964 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001965 RTL_W32(CounterAddrLow, cmd);
1966 RTL_W32(CounterAddrLow, cmd | CounterDump);
1967
Francois Romieuffc46952012-07-06 14:19:23 +02001968 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1969 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001970
1971 RTL_W32(CounterAddrLow, 0);
1972 RTL_W32(CounterAddrHigh, 0);
1973
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001974 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001975}
1976
Ivan Vecera355423d2009-02-06 21:49:57 -08001977static void rtl8169_get_ethtool_stats(struct net_device *dev,
1978 struct ethtool_stats *stats, u64 *data)
1979{
1980 struct rtl8169_private *tp = netdev_priv(dev);
1981
1982 ASSERT_RTNL();
1983
1984 rtl8169_update_counters(dev);
1985
1986 data[0] = le64_to_cpu(tp->counters.tx_packets);
1987 data[1] = le64_to_cpu(tp->counters.rx_packets);
1988 data[2] = le64_to_cpu(tp->counters.tx_errors);
1989 data[3] = le32_to_cpu(tp->counters.rx_errors);
1990 data[4] = le16_to_cpu(tp->counters.rx_missed);
1991 data[5] = le16_to_cpu(tp->counters.align_errors);
1992 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1993 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1994 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1995 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1996 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1997 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1998 data[12] = le16_to_cpu(tp->counters.tx_underun);
1999}
2000
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002001static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
2002{
2003 switch(stringset) {
2004 case ETH_SS_STATS:
2005 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
2006 break;
2007 }
2008}
2009
Jeff Garzik7282d492006-09-13 14:30:00 -04002010static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 .get_drvinfo = rtl8169_get_drvinfo,
2012 .get_regs_len = rtl8169_get_regs_len,
2013 .get_link = ethtool_op_get_link,
2014 .get_settings = rtl8169_get_settings,
2015 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002016 .get_msglevel = rtl8169_get_msglevel,
2017 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002019 .get_wol = rtl8169_get_wol,
2020 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002021 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002022 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002023 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002024 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025};
2026
Francois Romieu07d3f512007-02-21 22:40:46 +01002027static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002028 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
Francois Romieu5d320a22011-05-08 17:47:36 +02002030 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002031 /*
2032 * The driver currently handles the 8168Bf and the 8168Be identically
2033 * but they can be identified more specifically through the test below
2034 * if needed:
2035 *
2036 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002037 *
2038 * Same thing for the 8101Eb and the 8101Ec:
2039 *
2040 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002041 */
Francois Romieu37441002011-06-17 22:58:54 +02002042 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002044 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 int mac_version;
2046 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002047 /* 8168G family. */
2048 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2049 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2050
Hayes Wangc2218922011-09-06 16:55:18 +08002051 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002052 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002053 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2054 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2055
hayeswang01dc7fe2011-03-21 01:50:28 +00002056 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002057 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002058 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2059 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2060 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2061
Francois Romieu5b538df2008-07-20 16:22:45 +02002062 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002063 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2064 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002065 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002066
françois romieue6de30d2011-01-03 15:08:37 +00002067 /* 8168DP family. */
2068 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2069 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002070 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002071
Francois Romieuef808d52008-06-29 13:10:54 +02002072 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002073 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002074 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002075 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002076 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002077 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2078 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002079 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002080 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002081 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002082
2083 /* 8168B family. */
2084 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2085 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2086 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2087 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2088
2089 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002090 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2091 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002092 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002093 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002094 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2095 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2096 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002097 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2098 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2099 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2100 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2101 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2102 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002103 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002104 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002105 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002106 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2107 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002108 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2109 /* FIXME: where did these entries come from ? -- FR */
2110 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2111 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2112
2113 /* 8110 family. */
2114 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2115 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2116 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2117 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2118 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2119 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2120
Jean Delvaref21b75e2009-05-26 20:54:48 -07002121 /* Catch-all */
2122 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002123 };
2124 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 u32 reg;
2126
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002127 reg = RTL_R32(TxConfig);
2128 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 p++;
2130 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002131
2132 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2133 netif_notice(tp, probe, dev,
2134 "unknown MAC, using family default\n");
2135 tp->mac_version = default_version;
2136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137}
2138
2139static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2140{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002141 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142}
2143
Francois Romieu867763c2007-08-17 18:21:58 +02002144struct phy_reg {
2145 u16 reg;
2146 u16 val;
2147};
2148
françois romieu4da19632011-01-03 15:07:55 +00002149static void rtl_writephy_batch(struct rtl8169_private *tp,
2150 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002151{
2152 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002153 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002154 regs++;
2155 }
2156}
2157
françois romieubca03d52011-01-03 15:07:31 +00002158#define PHY_READ 0x00000000
2159#define PHY_DATA_OR 0x10000000
2160#define PHY_DATA_AND 0x20000000
2161#define PHY_BJMPN 0x30000000
2162#define PHY_READ_EFUSE 0x40000000
2163#define PHY_READ_MAC_BYTE 0x50000000
2164#define PHY_WRITE_MAC_BYTE 0x60000000
2165#define PHY_CLEAR_READCOUNT 0x70000000
2166#define PHY_WRITE 0x80000000
2167#define PHY_READCOUNT_EQ_SKIP 0x90000000
2168#define PHY_COMP_EQ_SKIPN 0xa0000000
2169#define PHY_COMP_NEQ_SKIPN 0xb0000000
2170#define PHY_WRITE_PREVIOUS 0xc0000000
2171#define PHY_SKIPN 0xd0000000
2172#define PHY_DELAY_MS 0xe0000000
2173#define PHY_WRITE_ERI_WORD 0xf0000000
2174
Hayes Wang960aee62011-06-18 11:37:48 +02002175struct fw_info {
2176 u32 magic;
2177 char version[RTL_VER_SIZE];
2178 __le32 fw_start;
2179 __le32 fw_len;
2180 u8 chksum;
2181} __packed;
2182
Francois Romieu1c361ef2011-06-17 17:16:24 +02002183#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2184
2185static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002186{
Francois Romieub6ffd972011-06-17 17:00:05 +02002187 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002188 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002189 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2190 char *version = rtl_fw->version;
2191 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002192
Francois Romieu1c361ef2011-06-17 17:16:24 +02002193 if (fw->size < FW_OPCODE_SIZE)
2194 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002195
2196 if (!fw_info->magic) {
2197 size_t i, size, start;
2198 u8 checksum = 0;
2199
2200 if (fw->size < sizeof(*fw_info))
2201 goto out;
2202
2203 for (i = 0; i < fw->size; i++)
2204 checksum += fw->data[i];
2205 if (checksum != 0)
2206 goto out;
2207
2208 start = le32_to_cpu(fw_info->fw_start);
2209 if (start > fw->size)
2210 goto out;
2211
2212 size = le32_to_cpu(fw_info->fw_len);
2213 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2214 goto out;
2215
2216 memcpy(version, fw_info->version, RTL_VER_SIZE);
2217
2218 pa->code = (__le32 *)(fw->data + start);
2219 pa->size = size;
2220 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002221 if (fw->size % FW_OPCODE_SIZE)
2222 goto out;
2223
2224 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2225
2226 pa->code = (__le32 *)fw->data;
2227 pa->size = fw->size / FW_OPCODE_SIZE;
2228 }
2229 version[RTL_VER_SIZE - 1] = 0;
2230
2231 rc = true;
2232out:
2233 return rc;
2234}
2235
Francois Romieufd112f22011-06-18 00:10:29 +02002236static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2237 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002238{
Francois Romieufd112f22011-06-18 00:10:29 +02002239 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002240 size_t index;
2241
Francois Romieu1c361ef2011-06-17 17:16:24 +02002242 for (index = 0; index < pa->size; index++) {
2243 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002244 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002245
hayeswang42b82dc2011-01-10 02:07:25 +00002246 switch(action & 0xf0000000) {
2247 case PHY_READ:
2248 case PHY_DATA_OR:
2249 case PHY_DATA_AND:
2250 case PHY_READ_EFUSE:
2251 case PHY_CLEAR_READCOUNT:
2252 case PHY_WRITE:
2253 case PHY_WRITE_PREVIOUS:
2254 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002255 break;
2256
hayeswang42b82dc2011-01-10 02:07:25 +00002257 case PHY_BJMPN:
2258 if (regno > index) {
Francois Romieufd112f22011-06-18 00:10:29 +02002259 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002260 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002261 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002262 }
2263 break;
2264 case PHY_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002265 if (index + 2 >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002266 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002267 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002268 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002269 }
2270 break;
2271 case PHY_COMP_EQ_SKIPN:
2272 case PHY_COMP_NEQ_SKIPN:
2273 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002274 if (index + 1 + regno >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002275 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002276 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002277 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002278 }
2279 break;
2280
2281 case PHY_READ_MAC_BYTE:
2282 case PHY_WRITE_MAC_BYTE:
2283 case PHY_WRITE_ERI_WORD:
2284 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002285 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002286 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002287 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002288 }
2289 }
Francois Romieufd112f22011-06-18 00:10:29 +02002290 rc = true;
2291out:
2292 return rc;
2293}
françois romieubca03d52011-01-03 15:07:31 +00002294
Francois Romieufd112f22011-06-18 00:10:29 +02002295static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2296{
2297 struct net_device *dev = tp->dev;
2298 int rc = -EINVAL;
2299
2300 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2301 netif_err(tp, ifup, dev, "invalid firwmare\n");
2302 goto out;
2303 }
2304
2305 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2306 rc = 0;
2307out:
2308 return rc;
2309}
2310
2311static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2312{
2313 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2314 u32 predata, count;
2315 size_t index;
2316
2317 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002318
Francois Romieu1c361ef2011-06-17 17:16:24 +02002319 for (index = 0; index < pa->size; ) {
2320 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002321 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002322 u32 regno = (action & 0x0fff0000) >> 16;
2323
2324 if (!action)
2325 break;
françois romieubca03d52011-01-03 15:07:31 +00002326
2327 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002328 case PHY_READ:
2329 predata = rtl_readphy(tp, regno);
2330 count++;
2331 index++;
françois romieubca03d52011-01-03 15:07:31 +00002332 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002333 case PHY_DATA_OR:
2334 predata |= data;
2335 index++;
2336 break;
2337 case PHY_DATA_AND:
2338 predata &= data;
2339 index++;
2340 break;
2341 case PHY_BJMPN:
2342 index -= regno;
2343 break;
2344 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002345 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002346 index++;
2347 break;
2348 case PHY_CLEAR_READCOUNT:
2349 count = 0;
2350 index++;
2351 break;
2352 case PHY_WRITE:
2353 rtl_writephy(tp, regno, data);
2354 index++;
2355 break;
2356 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002357 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002358 break;
2359 case PHY_COMP_EQ_SKIPN:
2360 if (predata == data)
2361 index += regno;
2362 index++;
2363 break;
2364 case PHY_COMP_NEQ_SKIPN:
2365 if (predata != data)
2366 index += regno;
2367 index++;
2368 break;
2369 case PHY_WRITE_PREVIOUS:
2370 rtl_writephy(tp, regno, predata);
2371 index++;
2372 break;
2373 case PHY_SKIPN:
2374 index += regno + 1;
2375 break;
2376 case PHY_DELAY_MS:
2377 mdelay(data);
2378 index++;
2379 break;
2380
2381 case PHY_READ_MAC_BYTE:
2382 case PHY_WRITE_MAC_BYTE:
2383 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002384 default:
2385 BUG();
2386 }
2387 }
2388}
2389
françois romieuf1e02ed2011-01-13 13:07:53 +00002390static void rtl_release_firmware(struct rtl8169_private *tp)
2391{
Francois Romieub6ffd972011-06-17 17:00:05 +02002392 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2393 release_firmware(tp->rtl_fw->fw);
2394 kfree(tp->rtl_fw);
2395 }
2396 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002397}
2398
François Romieu953a12c2011-04-24 17:38:48 +02002399static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002400{
Francois Romieub6ffd972011-06-17 17:00:05 +02002401 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002402
2403 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
Francois Romieub6ffd972011-06-17 17:00:05 +02002404 if (!IS_ERR_OR_NULL(rtl_fw))
2405 rtl_phy_write_fw(tp, rtl_fw);
François Romieu953a12c2011-04-24 17:38:48 +02002406}
2407
2408static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2409{
2410 if (rtl_readphy(tp, reg) != val)
2411 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2412 else
2413 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002414}
2415
françois romieu4da19632011-01-03 15:07:55 +00002416static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002418 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002419 { 0x1f, 0x0001 },
2420 { 0x06, 0x006e },
2421 { 0x08, 0x0708 },
2422 { 0x15, 0x4000 },
2423 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
françois romieu0b9b5712009-08-10 19:44:56 +00002425 { 0x1f, 0x0001 },
2426 { 0x03, 0x00a1 },
2427 { 0x02, 0x0008 },
2428 { 0x01, 0x0120 },
2429 { 0x00, 0x1000 },
2430 { 0x04, 0x0800 },
2431 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
françois romieu0b9b5712009-08-10 19:44:56 +00002433 { 0x03, 0xff41 },
2434 { 0x02, 0xdf60 },
2435 { 0x01, 0x0140 },
2436 { 0x00, 0x0077 },
2437 { 0x04, 0x7800 },
2438 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
françois romieu0b9b5712009-08-10 19:44:56 +00002440 { 0x03, 0x802f },
2441 { 0x02, 0x4f02 },
2442 { 0x01, 0x0409 },
2443 { 0x00, 0xf0f9 },
2444 { 0x04, 0x9800 },
2445 { 0x04, 0x9000 },
2446
2447 { 0x03, 0xdf01 },
2448 { 0x02, 0xdf20 },
2449 { 0x01, 0xff95 },
2450 { 0x00, 0xba00 },
2451 { 0x04, 0xa800 },
2452 { 0x04, 0xa000 },
2453
2454 { 0x03, 0xff41 },
2455 { 0x02, 0xdf20 },
2456 { 0x01, 0x0140 },
2457 { 0x00, 0x00bb },
2458 { 0x04, 0xb800 },
2459 { 0x04, 0xb000 },
2460
2461 { 0x03, 0xdf41 },
2462 { 0x02, 0xdc60 },
2463 { 0x01, 0x6340 },
2464 { 0x00, 0x007d },
2465 { 0x04, 0xd800 },
2466 { 0x04, 0xd000 },
2467
2468 { 0x03, 0xdf01 },
2469 { 0x02, 0xdf20 },
2470 { 0x01, 0x100a },
2471 { 0x00, 0xa0ff },
2472 { 0x04, 0xf800 },
2473 { 0x04, 0xf000 },
2474
2475 { 0x1f, 0x0000 },
2476 { 0x0b, 0x0000 },
2477 { 0x00, 0x9200 }
2478 };
2479
françois romieu4da19632011-01-03 15:07:55 +00002480 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481}
2482
françois romieu4da19632011-01-03 15:07:55 +00002483static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002484{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002485 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002486 { 0x1f, 0x0002 },
2487 { 0x01, 0x90d0 },
2488 { 0x1f, 0x0000 }
2489 };
2490
françois romieu4da19632011-01-03 15:07:55 +00002491 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002492}
2493
françois romieu4da19632011-01-03 15:07:55 +00002494static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002495{
2496 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002497
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002498 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2499 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002500 return;
2501
françois romieu4da19632011-01-03 15:07:55 +00002502 rtl_writephy(tp, 0x1f, 0x0001);
2503 rtl_writephy(tp, 0x10, 0xf01b);
2504 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002505}
2506
françois romieu4da19632011-01-03 15:07:55 +00002507static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002508{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002509 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002510 { 0x1f, 0x0001 },
2511 { 0x04, 0x0000 },
2512 { 0x03, 0x00a1 },
2513 { 0x02, 0x0008 },
2514 { 0x01, 0x0120 },
2515 { 0x00, 0x1000 },
2516 { 0x04, 0x0800 },
2517 { 0x04, 0x9000 },
2518 { 0x03, 0x802f },
2519 { 0x02, 0x4f02 },
2520 { 0x01, 0x0409 },
2521 { 0x00, 0xf099 },
2522 { 0x04, 0x9800 },
2523 { 0x04, 0xa000 },
2524 { 0x03, 0xdf01 },
2525 { 0x02, 0xdf20 },
2526 { 0x01, 0xff95 },
2527 { 0x00, 0xba00 },
2528 { 0x04, 0xa800 },
2529 { 0x04, 0xf000 },
2530 { 0x03, 0xdf01 },
2531 { 0x02, 0xdf20 },
2532 { 0x01, 0x101a },
2533 { 0x00, 0xa0ff },
2534 { 0x04, 0xf800 },
2535 { 0x04, 0x0000 },
2536 { 0x1f, 0x0000 },
2537
2538 { 0x1f, 0x0001 },
2539 { 0x10, 0xf41b },
2540 { 0x14, 0xfb54 },
2541 { 0x18, 0xf5c7 },
2542 { 0x1f, 0x0000 },
2543
2544 { 0x1f, 0x0001 },
2545 { 0x17, 0x0cc0 },
2546 { 0x1f, 0x0000 }
2547 };
2548
françois romieu4da19632011-01-03 15:07:55 +00002549 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002550
françois romieu4da19632011-01-03 15:07:55 +00002551 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002552}
2553
françois romieu4da19632011-01-03 15:07:55 +00002554static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002555{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002556 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002557 { 0x1f, 0x0001 },
2558 { 0x04, 0x0000 },
2559 { 0x03, 0x00a1 },
2560 { 0x02, 0x0008 },
2561 { 0x01, 0x0120 },
2562 { 0x00, 0x1000 },
2563 { 0x04, 0x0800 },
2564 { 0x04, 0x9000 },
2565 { 0x03, 0x802f },
2566 { 0x02, 0x4f02 },
2567 { 0x01, 0x0409 },
2568 { 0x00, 0xf099 },
2569 { 0x04, 0x9800 },
2570 { 0x04, 0xa000 },
2571 { 0x03, 0xdf01 },
2572 { 0x02, 0xdf20 },
2573 { 0x01, 0xff95 },
2574 { 0x00, 0xba00 },
2575 { 0x04, 0xa800 },
2576 { 0x04, 0xf000 },
2577 { 0x03, 0xdf01 },
2578 { 0x02, 0xdf20 },
2579 { 0x01, 0x101a },
2580 { 0x00, 0xa0ff },
2581 { 0x04, 0xf800 },
2582 { 0x04, 0x0000 },
2583 { 0x1f, 0x0000 },
2584
2585 { 0x1f, 0x0001 },
2586 { 0x0b, 0x8480 },
2587 { 0x1f, 0x0000 },
2588
2589 { 0x1f, 0x0001 },
2590 { 0x18, 0x67c7 },
2591 { 0x04, 0x2000 },
2592 { 0x03, 0x002f },
2593 { 0x02, 0x4360 },
2594 { 0x01, 0x0109 },
2595 { 0x00, 0x3022 },
2596 { 0x04, 0x2800 },
2597 { 0x1f, 0x0000 },
2598
2599 { 0x1f, 0x0001 },
2600 { 0x17, 0x0cc0 },
2601 { 0x1f, 0x0000 }
2602 };
2603
françois romieu4da19632011-01-03 15:07:55 +00002604 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002605}
2606
françois romieu4da19632011-01-03 15:07:55 +00002607static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002608{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002609 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002610 { 0x10, 0xf41b },
2611 { 0x1f, 0x0000 }
2612 };
2613
françois romieu4da19632011-01-03 15:07:55 +00002614 rtl_writephy(tp, 0x1f, 0x0001);
2615 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002616
françois romieu4da19632011-01-03 15:07:55 +00002617 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002618}
2619
françois romieu4da19632011-01-03 15:07:55 +00002620static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002621{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002622 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002623 { 0x1f, 0x0001 },
2624 { 0x10, 0xf41b },
2625 { 0x1f, 0x0000 }
2626 };
2627
françois romieu4da19632011-01-03 15:07:55 +00002628 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002629}
2630
françois romieu4da19632011-01-03 15:07:55 +00002631static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002632{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002633 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002634 { 0x1f, 0x0000 },
2635 { 0x1d, 0x0f00 },
2636 { 0x1f, 0x0002 },
2637 { 0x0c, 0x1ec8 },
2638 { 0x1f, 0x0000 }
2639 };
2640
françois romieu4da19632011-01-03 15:07:55 +00002641 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002642}
2643
françois romieu4da19632011-01-03 15:07:55 +00002644static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002645{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002646 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002647 { 0x1f, 0x0001 },
2648 { 0x1d, 0x3d98 },
2649 { 0x1f, 0x0000 }
2650 };
2651
françois romieu4da19632011-01-03 15:07:55 +00002652 rtl_writephy(tp, 0x1f, 0x0000);
2653 rtl_patchphy(tp, 0x14, 1 << 5);
2654 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002655
françois romieu4da19632011-01-03 15:07:55 +00002656 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002657}
2658
françois romieu4da19632011-01-03 15:07:55 +00002659static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002660{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002661 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002662 { 0x1f, 0x0001 },
2663 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002664 { 0x1f, 0x0002 },
2665 { 0x00, 0x88d4 },
2666 { 0x01, 0x82b1 },
2667 { 0x03, 0x7002 },
2668 { 0x08, 0x9e30 },
2669 { 0x09, 0x01f0 },
2670 { 0x0a, 0x5500 },
2671 { 0x0c, 0x00c8 },
2672 { 0x1f, 0x0003 },
2673 { 0x12, 0xc096 },
2674 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002675 { 0x1f, 0x0000 },
2676 { 0x1f, 0x0000 },
2677 { 0x09, 0x2000 },
2678 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002679 };
2680
françois romieu4da19632011-01-03 15:07:55 +00002681 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002682
françois romieu4da19632011-01-03 15:07:55 +00002683 rtl_patchphy(tp, 0x14, 1 << 5);
2684 rtl_patchphy(tp, 0x0d, 1 << 5);
2685 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002686}
2687
françois romieu4da19632011-01-03 15:07:55 +00002688static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002689{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002690 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002691 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002692 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002693 { 0x03, 0x802f },
2694 { 0x02, 0x4f02 },
2695 { 0x01, 0x0409 },
2696 { 0x00, 0xf099 },
2697 { 0x04, 0x9800 },
2698 { 0x04, 0x9000 },
2699 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002700 { 0x1f, 0x0002 },
2701 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002702 { 0x06, 0x0761 },
2703 { 0x1f, 0x0003 },
2704 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002705 { 0x1f, 0x0000 }
2706 };
2707
françois romieu4da19632011-01-03 15:07:55 +00002708 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002709
françois romieu4da19632011-01-03 15:07:55 +00002710 rtl_patchphy(tp, 0x16, 1 << 0);
2711 rtl_patchphy(tp, 0x14, 1 << 5);
2712 rtl_patchphy(tp, 0x0d, 1 << 5);
2713 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002714}
2715
françois romieu4da19632011-01-03 15:07:55 +00002716static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002717{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002718 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002719 { 0x1f, 0x0001 },
2720 { 0x12, 0x2300 },
2721 { 0x1d, 0x3d98 },
2722 { 0x1f, 0x0002 },
2723 { 0x0c, 0x7eb8 },
2724 { 0x06, 0x5461 },
2725 { 0x1f, 0x0003 },
2726 { 0x16, 0x0f0a },
2727 { 0x1f, 0x0000 }
2728 };
2729
françois romieu4da19632011-01-03 15:07:55 +00002730 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002731
françois romieu4da19632011-01-03 15:07:55 +00002732 rtl_patchphy(tp, 0x16, 1 << 0);
2733 rtl_patchphy(tp, 0x14, 1 << 5);
2734 rtl_patchphy(tp, 0x0d, 1 << 5);
2735 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002736}
2737
françois romieu4da19632011-01-03 15:07:55 +00002738static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002739{
françois romieu4da19632011-01-03 15:07:55 +00002740 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002741}
2742
françois romieubca03d52011-01-03 15:07:31 +00002743static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002744{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002745 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002746 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002747 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002748 { 0x06, 0x4064 },
2749 { 0x07, 0x2863 },
2750 { 0x08, 0x059c },
2751 { 0x09, 0x26b4 },
2752 { 0x0a, 0x6a19 },
2753 { 0x0b, 0xdcc8 },
2754 { 0x10, 0xf06d },
2755 { 0x14, 0x7f68 },
2756 { 0x18, 0x7fd9 },
2757 { 0x1c, 0xf0ff },
2758 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002759 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002760 { 0x12, 0xf49f },
2761 { 0x13, 0x070b },
2762 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002763 { 0x14, 0x94c0 },
2764
2765 /*
2766 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002767 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002768 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002769 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002770 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002771 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002772 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002773 { 0x06, 0x5561 },
2774
2775 /*
2776 * Can not link to 1Gbps with bad cable
2777 * Decrease SNR threshold form 21.07dB to 19.04dB
2778 */
2779 { 0x1f, 0x0001 },
2780 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002781
2782 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002783 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002784 };
2785
françois romieu4da19632011-01-03 15:07:55 +00002786 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002787
françois romieubca03d52011-01-03 15:07:31 +00002788 /*
2789 * Rx Error Issue
2790 * Fine Tune Switching regulator parameter
2791 */
françois romieu4da19632011-01-03 15:07:55 +00002792 rtl_writephy(tp, 0x1f, 0x0002);
2793 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2794 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002795
Francois Romieufdf6fc02012-07-06 22:40:38 +02002796 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002797 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002798 { 0x1f, 0x0002 },
2799 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002800 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002801 { 0x05, 0x8330 },
2802 { 0x06, 0x669a },
2803 { 0x1f, 0x0002 }
2804 };
2805 int val;
2806
françois romieu4da19632011-01-03 15:07:55 +00002807 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002808
françois romieu4da19632011-01-03 15:07:55 +00002809 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002810
2811 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002812 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002813 0x0065, 0x0066, 0x0067, 0x0068,
2814 0x0069, 0x006a, 0x006b, 0x006c
2815 };
2816 int i;
2817
françois romieu4da19632011-01-03 15:07:55 +00002818 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002819
2820 val &= 0xff00;
2821 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002822 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002823 }
2824 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002825 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002826 { 0x1f, 0x0002 },
2827 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002828 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002829 { 0x05, 0x8330 },
2830 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002831 };
2832
françois romieu4da19632011-01-03 15:07:55 +00002833 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002834 }
2835
françois romieubca03d52011-01-03 15:07:31 +00002836 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002837 rtl_writephy(tp, 0x1f, 0x0002);
2838 rtl_patchphy(tp, 0x0d, 0x0300);
2839 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002840
françois romieubca03d52011-01-03 15:07:31 +00002841 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002842 rtl_writephy(tp, 0x1f, 0x0002);
2843 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2844 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002845
françois romieu4da19632011-01-03 15:07:55 +00002846 rtl_writephy(tp, 0x1f, 0x0005);
2847 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002848
2849 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002850
françois romieu4da19632011-01-03 15:07:55 +00002851 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002852}
2853
françois romieubca03d52011-01-03 15:07:31 +00002854static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002855{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002856 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002857 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002858 { 0x1f, 0x0001 },
2859 { 0x06, 0x4064 },
2860 { 0x07, 0x2863 },
2861 { 0x08, 0x059c },
2862 { 0x09, 0x26b4 },
2863 { 0x0a, 0x6a19 },
2864 { 0x0b, 0xdcc8 },
2865 { 0x10, 0xf06d },
2866 { 0x14, 0x7f68 },
2867 { 0x18, 0x7fd9 },
2868 { 0x1c, 0xf0ff },
2869 { 0x1d, 0x3d9c },
2870 { 0x1f, 0x0003 },
2871 { 0x12, 0xf49f },
2872 { 0x13, 0x070b },
2873 { 0x1a, 0x05ad },
2874 { 0x14, 0x94c0 },
2875
françois romieubca03d52011-01-03 15:07:31 +00002876 /*
2877 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002878 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002879 */
françois romieudaf9df62009-10-07 12:44:20 +00002880 { 0x1f, 0x0002 },
2881 { 0x06, 0x5561 },
2882 { 0x1f, 0x0005 },
2883 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002884 { 0x06, 0x5561 },
2885
2886 /*
2887 * Can not link to 1Gbps with bad cable
2888 * Decrease SNR threshold form 21.07dB to 19.04dB
2889 */
2890 { 0x1f, 0x0001 },
2891 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002892
2893 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002894 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002895 };
2896
françois romieu4da19632011-01-03 15:07:55 +00002897 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002898
Francois Romieufdf6fc02012-07-06 22:40:38 +02002899 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002900 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002901 { 0x1f, 0x0002 },
2902 { 0x05, 0x669a },
2903 { 0x1f, 0x0005 },
2904 { 0x05, 0x8330 },
2905 { 0x06, 0x669a },
2906
2907 { 0x1f, 0x0002 }
2908 };
2909 int val;
2910
françois romieu4da19632011-01-03 15:07:55 +00002911 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002912
françois romieu4da19632011-01-03 15:07:55 +00002913 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002914 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002915 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002916 0x0065, 0x0066, 0x0067, 0x0068,
2917 0x0069, 0x006a, 0x006b, 0x006c
2918 };
2919 int i;
2920
françois romieu4da19632011-01-03 15:07:55 +00002921 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002922
2923 val &= 0xff00;
2924 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002925 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002926 }
2927 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002928 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002929 { 0x1f, 0x0002 },
2930 { 0x05, 0x2642 },
2931 { 0x1f, 0x0005 },
2932 { 0x05, 0x8330 },
2933 { 0x06, 0x2642 }
2934 };
2935
françois romieu4da19632011-01-03 15:07:55 +00002936 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002937 }
2938
françois romieubca03d52011-01-03 15:07:31 +00002939 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002940 rtl_writephy(tp, 0x1f, 0x0002);
2941 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2942 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002943
françois romieubca03d52011-01-03 15:07:31 +00002944 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002945 rtl_writephy(tp, 0x1f, 0x0002);
2946 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002947
françois romieu4da19632011-01-03 15:07:55 +00002948 rtl_writephy(tp, 0x1f, 0x0005);
2949 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002950
2951 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002952
françois romieu4da19632011-01-03 15:07:55 +00002953 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002954}
2955
françois romieu4da19632011-01-03 15:07:55 +00002956static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002957{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002958 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002959 { 0x1f, 0x0002 },
2960 { 0x10, 0x0008 },
2961 { 0x0d, 0x006c },
2962
2963 { 0x1f, 0x0000 },
2964 { 0x0d, 0xf880 },
2965
2966 { 0x1f, 0x0001 },
2967 { 0x17, 0x0cc0 },
2968
2969 { 0x1f, 0x0001 },
2970 { 0x0b, 0xa4d8 },
2971 { 0x09, 0x281c },
2972 { 0x07, 0x2883 },
2973 { 0x0a, 0x6b35 },
2974 { 0x1d, 0x3da4 },
2975 { 0x1c, 0xeffd },
2976 { 0x14, 0x7f52 },
2977 { 0x18, 0x7fc6 },
2978 { 0x08, 0x0601 },
2979 { 0x06, 0x4063 },
2980 { 0x10, 0xf074 },
2981 { 0x1f, 0x0003 },
2982 { 0x13, 0x0789 },
2983 { 0x12, 0xf4bd },
2984 { 0x1a, 0x04fd },
2985 { 0x14, 0x84b0 },
2986 { 0x1f, 0x0000 },
2987 { 0x00, 0x9200 },
2988
2989 { 0x1f, 0x0005 },
2990 { 0x01, 0x0340 },
2991 { 0x1f, 0x0001 },
2992 { 0x04, 0x4000 },
2993 { 0x03, 0x1d21 },
2994 { 0x02, 0x0c32 },
2995 { 0x01, 0x0200 },
2996 { 0x00, 0x5554 },
2997 { 0x04, 0x4800 },
2998 { 0x04, 0x4000 },
2999 { 0x04, 0xf000 },
3000 { 0x03, 0xdf01 },
3001 { 0x02, 0xdf20 },
3002 { 0x01, 0x101a },
3003 { 0x00, 0xa0ff },
3004 { 0x04, 0xf800 },
3005 { 0x04, 0xf000 },
3006 { 0x1f, 0x0000 },
3007
3008 { 0x1f, 0x0007 },
3009 { 0x1e, 0x0023 },
3010 { 0x16, 0x0000 },
3011 { 0x1f, 0x0000 }
3012 };
3013
françois romieu4da19632011-01-03 15:07:55 +00003014 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02003015}
3016
françois romieue6de30d2011-01-03 15:08:37 +00003017static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3018{
3019 static const struct phy_reg phy_reg_init[] = {
3020 { 0x1f, 0x0001 },
3021 { 0x17, 0x0cc0 },
3022
3023 { 0x1f, 0x0007 },
3024 { 0x1e, 0x002d },
3025 { 0x18, 0x0040 },
3026 { 0x1f, 0x0000 }
3027 };
3028
3029 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3030 rtl_patchphy(tp, 0x0d, 1 << 5);
3031}
3032
Hayes Wang70090422011-07-06 15:58:06 +08003033static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003034{
3035 static const struct phy_reg phy_reg_init[] = {
3036 /* Enable Delay cap */
3037 { 0x1f, 0x0005 },
3038 { 0x05, 0x8b80 },
3039 { 0x06, 0xc896 },
3040 { 0x1f, 0x0000 },
3041
3042 /* Channel estimation fine tune */
3043 { 0x1f, 0x0001 },
3044 { 0x0b, 0x6c20 },
3045 { 0x07, 0x2872 },
3046 { 0x1c, 0xefff },
3047 { 0x1f, 0x0003 },
3048 { 0x14, 0x6420 },
3049 { 0x1f, 0x0000 },
3050
3051 /* Update PFM & 10M TX idle timer */
3052 { 0x1f, 0x0007 },
3053 { 0x1e, 0x002f },
3054 { 0x15, 0x1919 },
3055 { 0x1f, 0x0000 },
3056
3057 { 0x1f, 0x0007 },
3058 { 0x1e, 0x00ac },
3059 { 0x18, 0x0006 },
3060 { 0x1f, 0x0000 }
3061 };
3062
Francois Romieu15ecd032011-04-27 13:52:22 -07003063 rtl_apply_firmware(tp);
3064
hayeswang01dc7fe2011-03-21 01:50:28 +00003065 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3066
3067 /* DCO enable for 10M IDLE Power */
3068 rtl_writephy(tp, 0x1f, 0x0007);
3069 rtl_writephy(tp, 0x1e, 0x0023);
3070 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3071 rtl_writephy(tp, 0x1f, 0x0000);
3072
3073 /* For impedance matching */
3074 rtl_writephy(tp, 0x1f, 0x0002);
3075 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003076 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003077
3078 /* PHY auto speed down */
3079 rtl_writephy(tp, 0x1f, 0x0007);
3080 rtl_writephy(tp, 0x1e, 0x002d);
3081 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3082 rtl_writephy(tp, 0x1f, 0x0000);
3083 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3084
3085 rtl_writephy(tp, 0x1f, 0x0005);
3086 rtl_writephy(tp, 0x05, 0x8b86);
3087 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3088 rtl_writephy(tp, 0x1f, 0x0000);
3089
3090 rtl_writephy(tp, 0x1f, 0x0005);
3091 rtl_writephy(tp, 0x05, 0x8b85);
3092 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3093 rtl_writephy(tp, 0x1f, 0x0007);
3094 rtl_writephy(tp, 0x1e, 0x0020);
3095 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3096 rtl_writephy(tp, 0x1f, 0x0006);
3097 rtl_writephy(tp, 0x00, 0x5a00);
3098 rtl_writephy(tp, 0x1f, 0x0000);
3099 rtl_writephy(tp, 0x0d, 0x0007);
3100 rtl_writephy(tp, 0x0e, 0x003c);
3101 rtl_writephy(tp, 0x0d, 0x4007);
3102 rtl_writephy(tp, 0x0e, 0x0000);
3103 rtl_writephy(tp, 0x0d, 0x0000);
3104}
3105
Hayes Wang70090422011-07-06 15:58:06 +08003106static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3107{
3108 static const struct phy_reg phy_reg_init[] = {
3109 /* Enable Delay cap */
3110 { 0x1f, 0x0004 },
3111 { 0x1f, 0x0007 },
3112 { 0x1e, 0x00ac },
3113 { 0x18, 0x0006 },
3114 { 0x1f, 0x0002 },
3115 { 0x1f, 0x0000 },
3116 { 0x1f, 0x0000 },
3117
3118 /* Channel estimation fine tune */
3119 { 0x1f, 0x0003 },
3120 { 0x09, 0xa20f },
3121 { 0x1f, 0x0000 },
3122 { 0x1f, 0x0000 },
3123
3124 /* Green Setting */
3125 { 0x1f, 0x0005 },
3126 { 0x05, 0x8b5b },
3127 { 0x06, 0x9222 },
3128 { 0x05, 0x8b6d },
3129 { 0x06, 0x8000 },
3130 { 0x05, 0x8b76 },
3131 { 0x06, 0x8000 },
3132 { 0x1f, 0x0000 }
3133 };
3134
3135 rtl_apply_firmware(tp);
3136
3137 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3138
3139 /* For 4-corner performance improve */
3140 rtl_writephy(tp, 0x1f, 0x0005);
3141 rtl_writephy(tp, 0x05, 0x8b80);
3142 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3143 rtl_writephy(tp, 0x1f, 0x0000);
3144
3145 /* PHY auto speed down */
3146 rtl_writephy(tp, 0x1f, 0x0004);
3147 rtl_writephy(tp, 0x1f, 0x0007);
3148 rtl_writephy(tp, 0x1e, 0x002d);
3149 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3150 rtl_writephy(tp, 0x1f, 0x0002);
3151 rtl_writephy(tp, 0x1f, 0x0000);
3152 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3153
3154 /* improve 10M EEE waveform */
3155 rtl_writephy(tp, 0x1f, 0x0005);
3156 rtl_writephy(tp, 0x05, 0x8b86);
3157 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3158 rtl_writephy(tp, 0x1f, 0x0000);
3159
3160 /* Improve 2-pair detection performance */
3161 rtl_writephy(tp, 0x1f, 0x0005);
3162 rtl_writephy(tp, 0x05, 0x8b85);
3163 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3164 rtl_writephy(tp, 0x1f, 0x0000);
3165
3166 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003167 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003168 rtl_writephy(tp, 0x1f, 0x0005);
3169 rtl_writephy(tp, 0x05, 0x8b85);
3170 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3171 rtl_writephy(tp, 0x1f, 0x0004);
3172 rtl_writephy(tp, 0x1f, 0x0007);
3173 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003174 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003175 rtl_writephy(tp, 0x1f, 0x0002);
3176 rtl_writephy(tp, 0x1f, 0x0000);
3177 rtl_writephy(tp, 0x0d, 0x0007);
3178 rtl_writephy(tp, 0x0e, 0x003c);
3179 rtl_writephy(tp, 0x0d, 0x4007);
3180 rtl_writephy(tp, 0x0e, 0x0000);
3181 rtl_writephy(tp, 0x0d, 0x0000);
3182
3183 /* Green feature */
3184 rtl_writephy(tp, 0x1f, 0x0003);
3185 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3186 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3187 rtl_writephy(tp, 0x1f, 0x0000);
3188}
3189
Hayes Wang5f886e02012-03-30 14:33:03 +08003190static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3191{
3192 /* For 4-corner performance improve */
3193 rtl_writephy(tp, 0x1f, 0x0005);
3194 rtl_writephy(tp, 0x05, 0x8b80);
3195 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3196 rtl_writephy(tp, 0x1f, 0x0000);
3197
3198 /* PHY auto speed down */
3199 rtl_writephy(tp, 0x1f, 0x0007);
3200 rtl_writephy(tp, 0x1e, 0x002d);
3201 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3202 rtl_writephy(tp, 0x1f, 0x0000);
3203 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3204
3205 /* Improve 10M EEE waveform */
3206 rtl_writephy(tp, 0x1f, 0x0005);
3207 rtl_writephy(tp, 0x05, 0x8b86);
3208 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3209 rtl_writephy(tp, 0x1f, 0x0000);
3210}
3211
Hayes Wangc2218922011-09-06 16:55:18 +08003212static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3213{
3214 static const struct phy_reg phy_reg_init[] = {
3215 /* Channel estimation fine tune */
3216 { 0x1f, 0x0003 },
3217 { 0x09, 0xa20f },
3218 { 0x1f, 0x0000 },
3219
3220 /* Modify green table for giga & fnet */
3221 { 0x1f, 0x0005 },
3222 { 0x05, 0x8b55 },
3223 { 0x06, 0x0000 },
3224 { 0x05, 0x8b5e },
3225 { 0x06, 0x0000 },
3226 { 0x05, 0x8b67 },
3227 { 0x06, 0x0000 },
3228 { 0x05, 0x8b70 },
3229 { 0x06, 0x0000 },
3230 { 0x1f, 0x0000 },
3231 { 0x1f, 0x0007 },
3232 { 0x1e, 0x0078 },
3233 { 0x17, 0x0000 },
3234 { 0x19, 0x00fb },
3235 { 0x1f, 0x0000 },
3236
3237 /* Modify green table for 10M */
3238 { 0x1f, 0x0005 },
3239 { 0x05, 0x8b79 },
3240 { 0x06, 0xaa00 },
3241 { 0x1f, 0x0000 },
3242
3243 /* Disable hiimpedance detection (RTCT) */
3244 { 0x1f, 0x0003 },
3245 { 0x01, 0x328a },
3246 { 0x1f, 0x0000 }
3247 };
3248
3249 rtl_apply_firmware(tp);
3250
3251 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3252
Hayes Wang5f886e02012-03-30 14:33:03 +08003253 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003254
3255 /* Improve 2-pair detection performance */
3256 rtl_writephy(tp, 0x1f, 0x0005);
3257 rtl_writephy(tp, 0x05, 0x8b85);
3258 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3259 rtl_writephy(tp, 0x1f, 0x0000);
3260}
3261
3262static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3263{
3264 rtl_apply_firmware(tp);
3265
Hayes Wang5f886e02012-03-30 14:33:03 +08003266 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003267}
3268
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003269static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3270{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003271 static const struct phy_reg phy_reg_init[] = {
3272 /* Channel estimation fine tune */
3273 { 0x1f, 0x0003 },
3274 { 0x09, 0xa20f },
3275 { 0x1f, 0x0000 },
3276
3277 /* Modify green table for giga & fnet */
3278 { 0x1f, 0x0005 },
3279 { 0x05, 0x8b55 },
3280 { 0x06, 0x0000 },
3281 { 0x05, 0x8b5e },
3282 { 0x06, 0x0000 },
3283 { 0x05, 0x8b67 },
3284 { 0x06, 0x0000 },
3285 { 0x05, 0x8b70 },
3286 { 0x06, 0x0000 },
3287 { 0x1f, 0x0000 },
3288 { 0x1f, 0x0007 },
3289 { 0x1e, 0x0078 },
3290 { 0x17, 0x0000 },
3291 { 0x19, 0x00aa },
3292 { 0x1f, 0x0000 },
3293
3294 /* Modify green table for 10M */
3295 { 0x1f, 0x0005 },
3296 { 0x05, 0x8b79 },
3297 { 0x06, 0xaa00 },
3298 { 0x1f, 0x0000 },
3299
3300 /* Disable hiimpedance detection (RTCT) */
3301 { 0x1f, 0x0003 },
3302 { 0x01, 0x328a },
3303 { 0x1f, 0x0000 }
3304 };
3305
3306
3307 rtl_apply_firmware(tp);
3308
3309 rtl8168f_hw_phy_config(tp);
3310
3311 /* Improve 2-pair detection performance */
3312 rtl_writephy(tp, 0x1f, 0x0005);
3313 rtl_writephy(tp, 0x05, 0x8b85);
3314 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3315 rtl_writephy(tp, 0x1f, 0x0000);
3316
3317 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3318
3319 /* Modify green table for giga */
3320 rtl_writephy(tp, 0x1f, 0x0005);
3321 rtl_writephy(tp, 0x05, 0x8b54);
3322 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3323 rtl_writephy(tp, 0x05, 0x8b5d);
3324 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3325 rtl_writephy(tp, 0x05, 0x8a7c);
3326 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3327 rtl_writephy(tp, 0x05, 0x8a7f);
3328 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3329 rtl_writephy(tp, 0x05, 0x8a82);
3330 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3331 rtl_writephy(tp, 0x05, 0x8a85);
3332 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3333 rtl_writephy(tp, 0x05, 0x8a88);
3334 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3335 rtl_writephy(tp, 0x1f, 0x0000);
3336
3337 /* uc same-seed solution */
3338 rtl_writephy(tp, 0x1f, 0x0005);
3339 rtl_writephy(tp, 0x05, 0x8b85);
3340 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3341 rtl_writephy(tp, 0x1f, 0x0000);
3342
3343 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003344 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003345 rtl_writephy(tp, 0x1f, 0x0005);
3346 rtl_writephy(tp, 0x05, 0x8b85);
3347 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3348 rtl_writephy(tp, 0x1f, 0x0004);
3349 rtl_writephy(tp, 0x1f, 0x0007);
3350 rtl_writephy(tp, 0x1e, 0x0020);
3351 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3352 rtl_writephy(tp, 0x1f, 0x0000);
3353 rtl_writephy(tp, 0x0d, 0x0007);
3354 rtl_writephy(tp, 0x0e, 0x003c);
3355 rtl_writephy(tp, 0x0d, 0x4007);
3356 rtl_writephy(tp, 0x0e, 0x0000);
3357 rtl_writephy(tp, 0x0d, 0x0000);
3358
3359 /* Green feature */
3360 rtl_writephy(tp, 0x1f, 0x0003);
3361 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3362 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3363 rtl_writephy(tp, 0x1f, 0x0000);
3364}
3365
Hayes Wangc5583862012-07-02 17:23:22 +08003366static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3367{
3368 static const u16 mac_ocp_patch[] = {
3369 0xe008, 0xe01b, 0xe01d, 0xe01f,
3370 0xe021, 0xe023, 0xe025, 0xe027,
3371 0x49d2, 0xf10d, 0x766c, 0x49e2,
3372 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3373
3374 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3375 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3376 0xbe00, 0xb416, 0x0076, 0xe86c,
3377 0xc602, 0xbe00, 0x0000, 0xc602,
3378
3379 0xbe00, 0x0000, 0xc602, 0xbe00,
3380 0x0000, 0xc602, 0xbe00, 0x0000,
3381 0xc602, 0xbe00, 0x0000, 0xc602,
3382 0xbe00, 0x0000, 0xc602, 0xbe00,
3383
3384 0x0000, 0x0000, 0x0000, 0x0000
3385 };
3386 u32 i;
3387
3388 /* Patch code for GPHY reset */
3389 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3390 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3391 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3392 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3393
3394 rtl_apply_firmware(tp);
3395
3396 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3397 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3398 else
3399 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3400
3401 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3402 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3403 else
3404 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3405
3406 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3407 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3408
3409 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3410 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3411
3412 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3413}
3414
françois romieu4da19632011-01-03 15:07:55 +00003415static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003416{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003417 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003418 { 0x1f, 0x0003 },
3419 { 0x08, 0x441d },
3420 { 0x01, 0x9100 },
3421 { 0x1f, 0x0000 }
3422 };
3423
françois romieu4da19632011-01-03 15:07:55 +00003424 rtl_writephy(tp, 0x1f, 0x0000);
3425 rtl_patchphy(tp, 0x11, 1 << 12);
3426 rtl_patchphy(tp, 0x19, 1 << 13);
3427 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003428
françois romieu4da19632011-01-03 15:07:55 +00003429 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003430}
3431
Hayes Wang5a5e4442011-02-22 17:26:21 +08003432static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3433{
3434 static const struct phy_reg phy_reg_init[] = {
3435 { 0x1f, 0x0005 },
3436 { 0x1a, 0x0000 },
3437 { 0x1f, 0x0000 },
3438
3439 { 0x1f, 0x0004 },
3440 { 0x1c, 0x0000 },
3441 { 0x1f, 0x0000 },
3442
3443 { 0x1f, 0x0001 },
3444 { 0x15, 0x7701 },
3445 { 0x1f, 0x0000 }
3446 };
3447
3448 /* Disable ALDPS before ram code */
3449 rtl_writephy(tp, 0x1f, 0x0000);
3450 rtl_writephy(tp, 0x18, 0x0310);
3451 msleep(100);
3452
François Romieu953a12c2011-04-24 17:38:48 +02003453 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003454
3455 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3456}
3457
Hayes Wang7e18dca2012-03-30 14:33:02 +08003458static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3459{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003460 /* Disable ALDPS before setting firmware */
3461 rtl_writephy(tp, 0x1f, 0x0000);
3462 rtl_writephy(tp, 0x18, 0x0310);
3463 msleep(20);
3464
3465 rtl_apply_firmware(tp);
3466
3467 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003468 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003469 rtl_writephy(tp, 0x1f, 0x0004);
3470 rtl_writephy(tp, 0x10, 0x401f);
3471 rtl_writephy(tp, 0x19, 0x7030);
3472 rtl_writephy(tp, 0x1f, 0x0000);
3473}
3474
Hayes Wang5598bfe2012-07-02 17:23:21 +08003475static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3476{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003477 static const struct phy_reg phy_reg_init[] = {
3478 { 0x1f, 0x0004 },
3479 { 0x10, 0xc07f },
3480 { 0x19, 0x7030 },
3481 { 0x1f, 0x0000 }
3482 };
3483
3484 /* Disable ALDPS before ram code */
3485 rtl_writephy(tp, 0x1f, 0x0000);
3486 rtl_writephy(tp, 0x18, 0x0310);
3487 msleep(100);
3488
3489 rtl_apply_firmware(tp);
3490
Francois Romieufdf6fc02012-07-06 22:40:38 +02003491 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003492 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3493
Francois Romieufdf6fc02012-07-06 22:40:38 +02003494 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003495}
3496
Francois Romieu5615d9f2007-08-17 17:50:46 +02003497static void rtl_hw_phy_config(struct net_device *dev)
3498{
3499 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003500
3501 rtl8169_print_mac_version(tp);
3502
3503 switch (tp->mac_version) {
3504 case RTL_GIGA_MAC_VER_01:
3505 break;
3506 case RTL_GIGA_MAC_VER_02:
3507 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003508 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003509 break;
3510 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003511 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003512 break;
françois romieu2e9558562009-08-10 19:44:19 +00003513 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003514 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003515 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003516 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003517 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003518 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003519 case RTL_GIGA_MAC_VER_07:
3520 case RTL_GIGA_MAC_VER_08:
3521 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003522 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003523 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003524 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003525 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003526 break;
3527 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003528 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003529 break;
3530 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003531 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003532 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003533 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003534 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003535 break;
3536 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003537 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003538 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003539 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003540 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003541 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003542 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003543 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003544 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003545 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003546 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003547 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003548 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003549 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003550 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003551 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003552 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003553 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003554 break;
3555 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003556 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003557 break;
3558 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003559 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003560 break;
françois romieue6de30d2011-01-03 15:08:37 +00003561 case RTL_GIGA_MAC_VER_28:
3562 rtl8168d_4_hw_phy_config(tp);
3563 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003564 case RTL_GIGA_MAC_VER_29:
3565 case RTL_GIGA_MAC_VER_30:
3566 rtl8105e_hw_phy_config(tp);
3567 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003568 case RTL_GIGA_MAC_VER_31:
3569 /* None. */
3570 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003571 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003572 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003573 rtl8168e_1_hw_phy_config(tp);
3574 break;
3575 case RTL_GIGA_MAC_VER_34:
3576 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003577 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003578 case RTL_GIGA_MAC_VER_35:
3579 rtl8168f_1_hw_phy_config(tp);
3580 break;
3581 case RTL_GIGA_MAC_VER_36:
3582 rtl8168f_2_hw_phy_config(tp);
3583 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003584
Hayes Wang7e18dca2012-03-30 14:33:02 +08003585 case RTL_GIGA_MAC_VER_37:
3586 rtl8402_hw_phy_config(tp);
3587 break;
3588
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003589 case RTL_GIGA_MAC_VER_38:
3590 rtl8411_hw_phy_config(tp);
3591 break;
3592
Hayes Wang5598bfe2012-07-02 17:23:21 +08003593 case RTL_GIGA_MAC_VER_39:
3594 rtl8106e_hw_phy_config(tp);
3595 break;
3596
Hayes Wangc5583862012-07-02 17:23:22 +08003597 case RTL_GIGA_MAC_VER_40:
3598 rtl8168g_1_hw_phy_config(tp);
3599 break;
3600
3601 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003602 default:
3603 break;
3604 }
3605}
3606
Francois Romieuda78dbf2012-01-26 14:18:23 +01003607static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 struct timer_list *timer = &tp->timer;
3610 void __iomem *ioaddr = tp->mmio_addr;
3611 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3612
Francois Romieubcf0bf92006-07-26 23:14:13 +02003613 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614
françois romieu4da19632011-01-03 15:07:55 +00003615 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003616 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 * A busy loop could burn quite a few cycles on nowadays CPU.
3618 * Let's delay the execution of the timer for a few ticks.
3619 */
3620 timeout = HZ/10;
3621 goto out_mod_timer;
3622 }
3623
3624 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003625 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626
Francois Romieuda78dbf2012-01-26 14:18:23 +01003627 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
françois romieu4da19632011-01-03 15:07:55 +00003629 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630
3631out_mod_timer:
3632 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003633}
3634
3635static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3636{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003637 if (!test_and_set_bit(flag, tp->wk.flags))
3638 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003639}
3640
3641static void rtl8169_phy_timer(unsigned long __opaque)
3642{
3643 struct net_device *dev = (struct net_device *)__opaque;
3644 struct rtl8169_private *tp = netdev_priv(dev);
3645
Francois Romieu98ddf982012-01-31 10:47:34 +01003646 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647}
3648
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3650 void __iomem *ioaddr)
3651{
3652 iounmap(ioaddr);
3653 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003654 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 pci_disable_device(pdev);
3656 free_netdev(dev);
3657}
3658
Francois Romieuffc46952012-07-06 14:19:23 +02003659DECLARE_RTL_COND(rtl_phy_reset_cond)
3660{
3661 return tp->phy_reset_pending(tp);
3662}
3663
Francois Romieubf793292006-11-01 00:53:05 +01003664static void rtl8169_phy_reset(struct net_device *dev,
3665 struct rtl8169_private *tp)
3666{
françois romieu4da19632011-01-03 15:07:55 +00003667 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003668 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003669}
3670
David S. Miller8decf862011-09-22 03:23:13 -04003671static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3672{
3673 void __iomem *ioaddr = tp->mmio_addr;
3674
3675 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3676 (RTL_R8(PHYstatus) & TBI_Enable);
3677}
3678
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003679static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003681 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003682
Francois Romieu5615d9f2007-08-17 17:50:46 +02003683 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003684
Marcus Sundberg773328942008-07-10 21:28:08 +02003685 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3686 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3687 RTL_W8(0x82, 0x01);
3688 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003689
Francois Romieu6dccd162007-02-13 23:38:05 +01003690 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3691
3692 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3693 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003694
Francois Romieubcf0bf92006-07-26 23:14:13 +02003695 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003696 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3697 RTL_W8(0x82, 0x01);
3698 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003699 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003700 }
3701
Francois Romieubf793292006-11-01 00:53:05 +01003702 rtl8169_phy_reset(dev, tp);
3703
Oliver Neukum54405cd2011-01-06 21:55:13 +01003704 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003705 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3706 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3707 (tp->mii.supports_gmii ?
3708 ADVERTISED_1000baseT_Half |
3709 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003710
David S. Miller8decf862011-09-22 03:23:13 -04003711 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003712 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003713}
3714
Francois Romieu773d2022007-01-31 23:47:43 +01003715static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3716{
3717 void __iomem *ioaddr = tp->mmio_addr;
3718 u32 high;
3719 u32 low;
3720
3721 low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
3722 high = addr[4] | (addr[5] << 8);
3723
Francois Romieuda78dbf2012-01-26 14:18:23 +01003724 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003725
3726 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2bf2010-04-26 11:42:58 +00003727
Francois Romieu773d2022007-01-31 23:47:43 +01003728 RTL_W32(MAC4, high);
françois romieu908ba2bf2010-04-26 11:42:58 +00003729 RTL_R32(MAC4);
3730
Francois Romieu78f1cd02010-03-27 19:35:46 -07003731 RTL_W32(MAC0, low);
françois romieu908ba2bf2010-04-26 11:42:58 +00003732 RTL_R32(MAC0);
3733
françois romieuc28aa382011-08-02 03:53:43 +00003734 if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
3735 const struct exgmac_reg e[] = {
3736 { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
3737 { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
3738 { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
3739 { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
3740 low >> 16 },
3741 };
3742
Francois Romieufdf6fc02012-07-06 22:40:38 +02003743 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
françois romieuc28aa382011-08-02 03:53:43 +00003744 }
3745
Francois Romieu773d2022007-01-31 23:47:43 +01003746 RTL_W8(Cfg9346, Cfg9346_Lock);
3747
Francois Romieuda78dbf2012-01-26 14:18:23 +01003748 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003749}
3750
3751static int rtl_set_mac_address(struct net_device *dev, void *p)
3752{
3753 struct rtl8169_private *tp = netdev_priv(dev);
3754 struct sockaddr *addr = p;
3755
3756 if (!is_valid_ether_addr(addr->sa_data))
3757 return -EADDRNOTAVAIL;
3758
3759 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3760
3761 rtl_rar_set(tp, dev->dev_addr);
3762
3763 return 0;
3764}
3765
Francois Romieu5f787a12006-08-17 13:02:36 +02003766static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3767{
3768 struct rtl8169_private *tp = netdev_priv(dev);
3769 struct mii_ioctl_data *data = if_mii(ifr);
3770
Francois Romieu8b4ab282008-11-19 22:05:25 -08003771 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3772}
Francois Romieu5f787a12006-08-17 13:02:36 +02003773
Francois Romieucecb5fd2011-04-01 10:21:07 +02003774static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3775 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003776{
Francois Romieu5f787a12006-08-17 13:02:36 +02003777 switch (cmd) {
3778 case SIOCGMIIPHY:
3779 data->phy_id = 32; /* Internal PHY */
3780 return 0;
3781
3782 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003783 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003784 return 0;
3785
3786 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003787 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003788 return 0;
3789 }
3790 return -EOPNOTSUPP;
3791}
3792
Francois Romieu8b4ab282008-11-19 22:05:25 -08003793static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3794{
3795 return -EOPNOTSUPP;
3796}
3797
Francois Romieufbac58f2007-10-04 22:51:38 +02003798static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3799{
3800 if (tp->features & RTL_FEATURE_MSI) {
3801 pci_disable_msi(pdev);
3802 tp->features &= ~RTL_FEATURE_MSI;
3803 }
3804}
3805
françois romieuc0e45c12011-01-03 15:08:04 +00003806static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
3807{
3808 struct mdio_ops *ops = &tp->mdio_ops;
3809
3810 switch (tp->mac_version) {
3811 case RTL_GIGA_MAC_VER_27:
3812 ops->write = r8168dp_1_mdio_write;
3813 ops->read = r8168dp_1_mdio_read;
3814 break;
françois romieue6de30d2011-01-03 15:08:37 +00003815 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003816 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003817 ops->write = r8168dp_2_mdio_write;
3818 ops->read = r8168dp_2_mdio_read;
3819 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003820 case RTL_GIGA_MAC_VER_40:
3821 case RTL_GIGA_MAC_VER_41:
3822 ops->write = r8168g_mdio_write;
3823 ops->read = r8168g_mdio_read;
3824 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003825 default:
3826 ops->write = r8169_mdio_write;
3827 ops->read = r8169_mdio_read;
3828 break;
3829 }
3830}
3831
David S. Miller1805b2f2011-10-24 18:18:09 -04003832static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3833{
3834 void __iomem *ioaddr = tp->mmio_addr;
3835
3836 switch (tp->mac_version) {
3837 case RTL_GIGA_MAC_VER_29:
3838 case RTL_GIGA_MAC_VER_30:
3839 case RTL_GIGA_MAC_VER_32:
3840 case RTL_GIGA_MAC_VER_33:
3841 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003842 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003843 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003844 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003845 case RTL_GIGA_MAC_VER_40:
3846 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003847 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3848 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3849 break;
3850 default:
3851 break;
3852 }
3853}
3854
3855static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3856{
3857 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3858 return false;
3859
3860 rtl_writephy(tp, 0x1f, 0x0000);
3861 rtl_writephy(tp, MII_BMCR, 0x0000);
3862
3863 rtl_wol_suspend_quirk(tp);
3864
3865 return true;
3866}
3867
françois romieu065c27c2011-01-03 15:08:12 +00003868static void r810x_phy_power_down(struct rtl8169_private *tp)
3869{
3870 rtl_writephy(tp, 0x1f, 0x0000);
3871 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3872}
3873
3874static void r810x_phy_power_up(struct rtl8169_private *tp)
3875{
3876 rtl_writephy(tp, 0x1f, 0x0000);
3877 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3878}
3879
3880static void r810x_pll_power_down(struct rtl8169_private *tp)
3881{
Hayes Wang00042992012-03-30 14:33:00 +08003882 void __iomem *ioaddr = tp->mmio_addr;
3883
David S. Miller1805b2f2011-10-24 18:18:09 -04003884 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003885 return;
françois romieu065c27c2011-01-03 15:08:12 +00003886
3887 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003888
3889 switch (tp->mac_version) {
3890 case RTL_GIGA_MAC_VER_07:
3891 case RTL_GIGA_MAC_VER_08:
3892 case RTL_GIGA_MAC_VER_09:
3893 case RTL_GIGA_MAC_VER_10:
3894 case RTL_GIGA_MAC_VER_13:
3895 case RTL_GIGA_MAC_VER_16:
3896 break;
3897 default:
3898 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3899 break;
3900 }
françois romieu065c27c2011-01-03 15:08:12 +00003901}
3902
3903static void r810x_pll_power_up(struct rtl8169_private *tp)
3904{
Hayes Wang00042992012-03-30 14:33:00 +08003905 void __iomem *ioaddr = tp->mmio_addr;
3906
françois romieu065c27c2011-01-03 15:08:12 +00003907 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003908
3909 switch (tp->mac_version) {
3910 case RTL_GIGA_MAC_VER_07:
3911 case RTL_GIGA_MAC_VER_08:
3912 case RTL_GIGA_MAC_VER_09:
3913 case RTL_GIGA_MAC_VER_10:
3914 case RTL_GIGA_MAC_VER_13:
3915 case RTL_GIGA_MAC_VER_16:
3916 break;
3917 default:
3918 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3919 break;
3920 }
françois romieu065c27c2011-01-03 15:08:12 +00003921}
3922
3923static void r8168_phy_power_up(struct rtl8169_private *tp)
3924{
3925 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003926 switch (tp->mac_version) {
3927 case RTL_GIGA_MAC_VER_11:
3928 case RTL_GIGA_MAC_VER_12:
3929 case RTL_GIGA_MAC_VER_17:
3930 case RTL_GIGA_MAC_VER_18:
3931 case RTL_GIGA_MAC_VER_19:
3932 case RTL_GIGA_MAC_VER_20:
3933 case RTL_GIGA_MAC_VER_21:
3934 case RTL_GIGA_MAC_VER_22:
3935 case RTL_GIGA_MAC_VER_23:
3936 case RTL_GIGA_MAC_VER_24:
3937 case RTL_GIGA_MAC_VER_25:
3938 case RTL_GIGA_MAC_VER_26:
3939 case RTL_GIGA_MAC_VER_27:
3940 case RTL_GIGA_MAC_VER_28:
3941 case RTL_GIGA_MAC_VER_31:
3942 rtl_writephy(tp, 0x0e, 0x0000);
3943 break;
3944 default:
3945 break;
3946 }
françois romieu065c27c2011-01-03 15:08:12 +00003947 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3948}
3949
3950static void r8168_phy_power_down(struct rtl8169_private *tp)
3951{
3952 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003953 switch (tp->mac_version) {
3954 case RTL_GIGA_MAC_VER_32:
3955 case RTL_GIGA_MAC_VER_33:
3956 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3957 break;
3958
3959 case RTL_GIGA_MAC_VER_11:
3960 case RTL_GIGA_MAC_VER_12:
3961 case RTL_GIGA_MAC_VER_17:
3962 case RTL_GIGA_MAC_VER_18:
3963 case RTL_GIGA_MAC_VER_19:
3964 case RTL_GIGA_MAC_VER_20:
3965 case RTL_GIGA_MAC_VER_21:
3966 case RTL_GIGA_MAC_VER_22:
3967 case RTL_GIGA_MAC_VER_23:
3968 case RTL_GIGA_MAC_VER_24:
3969 case RTL_GIGA_MAC_VER_25:
3970 case RTL_GIGA_MAC_VER_26:
3971 case RTL_GIGA_MAC_VER_27:
3972 case RTL_GIGA_MAC_VER_28:
3973 case RTL_GIGA_MAC_VER_31:
3974 rtl_writephy(tp, 0x0e, 0x0200);
3975 default:
3976 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3977 break;
3978 }
françois romieu065c27c2011-01-03 15:08:12 +00003979}
3980
3981static void r8168_pll_power_down(struct rtl8169_private *tp)
3982{
3983 void __iomem *ioaddr = tp->mmio_addr;
3984
Francois Romieucecb5fd2011-04-01 10:21:07 +02003985 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
3986 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
3987 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00003988 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00003989 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08003990 }
françois romieu065c27c2011-01-03 15:08:12 +00003991
Francois Romieucecb5fd2011-04-01 10:21:07 +02003992 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
3993 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00003994 (RTL_R16(CPlusCmd) & ASF)) {
3995 return;
3996 }
3997
hayeswang01dc7fe2011-03-21 01:50:28 +00003998 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
3999 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02004000 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00004001
David S. Miller1805b2f2011-10-24 18:18:09 -04004002 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00004003 return;
françois romieu065c27c2011-01-03 15:08:12 +00004004
4005 r8168_phy_power_down(tp);
4006
4007 switch (tp->mac_version) {
4008 case RTL_GIGA_MAC_VER_25:
4009 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004010 case RTL_GIGA_MAC_VER_27:
4011 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004012 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004013 case RTL_GIGA_MAC_VER_32:
4014 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004015 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4016 break;
4017 }
4018}
4019
4020static void r8168_pll_power_up(struct rtl8169_private *tp)
4021{
4022 void __iomem *ioaddr = tp->mmio_addr;
4023
françois romieu065c27c2011-01-03 15:08:12 +00004024 switch (tp->mac_version) {
4025 case RTL_GIGA_MAC_VER_25:
4026 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004027 case RTL_GIGA_MAC_VER_27:
4028 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004029 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004030 case RTL_GIGA_MAC_VER_32:
4031 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004032 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4033 break;
4034 }
4035
4036 r8168_phy_power_up(tp);
4037}
4038
Francois Romieud58d46b2011-05-03 16:38:29 +02004039static void rtl_generic_op(struct rtl8169_private *tp,
4040 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004041{
4042 if (op)
4043 op(tp);
4044}
4045
4046static void rtl_pll_power_down(struct rtl8169_private *tp)
4047{
Francois Romieud58d46b2011-05-03 16:38:29 +02004048 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004049}
4050
4051static void rtl_pll_power_up(struct rtl8169_private *tp)
4052{
Francois Romieud58d46b2011-05-03 16:38:29 +02004053 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004054}
4055
4056static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
4057{
4058 struct pll_power_ops *ops = &tp->pll_power_ops;
4059
4060 switch (tp->mac_version) {
4061 case RTL_GIGA_MAC_VER_07:
4062 case RTL_GIGA_MAC_VER_08:
4063 case RTL_GIGA_MAC_VER_09:
4064 case RTL_GIGA_MAC_VER_10:
4065 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004066 case RTL_GIGA_MAC_VER_29:
4067 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004068 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004069 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004070 ops->down = r810x_pll_power_down;
4071 ops->up = r810x_pll_power_up;
4072 break;
4073
4074 case RTL_GIGA_MAC_VER_11:
4075 case RTL_GIGA_MAC_VER_12:
4076 case RTL_GIGA_MAC_VER_17:
4077 case RTL_GIGA_MAC_VER_18:
4078 case RTL_GIGA_MAC_VER_19:
4079 case RTL_GIGA_MAC_VER_20:
4080 case RTL_GIGA_MAC_VER_21:
4081 case RTL_GIGA_MAC_VER_22:
4082 case RTL_GIGA_MAC_VER_23:
4083 case RTL_GIGA_MAC_VER_24:
4084 case RTL_GIGA_MAC_VER_25:
4085 case RTL_GIGA_MAC_VER_26:
4086 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004087 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004088 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004089 case RTL_GIGA_MAC_VER_32:
4090 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004091 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004092 case RTL_GIGA_MAC_VER_35:
4093 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004094 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004095 case RTL_GIGA_MAC_VER_40:
4096 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004097 ops->down = r8168_pll_power_down;
4098 ops->up = r8168_pll_power_up;
4099 break;
4100
4101 default:
4102 ops->down = NULL;
4103 ops->up = NULL;
4104 break;
4105 }
4106}
4107
Hayes Wange542a222011-07-06 15:58:04 +08004108static void rtl_init_rxcfg(struct rtl8169_private *tp)
4109{
4110 void __iomem *ioaddr = tp->mmio_addr;
4111
4112 switch (tp->mac_version) {
4113 case RTL_GIGA_MAC_VER_01:
4114 case RTL_GIGA_MAC_VER_02:
4115 case RTL_GIGA_MAC_VER_03:
4116 case RTL_GIGA_MAC_VER_04:
4117 case RTL_GIGA_MAC_VER_05:
4118 case RTL_GIGA_MAC_VER_06:
4119 case RTL_GIGA_MAC_VER_10:
4120 case RTL_GIGA_MAC_VER_11:
4121 case RTL_GIGA_MAC_VER_12:
4122 case RTL_GIGA_MAC_VER_13:
4123 case RTL_GIGA_MAC_VER_14:
4124 case RTL_GIGA_MAC_VER_15:
4125 case RTL_GIGA_MAC_VER_16:
4126 case RTL_GIGA_MAC_VER_17:
4127 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4128 break;
4129 case RTL_GIGA_MAC_VER_18:
4130 case RTL_GIGA_MAC_VER_19:
4131 case RTL_GIGA_MAC_VER_20:
4132 case RTL_GIGA_MAC_VER_21:
4133 case RTL_GIGA_MAC_VER_22:
4134 case RTL_GIGA_MAC_VER_23:
4135 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004136 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004137 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4138 break;
4139 default:
4140 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4141 break;
4142 }
4143}
4144
Hayes Wang92fc43b2011-07-06 15:58:03 +08004145static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4146{
4147 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4148}
4149
Francois Romieud58d46b2011-05-03 16:38:29 +02004150static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4151{
françois romieu9c5028e2012-03-02 04:43:14 +00004152 void __iomem *ioaddr = tp->mmio_addr;
4153
4154 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004155 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004156 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004157}
4158
4159static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
4160{
françois romieu9c5028e2012-03-02 04:43:14 +00004161 void __iomem *ioaddr = tp->mmio_addr;
4162
4163 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004164 rtl_generic_op(tp, tp->jumbo_ops.disable);
françois romieu9c5028e2012-03-02 04:43:14 +00004165 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004166}
4167
4168static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4169{
4170 void __iomem *ioaddr = tp->mmio_addr;
4171
4172 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4173 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4174 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4175}
4176
4177static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
4178{
4179 void __iomem *ioaddr = tp->mmio_addr;
4180
4181 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4182 RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
4183 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
4184}
4185
4186static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
4187{
4188 void __iomem *ioaddr = tp->mmio_addr;
4189
4190 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4191}
4192
4193static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4194{
4195 void __iomem *ioaddr = tp->mmio_addr;
4196
4197 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4198}
4199
4200static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4201{
4202 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004203
4204 RTL_W8(MaxTxPacketSize, 0x3f);
4205 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4206 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004207 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004208}
4209
4210static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4211{
4212 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004213
4214 RTL_W8(MaxTxPacketSize, 0x0c);
4215 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4216 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004217 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004218}
4219
4220static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4221{
4222 rtl_tx_performance_tweak(tp->pci_dev,
4223 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4224}
4225
4226static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4227{
4228 rtl_tx_performance_tweak(tp->pci_dev,
4229 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4230}
4231
4232static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4233{
4234 void __iomem *ioaddr = tp->mmio_addr;
4235
4236 r8168b_0_hw_jumbo_enable(tp);
4237
4238 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4239}
4240
4241static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4242{
4243 void __iomem *ioaddr = tp->mmio_addr;
4244
4245 r8168b_0_hw_jumbo_disable(tp);
4246
4247 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4248}
4249
4250static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
4251{
4252 struct jumbo_ops *ops = &tp->jumbo_ops;
4253
4254 switch (tp->mac_version) {
4255 case RTL_GIGA_MAC_VER_11:
4256 ops->disable = r8168b_0_hw_jumbo_disable;
4257 ops->enable = r8168b_0_hw_jumbo_enable;
4258 break;
4259 case RTL_GIGA_MAC_VER_12:
4260 case RTL_GIGA_MAC_VER_17:
4261 ops->disable = r8168b_1_hw_jumbo_disable;
4262 ops->enable = r8168b_1_hw_jumbo_enable;
4263 break;
4264 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4265 case RTL_GIGA_MAC_VER_19:
4266 case RTL_GIGA_MAC_VER_20:
4267 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4268 case RTL_GIGA_MAC_VER_22:
4269 case RTL_GIGA_MAC_VER_23:
4270 case RTL_GIGA_MAC_VER_24:
4271 case RTL_GIGA_MAC_VER_25:
4272 case RTL_GIGA_MAC_VER_26:
4273 ops->disable = r8168c_hw_jumbo_disable;
4274 ops->enable = r8168c_hw_jumbo_enable;
4275 break;
4276 case RTL_GIGA_MAC_VER_27:
4277 case RTL_GIGA_MAC_VER_28:
4278 ops->disable = r8168dp_hw_jumbo_disable;
4279 ops->enable = r8168dp_hw_jumbo_enable;
4280 break;
4281 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4282 case RTL_GIGA_MAC_VER_32:
4283 case RTL_GIGA_MAC_VER_33:
4284 case RTL_GIGA_MAC_VER_34:
4285 ops->disable = r8168e_hw_jumbo_disable;
4286 ops->enable = r8168e_hw_jumbo_enable;
4287 break;
4288
4289 /*
4290 * No action needed for jumbo frames with 8169.
4291 * No jumbo for 810x at all.
4292 */
Hayes Wangc5583862012-07-02 17:23:22 +08004293 case RTL_GIGA_MAC_VER_40:
4294 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004295 default:
4296 ops->disable = NULL;
4297 ops->enable = NULL;
4298 break;
4299 }
4300}
4301
Francois Romieuffc46952012-07-06 14:19:23 +02004302DECLARE_RTL_COND(rtl_chipcmd_cond)
4303{
4304 void __iomem *ioaddr = tp->mmio_addr;
4305
4306 return RTL_R8(ChipCmd) & CmdReset;
4307}
4308
Francois Romieu6f43adc2011-04-29 15:05:51 +02004309static void rtl_hw_reset(struct rtl8169_private *tp)
4310{
4311 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004312
Francois Romieu6f43adc2011-04-29 15:05:51 +02004313 RTL_W8(ChipCmd, CmdReset);
4314
Francois Romieuffc46952012-07-06 14:19:23 +02004315 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004316}
4317
Francois Romieub6ffd972011-06-17 17:00:05 +02004318static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4319{
4320 struct rtl_fw *rtl_fw;
4321 const char *name;
4322 int rc = -ENOMEM;
4323
4324 name = rtl_lookup_firmware_name(tp);
4325 if (!name)
4326 goto out_no_firmware;
4327
4328 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4329 if (!rtl_fw)
4330 goto err_warn;
4331
4332 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4333 if (rc < 0)
4334 goto err_free;
4335
Francois Romieufd112f22011-06-18 00:10:29 +02004336 rc = rtl_check_firmware(tp, rtl_fw);
4337 if (rc < 0)
4338 goto err_release_firmware;
4339
Francois Romieub6ffd972011-06-17 17:00:05 +02004340 tp->rtl_fw = rtl_fw;
4341out:
4342 return;
4343
Francois Romieufd112f22011-06-18 00:10:29 +02004344err_release_firmware:
4345 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004346err_free:
4347 kfree(rtl_fw);
4348err_warn:
4349 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4350 name, rc);
4351out_no_firmware:
4352 tp->rtl_fw = NULL;
4353 goto out;
4354}
4355
François Romieu953a12c2011-04-24 17:38:48 +02004356static void rtl_request_firmware(struct rtl8169_private *tp)
4357{
Francois Romieub6ffd972011-06-17 17:00:05 +02004358 if (IS_ERR(tp->rtl_fw))
4359 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004360}
4361
Hayes Wang92fc43b2011-07-06 15:58:03 +08004362static void rtl_rx_close(struct rtl8169_private *tp)
4363{
4364 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004365
Francois Romieu1687b562011-07-19 17:21:29 +02004366 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004367}
4368
Francois Romieuffc46952012-07-06 14:19:23 +02004369DECLARE_RTL_COND(rtl_npq_cond)
4370{
4371 void __iomem *ioaddr = tp->mmio_addr;
4372
4373 return RTL_R8(TxPoll) & NPQ;
4374}
4375
4376DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4377{
4378 void __iomem *ioaddr = tp->mmio_addr;
4379
4380 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4381}
4382
françois romieue6de30d2011-01-03 15:08:37 +00004383static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384{
françois romieue6de30d2011-01-03 15:08:37 +00004385 void __iomem *ioaddr = tp->mmio_addr;
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004388 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389
Hayes Wang92fc43b2011-07-06 15:58:03 +08004390 rtl_rx_close(tp);
4391
Hayes Wang5d2e1952011-02-22 17:26:22 +08004392 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004393 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4394 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004395 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004396 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4397 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004398 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004399 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004400 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4401 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004402 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004403 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004404 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004405 } else {
4406 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4407 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004408 }
4409
Hayes Wang92fc43b2011-07-06 15:58:03 +08004410 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411}
4412
Francois Romieu7f796d832007-06-11 23:04:41 +02004413static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004414{
4415 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004416
4417 /* Set DMA burst size and Interframe Gap Time */
4418 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4419 (InterFrameGap << TxInterFrameGapShift));
4420}
4421
Francois Romieu07ce4062007-02-23 23:36:39 +01004422static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423{
4424 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
Francois Romieu07ce4062007-02-23 23:36:39 +01004426 tp->hw_start(dev);
4427
Francois Romieuda78dbf2012-01-26 14:18:23 +01004428 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004429}
4430
Francois Romieu7f796d832007-06-11 23:04:41 +02004431static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4432 void __iomem *ioaddr)
4433{
4434 /*
4435 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4436 * register to be written before TxDescAddrLow to work.
4437 * Switching from MMIO to I/O access fixes the issue as well.
4438 */
4439 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004440 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004441 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004442 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004443}
4444
4445static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4446{
4447 u16 cmd;
4448
4449 cmd = RTL_R16(CPlusCmd);
4450 RTL_W16(CPlusCmd, cmd);
4451 return cmd;
4452}
4453
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004454static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004455{
4456 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e872009-10-26 10:52:37 +00004457 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004458}
4459
Francois Romieu6dccd162007-02-13 23:38:05 +01004460static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4461{
Francois Romieu37441002011-06-17 22:58:54 +02004462 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004463 u32 mac_version;
4464 u32 clk;
4465 u32 val;
4466 } cfg2_info [] = {
4467 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4468 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4469 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4470 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004471 };
4472 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004473 unsigned int i;
4474 u32 clk;
4475
4476 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004477 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004478 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4479 RTL_W32(0x7c, p->val);
4480 break;
4481 }
4482 }
4483}
4484
Francois Romieue6b763e2012-03-08 09:35:39 +01004485static void rtl_set_rx_mode(struct net_device *dev)
4486{
4487 struct rtl8169_private *tp = netdev_priv(dev);
4488 void __iomem *ioaddr = tp->mmio_addr;
4489 u32 mc_filter[2]; /* Multicast hash filter */
4490 int rx_mode;
4491 u32 tmp = 0;
4492
4493 if (dev->flags & IFF_PROMISC) {
4494 /* Unconditionally log net taps. */
4495 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4496 rx_mode =
4497 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4498 AcceptAllPhys;
4499 mc_filter[1] = mc_filter[0] = 0xffffffff;
4500 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4501 (dev->flags & IFF_ALLMULTI)) {
4502 /* Too many to filter perfectly -- accept all multicasts. */
4503 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4504 mc_filter[1] = mc_filter[0] = 0xffffffff;
4505 } else {
4506 struct netdev_hw_addr *ha;
4507
4508 rx_mode = AcceptBroadcast | AcceptMyPhys;
4509 mc_filter[1] = mc_filter[0] = 0;
4510 netdev_for_each_mc_addr(ha, dev) {
4511 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4512 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4513 rx_mode |= AcceptMulticast;
4514 }
4515 }
4516
4517 if (dev->features & NETIF_F_RXALL)
4518 rx_mode |= (AcceptErr | AcceptRunt);
4519
4520 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4521
4522 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4523 u32 data = mc_filter[0];
4524
4525 mc_filter[0] = swab32(mc_filter[1]);
4526 mc_filter[1] = swab32(data);
4527 }
4528
4529 RTL_W32(MAR0 + 4, mc_filter[1]);
4530 RTL_W32(MAR0 + 0, mc_filter[0]);
4531
4532 RTL_W32(RxConfig, tmp);
4533}
4534
Francois Romieu07ce4062007-02-23 23:36:39 +01004535static void rtl_hw_start_8169(struct net_device *dev)
4536{
4537 struct rtl8169_private *tp = netdev_priv(dev);
4538 void __iomem *ioaddr = tp->mmio_addr;
4539 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004540
Francois Romieu9cb427b2006-11-02 00:10:16 +01004541 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4542 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4543 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4544 }
4545
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004547 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4548 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4549 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4550 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004551 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4552
Hayes Wange542a222011-07-06 15:58:04 +08004553 rtl_init_rxcfg(tp);
4554
françois romieuf0298f82011-01-03 15:07:42 +00004555 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004557 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
Francois Romieucecb5fd2011-04-01 10:21:07 +02004559 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4560 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4561 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4562 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004563 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Francois Romieu7f796d832007-06-11 23:04:41 +02004565 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004566
Francois Romieucecb5fd2011-04-01 10:21:07 +02004567 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4568 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004569 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004571 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
4573
Francois Romieubcf0bf92006-07-26 23:14:13 +02004574 RTL_W16(CPlusCmd, tp->cp_cmd);
4575
Francois Romieu6dccd162007-02-13 23:38:05 +01004576 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4577
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 /*
4579 * Undocumented corner. Supposedly:
4580 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4581 */
4582 RTL_W16(IntrMitigate, 0x0000);
4583
Francois Romieu7f796d832007-06-11 23:04:41 +02004584 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004585
Francois Romieucecb5fd2011-04-01 10:21:07 +02004586 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4587 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4588 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4589 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004590 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4591 rtl_set_rx_tx_config_registers(tp);
4592 }
4593
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004595
4596 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4597 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
4599 RTL_W32(RxMissed, 0);
4600
Francois Romieu07ce4062007-02-23 23:36:39 +01004601 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602
4603 /* no early-rx interrupts */
4604 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004605}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004607static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4608{
4609 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004610 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004611}
4612
4613static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4614{
Francois Romieu52989f02012-07-06 13:37:00 +02004615 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004616}
4617
4618static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004619{
4620 u32 csi;
4621
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004622 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4623 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004624}
4625
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004626static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004627{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004628 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004629}
4630
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004631static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004632{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004633 rtl_csi_access_enable(tp, 0x27000000);
4634}
4635
Francois Romieuffc46952012-07-06 14:19:23 +02004636DECLARE_RTL_COND(rtl_csiar_cond)
4637{
4638 void __iomem *ioaddr = tp->mmio_addr;
4639
4640 return RTL_R32(CSIAR) & CSIAR_FLAG;
4641}
4642
Francois Romieu52989f02012-07-06 13:37:00 +02004643static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004644{
Francois Romieu52989f02012-07-06 13:37:00 +02004645 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004646
4647 RTL_W32(CSIDR, value);
4648 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4649 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4650
Francois Romieuffc46952012-07-06 14:19:23 +02004651 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004652}
4653
Francois Romieu52989f02012-07-06 13:37:00 +02004654static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004655{
Francois Romieu52989f02012-07-06 13:37:00 +02004656 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004657
4658 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4659 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4660
Francois Romieuffc46952012-07-06 14:19:23 +02004661 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4662 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004663}
4664
Francois Romieu52989f02012-07-06 13:37:00 +02004665static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004666{
Francois Romieu52989f02012-07-06 13:37:00 +02004667 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004668
4669 RTL_W32(CSIDR, value);
4670 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4671 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4672 CSIAR_FUNC_NIC);
4673
Francois Romieuffc46952012-07-06 14:19:23 +02004674 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004675}
4676
Francois Romieu52989f02012-07-06 13:37:00 +02004677static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004678{
Francois Romieu52989f02012-07-06 13:37:00 +02004679 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004680
4681 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4682 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4683
Francois Romieuffc46952012-07-06 14:19:23 +02004684 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4685 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004686}
4687
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004688static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
4689{
4690 struct csi_ops *ops = &tp->csi_ops;
4691
4692 switch (tp->mac_version) {
4693 case RTL_GIGA_MAC_VER_01:
4694 case RTL_GIGA_MAC_VER_02:
4695 case RTL_GIGA_MAC_VER_03:
4696 case RTL_GIGA_MAC_VER_04:
4697 case RTL_GIGA_MAC_VER_05:
4698 case RTL_GIGA_MAC_VER_06:
4699 case RTL_GIGA_MAC_VER_10:
4700 case RTL_GIGA_MAC_VER_11:
4701 case RTL_GIGA_MAC_VER_12:
4702 case RTL_GIGA_MAC_VER_13:
4703 case RTL_GIGA_MAC_VER_14:
4704 case RTL_GIGA_MAC_VER_15:
4705 case RTL_GIGA_MAC_VER_16:
4706 case RTL_GIGA_MAC_VER_17:
4707 ops->write = NULL;
4708 ops->read = NULL;
4709 break;
4710
Hayes Wang7e18dca2012-03-30 14:33:02 +08004711 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004712 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004713 ops->write = r8402_csi_write;
4714 ops->read = r8402_csi_read;
4715 break;
4716
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004717 default:
4718 ops->write = r8169_csi_write;
4719 ops->read = r8169_csi_read;
4720 break;
4721 }
Francois Romieudacf8152008-08-02 20:44:13 +02004722}
4723
4724struct ephy_info {
4725 unsigned int offset;
4726 u16 mask;
4727 u16 bits;
4728};
4729
Francois Romieufdf6fc02012-07-06 22:40:38 +02004730static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4731 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004732{
4733 u16 w;
4734
4735 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004736 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4737 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004738 e++;
4739 }
4740}
4741
Francois Romieub726e492008-06-28 12:22:59 +02004742static void rtl_disable_clock_request(struct pci_dev *pdev)
4743{
Jon Masone44daad2011-06-27 07:46:31 +00004744 int cap = pci_pcie_cap(pdev);
Francois Romieub726e492008-06-28 12:22:59 +02004745
4746 if (cap) {
4747 u16 ctl;
4748
4749 pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
4750 ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
4751 pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
4752 }
4753}
4754
françois romieue6de30d2011-01-03 15:08:37 +00004755static void rtl_enable_clock_request(struct pci_dev *pdev)
4756{
Jon Masone44daad2011-06-27 07:46:31 +00004757 int cap = pci_pcie_cap(pdev);
françois romieue6de30d2011-01-03 15:08:37 +00004758
4759 if (cap) {
4760 u16 ctl;
4761
4762 pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
4763 ctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
4764 pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
4765 }
4766}
4767
Francois Romieub726e492008-06-28 12:22:59 +02004768#define R8168_CPCMD_QUIRK_MASK (\
4769 EnableBist | \
4770 Mac_dbgo_oe | \
4771 Force_half_dup | \
4772 Force_rxflow_en | \
4773 Force_txflow_en | \
4774 Cxpl_dbg_sel | \
4775 ASF | \
4776 PktCntrDisable | \
4777 Mac_dbgo_sel)
4778
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004779static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004780{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004781 void __iomem *ioaddr = tp->mmio_addr;
4782 struct pci_dev *pdev = tp->pci_dev;
4783
Francois Romieub726e492008-06-28 12:22:59 +02004784 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4785
4786 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4787
Francois Romieu2e68ae42008-06-28 12:00:55 +02004788 rtl_tx_performance_tweak(pdev,
4789 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004790}
4791
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004792static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004793{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004794 void __iomem *ioaddr = tp->mmio_addr;
4795
4796 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004797
françois romieuf0298f82011-01-03 15:07:42 +00004798 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004799
4800 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004801}
4802
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004803static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004804{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004805 void __iomem *ioaddr = tp->mmio_addr;
4806 struct pci_dev *pdev = tp->pci_dev;
4807
Francois Romieub726e492008-06-28 12:22:59 +02004808 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4809
4810 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4811
Francois Romieu219a1e92008-06-28 11:58:39 +02004812 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004813
4814 rtl_disable_clock_request(pdev);
4815
4816 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004817}
4818
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004819static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004820{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004821 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004822 { 0x01, 0, 0x0001 },
4823 { 0x02, 0x0800, 0x1000 },
4824 { 0x03, 0, 0x0042 },
4825 { 0x06, 0x0080, 0x0000 },
4826 { 0x07, 0, 0x2000 }
4827 };
4828
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004829 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004830
Francois Romieufdf6fc02012-07-06 22:40:38 +02004831 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004832
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004833 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004834}
4835
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004836static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004837{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004838 void __iomem *ioaddr = tp->mmio_addr;
4839 struct pci_dev *pdev = tp->pci_dev;
4840
4841 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004842
4843 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4844
4845 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4846
4847 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4848}
4849
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004850static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004851{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004852 void __iomem *ioaddr = tp->mmio_addr;
4853 struct pci_dev *pdev = tp->pci_dev;
4854
4855 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004856
4857 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4858
4859 /* Magic. */
4860 RTL_W8(DBG_REG, 0x20);
4861
françois romieuf0298f82011-01-03 15:07:42 +00004862 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004863
4864 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4865
4866 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4867}
4868
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004869static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004870{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004871 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004872 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004873 { 0x02, 0x0800, 0x1000 },
4874 { 0x03, 0, 0x0002 },
4875 { 0x06, 0x0080, 0x0000 }
4876 };
4877
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004878 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004879
4880 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4881
Francois Romieufdf6fc02012-07-06 22:40:38 +02004882 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004883
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004884 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004885}
4886
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004887static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004888{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004889 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004890 { 0x01, 0, 0x0001 },
4891 { 0x03, 0x0400, 0x0220 }
4892 };
4893
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004894 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004895
Francois Romieufdf6fc02012-07-06 22:40:38 +02004896 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004897
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004898 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004899}
4900
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004901static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004902{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004903 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004904}
4905
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004906static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004907{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004908 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004909
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004910 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004911}
4912
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004913static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004914{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004915 void __iomem *ioaddr = tp->mmio_addr;
4916 struct pci_dev *pdev = tp->pci_dev;
4917
4918 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004919
4920 rtl_disable_clock_request(pdev);
4921
françois romieuf0298f82011-01-03 15:07:42 +00004922 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004923
4924 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4925
4926 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4927}
4928
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004929static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004930{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004931 void __iomem *ioaddr = tp->mmio_addr;
4932 struct pci_dev *pdev = tp->pci_dev;
4933
4934 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004935
4936 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4937
4938 RTL_W8(MaxTxPacketSize, TxPacketMax);
4939
4940 rtl_disable_clock_request(pdev);
4941}
4942
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004943static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004944{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004945 void __iomem *ioaddr = tp->mmio_addr;
4946 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004947 static const struct ephy_info e_info_8168d_4[] = {
4948 { 0x0b, ~0, 0x48 },
4949 { 0x19, 0x20, 0x50 },
4950 { 0x0c, ~0, 0x20 }
4951 };
4952 int i;
4953
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004954 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004955
4956 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4957
4958 RTL_W8(MaxTxPacketSize, TxPacketMax);
4959
4960 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4961 const struct ephy_info *e = e_info_8168d_4 + i;
4962 u16 w;
4963
Francois Romieufdf6fc02012-07-06 22:40:38 +02004964 w = rtl_ephy_read(tp, e->offset);
4965 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004966 }
4967
4968 rtl_enable_clock_request(pdev);
4969}
4970
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004971static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004972{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004973 void __iomem *ioaddr = tp->mmio_addr;
4974 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004975 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004976 { 0x00, 0x0200, 0x0100 },
4977 { 0x00, 0x0000, 0x0004 },
4978 { 0x06, 0x0002, 0x0001 },
4979 { 0x06, 0x0000, 0x0030 },
4980 { 0x07, 0x0000, 0x2000 },
4981 { 0x00, 0x0000, 0x0020 },
4982 { 0x03, 0x5800, 0x2000 },
4983 { 0x03, 0x0000, 0x0001 },
4984 { 0x01, 0x0800, 0x1000 },
4985 { 0x07, 0x0000, 0x4000 },
4986 { 0x1e, 0x0000, 0x2000 },
4987 { 0x19, 0xffff, 0xfe6c },
4988 { 0x0a, 0x0000, 0x0040 }
4989 };
4990
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004991 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00004992
Francois Romieufdf6fc02012-07-06 22:40:38 +02004993 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00004994
4995 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4996
4997 RTL_W8(MaxTxPacketSize, TxPacketMax);
4998
4999 rtl_disable_clock_request(pdev);
5000
5001 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02005002 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
5003 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00005004
Francois Romieucecb5fd2011-04-01 10:21:07 +02005005 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00005006}
5007
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005008static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08005009{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005010 void __iomem *ioaddr = tp->mmio_addr;
5011 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08005012 static const struct ephy_info e_info_8168e_2[] = {
5013 { 0x09, 0x0000, 0x0080 },
5014 { 0x19, 0x0000, 0x0224 }
5015 };
5016
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005017 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005018
Francois Romieufdf6fc02012-07-06 22:40:38 +02005019 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08005020
5021 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5022
Francois Romieufdf6fc02012-07-06 22:40:38 +02005023 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5024 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5025 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5026 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5027 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5028 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5029 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5030 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005031
Hayes Wang3090bd92011-09-06 16:55:15 +08005032 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005033
5034 rtl_disable_clock_request(pdev);
5035
5036 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5037 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5038
5039 /* Adjust EEE LED frequency */
5040 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5041
5042 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5043 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5044 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5045}
5046
Hayes Wang5f886e02012-03-30 14:33:03 +08005047static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005048{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005049 void __iomem *ioaddr = tp->mmio_addr;
5050 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005051
Hayes Wang5f886e02012-03-30 14:33:03 +08005052 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005053
5054 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5055
Francois Romieufdf6fc02012-07-06 22:40:38 +02005056 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5057 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5058 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5059 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5060 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5061 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5062 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5063 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5064 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5065 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005066
5067 RTL_W8(MaxTxPacketSize, EarlySize);
5068
5069 rtl_disable_clock_request(pdev);
5070
5071 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5072 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005073 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5074 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5075 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5076}
5077
Hayes Wang5f886e02012-03-30 14:33:03 +08005078static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5079{
5080 void __iomem *ioaddr = tp->mmio_addr;
5081 static const struct ephy_info e_info_8168f_1[] = {
5082 { 0x06, 0x00c0, 0x0020 },
5083 { 0x08, 0x0001, 0x0002 },
5084 { 0x09, 0x0000, 0x0080 },
5085 { 0x19, 0x0000, 0x0224 }
5086 };
5087
5088 rtl_hw_start_8168f(tp);
5089
Francois Romieufdf6fc02012-07-06 22:40:38 +02005090 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005091
Francois Romieufdf6fc02012-07-06 22:40:38 +02005092 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005093
5094 /* Adjust EEE LED frequency */
5095 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5096}
5097
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005098static void rtl_hw_start_8411(struct rtl8169_private *tp)
5099{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005100 static const struct ephy_info e_info_8168f_1[] = {
5101 { 0x06, 0x00c0, 0x0020 },
5102 { 0x0f, 0xffff, 0x5200 },
5103 { 0x1e, 0x0000, 0x4000 },
5104 { 0x19, 0x0000, 0x0224 }
5105 };
5106
5107 rtl_hw_start_8168f(tp);
5108
Francois Romieufdf6fc02012-07-06 22:40:38 +02005109 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005110
Francois Romieufdf6fc02012-07-06 22:40:38 +02005111 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005112}
5113
Hayes Wangc5583862012-07-02 17:23:22 +08005114static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5115{
5116 void __iomem *ioaddr = tp->mmio_addr;
5117 struct pci_dev *pdev = tp->pci_dev;
5118
5119 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5120 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5121 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5122 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5123
5124 rtl_csi_access_enable_1(tp);
5125
5126 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5127
5128 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5129 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5130
5131 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5132 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
5133 RTL_W8(MaxTxPacketSize, EarlySize);
5134
5135 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5136 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5137
5138 /* Adjust EEE LED frequency */
5139 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5140
5141 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5142}
5143
Francois Romieu07ce4062007-02-23 23:36:39 +01005144static void rtl_hw_start_8168(struct net_device *dev)
5145{
Francois Romieu2dd99532007-06-11 23:22:52 +02005146 struct rtl8169_private *tp = netdev_priv(dev);
5147 void __iomem *ioaddr = tp->mmio_addr;
5148
5149 RTL_W8(Cfg9346, Cfg9346_Unlock);
5150
françois romieuf0298f82011-01-03 15:07:42 +00005151 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005152
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005153 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005154
Francois Romieu0e485152007-02-20 00:00:26 +01005155 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005156
5157 RTL_W16(CPlusCmd, tp->cp_cmd);
5158
Francois Romieu0e485152007-02-20 00:00:26 +01005159 RTL_W16(IntrMitigate, 0x5151);
5160
5161 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005162 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005163 tp->event_slow |= RxFIFOOver | PCSTimeout;
5164 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005165 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005166
5167 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5168
Francois Romieub8363902008-06-01 12:31:57 +02005169 rtl_set_rx_mode(dev);
5170
5171 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5172 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005173
5174 RTL_R8(IntrMask);
5175
Francois Romieu219a1e92008-06-28 11:58:39 +02005176 switch (tp->mac_version) {
5177 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005178 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005179 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005180
5181 case RTL_GIGA_MAC_VER_12:
5182 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005183 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005184 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005185
5186 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005187 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005188 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005189
5190 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005191 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005192 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005193
5194 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005195 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005196 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005197
Francois Romieu197ff762008-06-28 13:16:02 +02005198 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005199 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005200 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005201
Francois Romieu6fb07052008-06-29 11:54:28 +02005202 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005203 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005204 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005205
Francois Romieuef3386f2008-06-29 12:24:30 +02005206 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005207 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005208 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005209
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005210 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005211 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005212 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005213
Francois Romieu5b538df2008-07-20 16:22:45 +02005214 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005215 case RTL_GIGA_MAC_VER_26:
5216 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005217 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005218 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005219
françois romieue6de30d2011-01-03 15:08:37 +00005220 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005221 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005222 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005223
hayeswang4804b3b2011-03-21 01:50:29 +00005224 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005225 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005226 break;
5227
hayeswang01dc7fe2011-03-21 01:50:28 +00005228 case RTL_GIGA_MAC_VER_32:
5229 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005230 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005231 break;
5232 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005233 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005234 break;
françois romieue6de30d2011-01-03 15:08:37 +00005235
Hayes Wangc2218922011-09-06 16:55:18 +08005236 case RTL_GIGA_MAC_VER_35:
5237 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005238 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005239 break;
5240
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005241 case RTL_GIGA_MAC_VER_38:
5242 rtl_hw_start_8411(tp);
5243 break;
5244
Hayes Wangc5583862012-07-02 17:23:22 +08005245 case RTL_GIGA_MAC_VER_40:
5246 case RTL_GIGA_MAC_VER_41:
5247 rtl_hw_start_8168g_1(tp);
5248 break;
5249
Francois Romieu219a1e92008-06-28 11:58:39 +02005250 default:
5251 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5252 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005253 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005254 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005255
Francois Romieu0e485152007-02-20 00:00:26 +01005256 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5257
Francois Romieub8363902008-06-01 12:31:57 +02005258 RTL_W8(Cfg9346, Cfg9346_Lock);
5259
Francois Romieu2dd99532007-06-11 23:22:52 +02005260 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005261}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262
Francois Romieu2857ffb2008-08-02 21:08:49 +02005263#define R810X_CPCMD_QUIRK_MASK (\
5264 EnableBist | \
5265 Mac_dbgo_oe | \
5266 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005267 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005268 Force_txflow_en | \
5269 Cxpl_dbg_sel | \
5270 ASF | \
5271 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005272 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005273
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005274static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005275{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005276 void __iomem *ioaddr = tp->mmio_addr;
5277 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005278 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005279 { 0x01, 0, 0x6e65 },
5280 { 0x02, 0, 0x091f },
5281 { 0x03, 0, 0xc2f9 },
5282 { 0x06, 0, 0xafb5 },
5283 { 0x07, 0, 0x0e00 },
5284 { 0x19, 0, 0xec80 },
5285 { 0x01, 0, 0x2e65 },
5286 { 0x01, 0, 0x6e65 }
5287 };
5288 u8 cfg1;
5289
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005290 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005291
5292 RTL_W8(DBG_REG, FIX_NAK_1);
5293
5294 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5295
5296 RTL_W8(Config1,
5297 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5298 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5299
5300 cfg1 = RTL_R8(Config1);
5301 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5302 RTL_W8(Config1, cfg1 & ~LEDS0);
5303
Francois Romieufdf6fc02012-07-06 22:40:38 +02005304 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005305}
5306
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005307static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005308{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005309 void __iomem *ioaddr = tp->mmio_addr;
5310 struct pci_dev *pdev = tp->pci_dev;
5311
5312 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005313
5314 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5315
5316 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5317 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005318}
5319
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005320static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005321{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005322 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005323
Francois Romieufdf6fc02012-07-06 22:40:38 +02005324 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005325}
5326
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005327static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005328{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005329 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005330 static const struct ephy_info e_info_8105e_1[] = {
5331 { 0x07, 0, 0x4000 },
5332 { 0x19, 0, 0x0200 },
5333 { 0x19, 0, 0x0020 },
5334 { 0x1e, 0, 0x2000 },
5335 { 0x03, 0, 0x0001 },
5336 { 0x19, 0, 0x0100 },
5337 { 0x19, 0, 0x0004 },
5338 { 0x0a, 0, 0x0020 }
5339 };
5340
Francois Romieucecb5fd2011-04-01 10:21:07 +02005341 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005342 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5343
Francois Romieucecb5fd2011-04-01 10:21:07 +02005344 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005345 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5346
5347 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e52011-07-06 15:58:02 +08005348 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005349
Francois Romieufdf6fc02012-07-06 22:40:38 +02005350 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005351}
5352
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005353static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005354{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005355 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005356 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005357}
5358
Hayes Wang7e18dca2012-03-30 14:33:02 +08005359static void rtl_hw_start_8402(struct rtl8169_private *tp)
5360{
5361 void __iomem *ioaddr = tp->mmio_addr;
5362 static const struct ephy_info e_info_8402[] = {
5363 { 0x19, 0xffff, 0xff64 },
5364 { 0x1e, 0, 0x4000 }
5365 };
5366
5367 rtl_csi_access_enable_2(tp);
5368
5369 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5370 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5371
5372 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5373 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5374
Francois Romieufdf6fc02012-07-06 22:40:38 +02005375 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005376
5377 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5378
Francois Romieufdf6fc02012-07-06 22:40:38 +02005379 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5380 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5381 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5382 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5383 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5384 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5385 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005386}
5387
Hayes Wang5598bfe2012-07-02 17:23:21 +08005388static void rtl_hw_start_8106(struct rtl8169_private *tp)
5389{
5390 void __iomem *ioaddr = tp->mmio_addr;
5391
5392 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5393 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5394
5395 RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
5396 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5397 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5398}
5399
Francois Romieu07ce4062007-02-23 23:36:39 +01005400static void rtl_hw_start_8101(struct net_device *dev)
5401{
Francois Romieucdf1a602007-06-11 23:29:50 +02005402 struct rtl8169_private *tp = netdev_priv(dev);
5403 void __iomem *ioaddr = tp->mmio_addr;
5404 struct pci_dev *pdev = tp->pci_dev;
5405
Francois Romieuda78dbf2012-01-26 14:18:23 +01005406 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5407 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005408
Francois Romieucecb5fd2011-04-01 10:21:07 +02005409 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
5410 tp->mac_version == RTL_GIGA_MAC_VER_16) {
Jon Masone44daad2011-06-27 07:46:31 +00005411 int cap = pci_pcie_cap(pdev);
Francois Romieu9c14cea2008-07-05 00:21:15 +02005412
5413 if (cap) {
5414 pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
5415 PCI_EXP_DEVCTL_NOSNOOP_EN);
5416 }
Francois Romieucdf1a602007-06-11 23:29:50 +02005417 }
5418
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005419 RTL_W8(Cfg9346, Cfg9346_Unlock);
5420
Francois Romieu2857ffb2008-08-02 21:08:49 +02005421 switch (tp->mac_version) {
5422 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005423 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005424 break;
5425
5426 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005427 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005428 break;
5429
5430 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005431 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005432 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005433
5434 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005435 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005436 break;
5437 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005438 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005439 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005440
5441 case RTL_GIGA_MAC_VER_37:
5442 rtl_hw_start_8402(tp);
5443 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005444
5445 case RTL_GIGA_MAC_VER_39:
5446 rtl_hw_start_8106(tp);
5447 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005448 }
5449
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005450 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005451
françois romieuf0298f82011-01-03 15:07:42 +00005452 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005453
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005454 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005455
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005456 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005457 RTL_W16(CPlusCmd, tp->cp_cmd);
5458
5459 RTL_W16(IntrMitigate, 0x0000);
5460
5461 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5462
5463 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5464 rtl_set_rx_tx_config_registers(tp);
5465
Francois Romieucdf1a602007-06-11 23:29:50 +02005466 RTL_R8(IntrMask);
5467
Francois Romieucdf1a602007-06-11 23:29:50 +02005468 rtl_set_rx_mode(dev);
5469
5470 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471}
5472
5473static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5474{
Francois Romieud58d46b2011-05-03 16:38:29 +02005475 struct rtl8169_private *tp = netdev_priv(dev);
5476
5477 if (new_mtu < ETH_ZLEN ||
5478 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 return -EINVAL;
5480
Francois Romieud58d46b2011-05-03 16:38:29 +02005481 if (new_mtu > ETH_DATA_LEN)
5482 rtl_hw_jumbo_enable(tp);
5483 else
5484 rtl_hw_jumbo_disable(tp);
5485
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005487 netdev_update_features(dev);
5488
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005489 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490}
5491
5492static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5493{
Al Viro95e09182007-12-22 18:55:39 +00005494 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5496}
5497
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005498static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5499 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005501 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005502 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005503
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005504 kfree(*data_buff);
5505 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 rtl8169_make_unusable_by_asic(desc);
5507}
5508
5509static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5510{
5511 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5512
5513 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5514}
5515
5516static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5517 u32 rx_buf_sz)
5518{
5519 desc->addr = cpu_to_le64(mapping);
5520 wmb();
5521 rtl8169_mark_to_asic(desc, rx_buf_sz);
5522}
5523
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005524static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005526 return (void *)ALIGN((long)data, 16);
5527}
5528
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005529static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5530 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005531{
5532 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005534 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005535 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005536 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005538 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5539 if (!data)
5540 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005541
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005542 if (rtl8169_align(data) != data) {
5543 kfree(data);
5544 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5545 if (!data)
5546 return NULL;
5547 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005548
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005549 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005550 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005551 if (unlikely(dma_mapping_error(d, mapping))) {
5552 if (net_ratelimit())
5553 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005554 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556
5557 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005558 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005559
5560err_out:
5561 kfree(data);
5562 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563}
5564
5565static void rtl8169_rx_clear(struct rtl8169_private *tp)
5566{
Francois Romieu07d3f512007-02-21 22:40:46 +01005567 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568
5569 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005570 if (tp->Rx_databuff[i]) {
5571 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 tp->RxDescArray + i);
5573 }
5574 }
5575}
5576
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005577static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005579 desc->opts1 |= cpu_to_le32(RingEnd);
5580}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005581
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005582static int rtl8169_rx_fill(struct rtl8169_private *tp)
5583{
5584 unsigned int i;
5585
5586 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005587 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005588
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005589 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005591
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005592 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005593 if (!data) {
5594 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005595 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005596 }
5597 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005600 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5601 return 0;
5602
5603err_out:
5604 rtl8169_rx_clear(tp);
5605 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606}
5607
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608static int rtl8169_init_ring(struct net_device *dev)
5609{
5610 struct rtl8169_private *tp = netdev_priv(dev);
5611
5612 rtl8169_init_ring_indexes(tp);
5613
5614 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005615 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005617 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618}
5619
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005620static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621 struct TxDesc *desc)
5622{
5623 unsigned int len = tx_skb->len;
5624
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005625 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5626
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 desc->opts1 = 0x00;
5628 desc->opts2 = 0x00;
5629 desc->addr = 0x00;
5630 tx_skb->len = 0;
5631}
5632
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005633static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5634 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635{
5636 unsigned int i;
5637
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005638 for (i = 0; i < n; i++) {
5639 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 struct ring_info *tx_skb = tp->tx_skb + entry;
5641 unsigned int len = tx_skb->len;
5642
5643 if (len) {
5644 struct sk_buff *skb = tx_skb->skb;
5645
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005646 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 tp->TxDescArray + entry);
5648 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005649 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 dev_kfree_skb(skb);
5651 tx_skb->skb = NULL;
5652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 }
5654 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005655}
5656
5657static void rtl8169_tx_clear(struct rtl8169_private *tp)
5658{
5659 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 tp->cur_tx = tp->dirty_tx = 0;
5661}
5662
Francois Romieu4422bcd2012-01-26 11:23:32 +01005663static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664{
David Howellsc4028952006-11-22 14:57:56 +00005665 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005666 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
Francois Romieuda78dbf2012-01-26 14:18:23 +01005668 napi_disable(&tp->napi);
5669 netif_stop_queue(dev);
5670 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671
françois romieuc7c2c392011-12-04 20:30:52 +00005672 rtl8169_hw_reset(tp);
5673
Francois Romieu56de4142011-03-15 17:29:31 +01005674 for (i = 0; i < NUM_RX_DESC; i++)
5675 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5676
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005678 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
Francois Romieuda78dbf2012-01-26 14:18:23 +01005680 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005681 rtl_hw_start(dev);
5682 netif_wake_queue(dev);
5683 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684}
5685
5686static void rtl8169_tx_timeout(struct net_device *dev)
5687{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005688 struct rtl8169_private *tp = netdev_priv(dev);
5689
5690 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691}
5692
5693static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005694 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695{
5696 struct skb_shared_info *info = skb_shinfo(skb);
5697 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005698 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005699 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
5701 entry = tp->cur_tx;
5702 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005703 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 dma_addr_t mapping;
5705 u32 status, len;
5706 void *addr;
5707
5708 entry = (entry + 1) % NUM_TX_DESC;
5709
5710 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005711 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005712 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005713 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005714 if (unlikely(dma_mapping_error(d, mapping))) {
5715 if (net_ratelimit())
5716 netif_err(tp, drv, tp->dev,
5717 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005718 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720
Francois Romieucecb5fd2011-04-01 10:21:07 +02005721 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005722 status = opts[0] | len |
5723 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
5725 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005726 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 txd->addr = cpu_to_le64(mapping);
5728
5729 tp->tx_skb[entry].len = len;
5730 }
5731
5732 if (cur_frag) {
5733 tp->tx_skb[entry].skb = skb;
5734 txd->opts1 |= cpu_to_le32(LastFrag);
5735 }
5736
5737 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005738
5739err_out:
5740 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5741 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742}
5743
Francois Romieu2b7b4312011-04-18 22:53:24 -07005744static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5745 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005747 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005748 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005749 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750
Francois Romieu2b7b4312011-04-18 22:53:24 -07005751 if (mss) {
5752 opts[0] |= TD_LSO;
5753 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5754 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005755 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
5757 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005758 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005760 opts[offset] |= info->checksum.udp;
5761 else
5762 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764}
5765
Stephen Hemminger613573252009-08-31 19:50:58 +00005766static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5767 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768{
5769 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005770 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 struct TxDesc *txd = tp->TxDescArray + entry;
5772 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005773 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774 dma_addr_t mapping;
5775 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005776 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005777 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005778
Julien Ducourthial477206a2012-05-09 00:00:06 +02005779 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005780 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005781 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 }
5783
5784 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005785 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005787 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005788 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005789 if (unlikely(dma_mapping_error(d, mapping))) {
5790 if (net_ratelimit())
5791 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005792 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
5795 tp->tx_skb[entry].len = len;
5796 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
Francois Romieu2b7b4312011-04-18 22:53:24 -07005798 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
5799 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005800
Francois Romieu2b7b4312011-04-18 22:53:24 -07005801 rtl8169_tso_csum(tp, skb, opts);
5802
5803 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005804 if (frags < 0)
5805 goto err_dma_1;
5806 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005807 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005808 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005809 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005810 tp->tx_skb[entry].skb = skb;
5811 }
5812
Francois Romieu2b7b4312011-04-18 22:53:24 -07005813 txd->opts2 = cpu_to_le32(opts[1]);
5814
Richard Cochran5047fb52012-03-10 07:29:42 +00005815 skb_tx_timestamp(skb);
5816
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 wmb();
5818
Francois Romieucecb5fd2011-04-01 10:21:07 +02005819 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005820 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 txd->opts1 = cpu_to_le32(status);
5822
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 tp->cur_tx += frags + 1;
5824
David Dillow4c020a92010-03-03 16:33:10 +00005825 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
Francois Romieucecb5fd2011-04-01 10:21:07 +02005827 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
Francois Romieuda78dbf2012-01-26 14:18:23 +01005829 mmiowb();
5830
Julien Ducourthial477206a2012-05-09 00:00:06 +02005831 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005832 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5833 * not miss a ring update when it notices a stopped queue.
5834 */
5835 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005837 /* Sync with rtl_tx:
5838 * - publish queue status and cur_tx ring index (write barrier)
5839 * - refresh dirty_tx ring index (read barrier).
5840 * May the current thread have a pessimistic view of the ring
5841 * status and forget to wake up queue, a racing rtl_tx thread
5842 * can't.
5843 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005844 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005845 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 netif_wake_queue(dev);
5847 }
5848
Stephen Hemminger613573252009-08-31 19:50:58 +00005849 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005851err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005852 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005853err_dma_0:
5854 dev_kfree_skb(skb);
5855 dev->stats.tx_dropped++;
5856 return NETDEV_TX_OK;
5857
5858err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005860 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005861 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862}
5863
5864static void rtl8169_pcierr_interrupt(struct net_device *dev)
5865{
5866 struct rtl8169_private *tp = netdev_priv(dev);
5867 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 u16 pci_status, pci_cmd;
5869
5870 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5871 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5872
Joe Perchesbf82c182010-02-09 11:49:50 +00005873 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5874 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
5876 /*
5877 * The recovery sequence below admits a very elaborated explanation:
5878 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005879 * - I did not see what else could be done;
5880 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 *
5882 * Feel free to adjust to your needs.
5883 */
Francois Romieua27993f2006-12-18 00:04:19 +01005884 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005885 pci_cmd &= ~PCI_COMMAND_PARITY;
5886 else
5887 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5888
5889 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890
5891 pci_write_config_word(pdev, PCI_STATUS,
5892 pci_status & (PCI_STATUS_DETECTED_PARITY |
5893 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5894 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5895
5896 /* The infamous DAC f*ckup only happens at boot time */
5897 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005898 void __iomem *ioaddr = tp->mmio_addr;
5899
Joe Perchesbf82c182010-02-09 11:49:50 +00005900 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 tp->cp_cmd &= ~PCIDAC;
5902 RTL_W16(CPlusCmd, tp->cp_cmd);
5903 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 }
5905
françois romieue6de30d2011-01-03 15:08:37 +00005906 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005907
Francois Romieu98ddf982012-01-31 10:47:34 +01005908 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909}
5910
Francois Romieuda78dbf2012-01-26 14:18:23 +01005911static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912{
5913 unsigned int dirty_tx, tx_left;
5914
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 dirty_tx = tp->dirty_tx;
5916 smp_rmb();
5917 tx_left = tp->cur_tx - dirty_tx;
5918
5919 while (tx_left > 0) {
5920 unsigned int entry = dirty_tx % NUM_TX_DESC;
5921 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 u32 status;
5923
5924 rmb();
5925 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5926 if (status & DescOwn)
5927 break;
5928
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005929 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5930 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005932 u64_stats_update_begin(&tp->tx_stats.syncp);
5933 tp->tx_stats.packets++;
5934 tp->tx_stats.bytes += tx_skb->skb->len;
5935 u64_stats_update_end(&tp->tx_stats.syncp);
5936 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 tx_skb->skb = NULL;
5938 }
5939 dirty_tx++;
5940 tx_left--;
5941 }
5942
5943 if (tp->dirty_tx != dirty_tx) {
5944 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005945 /* Sync with rtl8169_start_xmit:
5946 * - publish dirty_tx ring index (write barrier)
5947 * - refresh cur_tx ring index and queue status (read barrier)
5948 * May the current thread miss the stopped queue condition,
5949 * a racing xmit thread can only have a right view of the
5950 * ring status.
5951 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005952 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005954 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955 netif_wake_queue(dev);
5956 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005957 /*
5958 * 8168 hack: TxPoll requests are lost when the Tx packets are
5959 * too close. Let's kick an extra TxPoll request when a burst
5960 * of start_xmit activity is detected (if it is not detected,
5961 * it is slow enough). -- FR
5962 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005963 if (tp->cur_tx != dirty_tx) {
5964 void __iomem *ioaddr = tp->mmio_addr;
5965
Francois Romieud78ae2d2007-08-26 20:08:19 +02005966 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968 }
5969}
5970
Francois Romieu126fa4b2005-05-12 20:09:17 -04005971static inline int rtl8169_fragmented_frame(u32 status)
5972{
5973 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5974}
5975
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005976static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 u32 status = opts1 & RxProtoMask;
5979
5980 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005981 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 skb->ip_summed = CHECKSUM_UNNECESSARY;
5983 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005984 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985}
5986
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005987static struct sk_buff *rtl8169_try_rx_copy(void *data,
5988 struct rtl8169_private *tp,
5989 int pkt_size,
5990 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02005992 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005993 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005995 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005996 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005997 prefetch(data);
5998 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
5999 if (skb)
6000 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00006001 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
6002
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006003 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004}
6005
Francois Romieuda78dbf2012-01-26 14:18:23 +01006006static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007{
6008 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006009 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 cur_rx = tp->cur_rx;
6012 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02006013 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006015 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006017 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 u32 status;
6019
6020 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04006021 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022
6023 if (status & DescOwn)
6024 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006025 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00006026 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
6027 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006028 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006030 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006032 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006033 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006034 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006035 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006036 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006037 if ((status & (RxRUNT | RxCRC)) &&
6038 !(status & (RxRWT | RxFOVF)) &&
6039 (dev->features & NETIF_F_RXALL))
6040 goto process_pkt;
6041
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006042 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006044 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006045 dma_addr_t addr;
6046 int pkt_size;
6047
6048process_pkt:
6049 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006050 if (likely(!(dev->features & NETIF_F_RXFCS)))
6051 pkt_size = (status & 0x00003fff) - 4;
6052 else
6053 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Francois Romieu126fa4b2005-05-12 20:09:17 -04006055 /*
6056 * The driver does not support incoming fragmented
6057 * frames. They are seen as a symptom of over-mtu
6058 * sized frames.
6059 */
6060 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006061 dev->stats.rx_dropped++;
6062 dev->stats.rx_length_errors++;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006063 rtl8169_mark_to_asic(desc, rx_buf_sz);
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006064 continue;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006065 }
6066
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006067 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6068 tp, pkt_size, addr);
6069 rtl8169_mark_to_asic(desc, rx_buf_sz);
6070 if (!skb) {
6071 dev->stats.rx_dropped++;
6072 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 }
6074
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006075 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 skb_put(skb, pkt_size);
6077 skb->protocol = eth_type_trans(skb, dev);
6078
Francois Romieu7a8fc772011-03-01 17:18:33 +01006079 rtl8169_rx_vlan_tag(desc, skb);
6080
Francois Romieu56de4142011-03-15 17:29:31 +01006081 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082
Junchang Wang8027aa22012-03-04 23:30:32 +01006083 u64_stats_update_begin(&tp->rx_stats.syncp);
6084 tp->rx_stats.packets++;
6085 tp->rx_stats.bytes += pkt_size;
6086 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 }
Francois Romieu6dccd162007-02-13 23:38:05 +01006088
6089 /* Work around for AMD plateform. */
Al Viro95e09182007-12-22 18:55:39 +00006090 if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
Francois Romieu6dccd162007-02-13 23:38:05 +01006091 (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
6092 desc->opts2 = 0;
6093 cur_rx++;
6094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 }
6096
6097 count = cur_rx - tp->cur_rx;
6098 tp->cur_rx = cur_rx;
6099
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006100 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101
6102 return count;
6103}
6104
Francois Romieu07d3f512007-02-21 22:40:46 +01006105static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106{
Francois Romieu07d3f512007-02-21 22:40:46 +01006107 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006110 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006112 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006113 if (status && status != 0xffff) {
6114 status &= RTL_EVENT_NAPI | tp->event_slow;
6115 if (status) {
6116 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006117
Francois Romieuda78dbf2012-01-26 14:18:23 +01006118 rtl_irq_disable(tp);
6119 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 return IRQ_RETVAL(handled);
6123}
6124
Francois Romieuda78dbf2012-01-26 14:18:23 +01006125/*
6126 * Workqueue context.
6127 */
6128static void rtl_slow_event_work(struct rtl8169_private *tp)
6129{
6130 struct net_device *dev = tp->dev;
6131 u16 status;
6132
6133 status = rtl_get_events(tp) & tp->event_slow;
6134 rtl_ack_events(tp, status);
6135
6136 if (unlikely(status & RxFIFOOver)) {
6137 switch (tp->mac_version) {
6138 /* Work around for rx fifo overflow */
6139 case RTL_GIGA_MAC_VER_11:
6140 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006141 /* XXX - Hack alert. See rtl_task(). */
6142 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006143 default:
6144 break;
6145 }
6146 }
6147
6148 if (unlikely(status & SYSErr))
6149 rtl8169_pcierr_interrupt(dev);
6150
6151 if (status & LinkChg)
6152 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6153
françois romieu7dbb4912012-06-09 10:53:16 +00006154 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006155}
6156
Francois Romieu4422bcd2012-01-26 11:23:32 +01006157static void rtl_task(struct work_struct *work)
6158{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006159 static const struct {
6160 int bitnr;
6161 void (*action)(struct rtl8169_private *);
6162 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006163 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006164 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6165 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6166 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6167 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006168 struct rtl8169_private *tp =
6169 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006170 struct net_device *dev = tp->dev;
6171 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006172
Francois Romieuda78dbf2012-01-26 14:18:23 +01006173 rtl_lock_work(tp);
6174
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006175 if (!netif_running(dev) ||
6176 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006177 goto out_unlock;
6178
6179 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6180 bool pending;
6181
Francois Romieuda78dbf2012-01-26 14:18:23 +01006182 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006183 if (pending)
6184 rtl_work[i].action(tp);
6185 }
6186
6187out_unlock:
6188 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006189}
6190
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006191static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006193 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6194 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006195 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6196 int work_done= 0;
6197 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
Francois Romieuda78dbf2012-01-26 14:18:23 +01006199 status = rtl_get_events(tp);
6200 rtl_ack_events(tp, status & ~tp->event_slow);
6201
6202 if (status & RTL_EVENT_NAPI_RX)
6203 work_done = rtl_rx(dev, tp, (u32) budget);
6204
6205 if (status & RTL_EVENT_NAPI_TX)
6206 rtl_tx(dev, tp);
6207
6208 if (status & tp->event_slow) {
6209 enable_mask &= ~tp->event_slow;
6210
6211 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006214 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006215 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006216
Francois Romieuda78dbf2012-01-26 14:18:23 +01006217 rtl_irq_enable(tp, enable_mask);
6218 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 }
6220
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006221 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Francois Romieu523a6092008-09-10 22:28:56 +02006224static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6225{
6226 struct rtl8169_private *tp = netdev_priv(dev);
6227
6228 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6229 return;
6230
6231 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6232 RTL_W32(RxMissed, 0);
6233}
6234
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235static void rtl8169_down(struct net_device *dev)
6236{
6237 struct rtl8169_private *tp = netdev_priv(dev);
6238 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239
Francois Romieu4876cc12011-03-11 21:07:11 +01006240 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006242 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006243 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244
Hayes Wang92fc43b2011-07-06 15:58:03 +08006245 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006246 /*
6247 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006248 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6249 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006250 */
Francois Romieu523a6092008-09-10 22:28:56 +02006251 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006254 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 rtl8169_tx_clear(tp);
6257
6258 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006259
6260 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261}
6262
6263static int rtl8169_close(struct net_device *dev)
6264{
6265 struct rtl8169_private *tp = netdev_priv(dev);
6266 struct pci_dev *pdev = tp->pci_dev;
6267
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006268 pm_runtime_get_sync(&pdev->dev);
6269
Francois Romieucecb5fd2011-04-01 10:21:07 +02006270 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006271 rtl8169_update_counters(dev);
6272
Francois Romieuda78dbf2012-01-26 14:18:23 +01006273 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006274 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006275
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006277 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006279 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006281 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6282 tp->RxPhyAddr);
6283 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6284 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 tp->TxDescArray = NULL;
6286 tp->RxDescArray = NULL;
6287
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006288 pm_runtime_put_sync(&pdev->dev);
6289
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 return 0;
6291}
6292
Francois Romieudc1c00c2012-03-08 10:06:18 +01006293#ifdef CONFIG_NET_POLL_CONTROLLER
6294static void rtl8169_netpoll(struct net_device *dev)
6295{
6296 struct rtl8169_private *tp = netdev_priv(dev);
6297
6298 rtl8169_interrupt(tp->pci_dev->irq, dev);
6299}
6300#endif
6301
Francois Romieudf43ac72012-03-08 09:48:40 +01006302static int rtl_open(struct net_device *dev)
6303{
6304 struct rtl8169_private *tp = netdev_priv(dev);
6305 void __iomem *ioaddr = tp->mmio_addr;
6306 struct pci_dev *pdev = tp->pci_dev;
6307 int retval = -ENOMEM;
6308
6309 pm_runtime_get_sync(&pdev->dev);
6310
6311 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006312 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006313 * dma_alloc_coherent provides more.
6314 */
6315 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6316 &tp->TxPhyAddr, GFP_KERNEL);
6317 if (!tp->TxDescArray)
6318 goto err_pm_runtime_put;
6319
6320 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6321 &tp->RxPhyAddr, GFP_KERNEL);
6322 if (!tp->RxDescArray)
6323 goto err_free_tx_0;
6324
6325 retval = rtl8169_init_ring(dev);
6326 if (retval < 0)
6327 goto err_free_rx_1;
6328
6329 INIT_WORK(&tp->wk.work, rtl_task);
6330
6331 smp_mb();
6332
6333 rtl_request_firmware(tp);
6334
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006335 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006336 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6337 dev->name, dev);
6338 if (retval < 0)
6339 goto err_release_fw_2;
6340
6341 rtl_lock_work(tp);
6342
6343 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6344
6345 napi_enable(&tp->napi);
6346
6347 rtl8169_init_phy(dev, tp);
6348
6349 __rtl8169_set_features(dev, dev->features);
6350
6351 rtl_pll_power_up(tp);
6352
6353 rtl_hw_start(dev);
6354
6355 netif_start_queue(dev);
6356
6357 rtl_unlock_work(tp);
6358
6359 tp->saved_wolopts = 0;
6360 pm_runtime_put_noidle(&pdev->dev);
6361
6362 rtl8169_check_link_status(dev, tp, ioaddr);
6363out:
6364 return retval;
6365
6366err_release_fw_2:
6367 rtl_release_firmware(tp);
6368 rtl8169_rx_clear(tp);
6369err_free_rx_1:
6370 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6371 tp->RxPhyAddr);
6372 tp->RxDescArray = NULL;
6373err_free_tx_0:
6374 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6375 tp->TxPhyAddr);
6376 tp->TxDescArray = NULL;
6377err_pm_runtime_put:
6378 pm_runtime_put_noidle(&pdev->dev);
6379 goto out;
6380}
6381
Junchang Wang8027aa22012-03-04 23:30:32 +01006382static struct rtnl_link_stats64 *
6383rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384{
6385 struct rtl8169_private *tp = netdev_priv(dev);
6386 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006387 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388
Francois Romieuda78dbf2012-01-26 14:18:23 +01006389 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006390 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006391
Junchang Wang8027aa22012-03-04 23:30:32 +01006392 do {
6393 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6394 stats->rx_packets = tp->rx_stats.packets;
6395 stats->rx_bytes = tp->rx_stats.bytes;
6396 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6397
6398
6399 do {
6400 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6401 stats->tx_packets = tp->tx_stats.packets;
6402 stats->tx_bytes = tp->tx_stats.bytes;
6403 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6404
6405 stats->rx_dropped = dev->stats.rx_dropped;
6406 stats->tx_dropped = dev->stats.tx_dropped;
6407 stats->rx_length_errors = dev->stats.rx_length_errors;
6408 stats->rx_errors = dev->stats.rx_errors;
6409 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6410 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6411 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6412
6413 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414}
6415
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006416static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006417{
françois romieu065c27c2011-01-03 15:08:12 +00006418 struct rtl8169_private *tp = netdev_priv(dev);
6419
Francois Romieu5d06a992006-02-23 00:47:58 +01006420 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006421 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006422
6423 netif_device_detach(dev);
6424 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006425
6426 rtl_lock_work(tp);
6427 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006428 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006429 rtl_unlock_work(tp);
6430
6431 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006432}
Francois Romieu5d06a992006-02-23 00:47:58 +01006433
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006434#ifdef CONFIG_PM
6435
6436static int rtl8169_suspend(struct device *device)
6437{
6438 struct pci_dev *pdev = to_pci_dev(device);
6439 struct net_device *dev = pci_get_drvdata(pdev);
6440
6441 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006442
Francois Romieu5d06a992006-02-23 00:47:58 +01006443 return 0;
6444}
6445
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006446static void __rtl8169_resume(struct net_device *dev)
6447{
françois romieu065c27c2011-01-03 15:08:12 +00006448 struct rtl8169_private *tp = netdev_priv(dev);
6449
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006450 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006451
6452 rtl_pll_power_up(tp);
6453
Artem Savkovcff4c162012-04-03 10:29:11 +00006454 rtl_lock_work(tp);
6455 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006456 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006457 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006458
Francois Romieu98ddf982012-01-31 10:47:34 +01006459 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006460}
6461
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006462static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006463{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006464 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006465 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006466 struct rtl8169_private *tp = netdev_priv(dev);
6467
6468 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006469
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006470 if (netif_running(dev))
6471 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006472
Francois Romieu5d06a992006-02-23 00:47:58 +01006473 return 0;
6474}
6475
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006476static int rtl8169_runtime_suspend(struct device *device)
6477{
6478 struct pci_dev *pdev = to_pci_dev(device);
6479 struct net_device *dev = pci_get_drvdata(pdev);
6480 struct rtl8169_private *tp = netdev_priv(dev);
6481
6482 if (!tp->TxDescArray)
6483 return 0;
6484
Francois Romieuda78dbf2012-01-26 14:18:23 +01006485 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006486 tp->saved_wolopts = __rtl8169_get_wol(tp);
6487 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006488 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006489
6490 rtl8169_net_suspend(dev);
6491
6492 return 0;
6493}
6494
6495static int rtl8169_runtime_resume(struct device *device)
6496{
6497 struct pci_dev *pdev = to_pci_dev(device);
6498 struct net_device *dev = pci_get_drvdata(pdev);
6499 struct rtl8169_private *tp = netdev_priv(dev);
6500
6501 if (!tp->TxDescArray)
6502 return 0;
6503
Francois Romieuda78dbf2012-01-26 14:18:23 +01006504 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006505 __rtl8169_set_wol(tp, tp->saved_wolopts);
6506 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006507 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006508
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006509 rtl8169_init_phy(dev, tp);
6510
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006511 __rtl8169_resume(dev);
6512
6513 return 0;
6514}
6515
6516static int rtl8169_runtime_idle(struct device *device)
6517{
6518 struct pci_dev *pdev = to_pci_dev(device);
6519 struct net_device *dev = pci_get_drvdata(pdev);
6520 struct rtl8169_private *tp = netdev_priv(dev);
6521
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006522 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006523}
6524
Alexey Dobriyan47145212009-12-14 18:00:08 -08006525static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006526 .suspend = rtl8169_suspend,
6527 .resume = rtl8169_resume,
6528 .freeze = rtl8169_suspend,
6529 .thaw = rtl8169_resume,
6530 .poweroff = rtl8169_suspend,
6531 .restore = rtl8169_resume,
6532 .runtime_suspend = rtl8169_runtime_suspend,
6533 .runtime_resume = rtl8169_runtime_resume,
6534 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006535};
6536
6537#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6538
6539#else /* !CONFIG_PM */
6540
6541#define RTL8169_PM_OPS NULL
6542
6543#endif /* !CONFIG_PM */
6544
David S. Miller1805b2f2011-10-24 18:18:09 -04006545static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6546{
6547 void __iomem *ioaddr = tp->mmio_addr;
6548
6549 /* WoL fails with 8168b when the receiver is disabled. */
6550 switch (tp->mac_version) {
6551 case RTL_GIGA_MAC_VER_11:
6552 case RTL_GIGA_MAC_VER_12:
6553 case RTL_GIGA_MAC_VER_17:
6554 pci_clear_master(tp->pci_dev);
6555
6556 RTL_W8(ChipCmd, CmdRxEnb);
6557 /* PCI commit */
6558 RTL_R8(ChipCmd);
6559 break;
6560 default:
6561 break;
6562 }
6563}
6564
Francois Romieu1765f952008-09-13 17:21:40 +02006565static void rtl_shutdown(struct pci_dev *pdev)
6566{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006567 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006568 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006569 struct device *d = &pdev->dev;
6570
6571 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006572
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006573 rtl8169_net_suspend(dev);
6574
Francois Romieucecb5fd2011-04-01 10:21:07 +02006575 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006576 rtl_rar_set(tp, dev->perm_addr);
6577
Hayes Wang92fc43b2011-07-06 15:58:03 +08006578 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006579
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006580 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006581 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6582 rtl_wol_suspend_quirk(tp);
6583 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006584 }
6585
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006586 pci_wake_from_d3(pdev, true);
6587 pci_set_power_state(pdev, PCI_D3hot);
6588 }
françois romieu2a15cd22012-03-06 01:14:12 +00006589
6590 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006591}
Francois Romieu5d06a992006-02-23 00:47:58 +01006592
Francois Romieue27566e2012-03-08 09:54:01 +01006593static void __devexit rtl_remove_one(struct pci_dev *pdev)
6594{
6595 struct net_device *dev = pci_get_drvdata(pdev);
6596 struct rtl8169_private *tp = netdev_priv(dev);
6597
6598 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6599 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6600 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6601 rtl8168_driver_stop(tp);
6602 }
6603
6604 cancel_work_sync(&tp->wk.work);
6605
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006606 netif_napi_del(&tp->napi);
6607
Francois Romieue27566e2012-03-08 09:54:01 +01006608 unregister_netdev(dev);
6609
6610 rtl_release_firmware(tp);
6611
6612 if (pci_dev_run_wake(pdev))
6613 pm_runtime_get_noresume(&pdev->dev);
6614
6615 /* restore original MAC address */
6616 rtl_rar_set(tp, dev->perm_addr);
6617
6618 rtl_disable_msi(pdev, tp);
6619 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6620 pci_set_drvdata(pdev, NULL);
6621}
6622
Francois Romieufa9c3852012-03-08 10:01:50 +01006623static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006624 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006625 .ndo_stop = rtl8169_close,
6626 .ndo_get_stats64 = rtl8169_get_stats64,
6627 .ndo_start_xmit = rtl8169_start_xmit,
6628 .ndo_tx_timeout = rtl8169_tx_timeout,
6629 .ndo_validate_addr = eth_validate_addr,
6630 .ndo_change_mtu = rtl8169_change_mtu,
6631 .ndo_fix_features = rtl8169_fix_features,
6632 .ndo_set_features = rtl8169_set_features,
6633 .ndo_set_mac_address = rtl_set_mac_address,
6634 .ndo_do_ioctl = rtl8169_ioctl,
6635 .ndo_set_rx_mode = rtl_set_rx_mode,
6636#ifdef CONFIG_NET_POLL_CONTROLLER
6637 .ndo_poll_controller = rtl8169_netpoll,
6638#endif
6639
6640};
6641
Francois Romieu31fa8b12012-03-08 10:09:40 +01006642static const struct rtl_cfg_info {
6643 void (*hw_start)(struct net_device *);
6644 unsigned int region;
6645 unsigned int align;
6646 u16 event_slow;
6647 unsigned features;
6648 u8 default_ver;
6649} rtl_cfg_infos [] = {
6650 [RTL_CFG_0] = {
6651 .hw_start = rtl_hw_start_8169,
6652 .region = 1,
6653 .align = 0,
6654 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6655 .features = RTL_FEATURE_GMII,
6656 .default_ver = RTL_GIGA_MAC_VER_01,
6657 },
6658 [RTL_CFG_1] = {
6659 .hw_start = rtl_hw_start_8168,
6660 .region = 2,
6661 .align = 8,
6662 .event_slow = SYSErr | LinkChg | RxOverflow,
6663 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6664 .default_ver = RTL_GIGA_MAC_VER_11,
6665 },
6666 [RTL_CFG_2] = {
6667 .hw_start = rtl_hw_start_8101,
6668 .region = 2,
6669 .align = 8,
6670 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6671 PCSTimeout,
6672 .features = RTL_FEATURE_MSI,
6673 .default_ver = RTL_GIGA_MAC_VER_13,
6674 }
6675};
6676
6677/* Cfg9346_Unlock assumed. */
6678static unsigned rtl_try_msi(struct rtl8169_private *tp,
6679 const struct rtl_cfg_info *cfg)
6680{
6681 void __iomem *ioaddr = tp->mmio_addr;
6682 unsigned msi = 0;
6683 u8 cfg2;
6684
6685 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6686 if (cfg->features & RTL_FEATURE_MSI) {
6687 if (pci_enable_msi(tp->pci_dev)) {
6688 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6689 } else {
6690 cfg2 |= MSIEnable;
6691 msi = RTL_FEATURE_MSI;
6692 }
6693 }
6694 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6695 RTL_W8(Config2, cfg2);
6696 return msi;
6697}
6698
Hayes Wangc5583862012-07-02 17:23:22 +08006699DECLARE_RTL_COND(rtl_link_list_ready_cond)
6700{
6701 void __iomem *ioaddr = tp->mmio_addr;
6702
6703 return RTL_R8(MCU) & LINK_LIST_RDY;
6704}
6705
6706DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6707{
6708 void __iomem *ioaddr = tp->mmio_addr;
6709
6710 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6711}
6712
6713static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
6714{
6715 void __iomem *ioaddr = tp->mmio_addr;
6716 u32 data;
6717
6718 tp->ocp_base = OCP_STD_PHY_BASE;
6719
6720 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6721
6722 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6723 return;
6724
6725 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6726 return;
6727
6728 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6729 msleep(1);
6730 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6731
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006732 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006733 data &= ~(1 << 14);
6734 r8168_mac_ocp_write(tp, 0xe8de, data);
6735
6736 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6737 return;
6738
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006739 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006740 data |= (1 << 15);
6741 r8168_mac_ocp_write(tp, 0xe8de, data);
6742
6743 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6744 return;
6745}
6746
6747static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
6748{
6749 switch (tp->mac_version) {
6750 case RTL_GIGA_MAC_VER_40:
6751 case RTL_GIGA_MAC_VER_41:
6752 rtl_hw_init_8168g(tp);
6753 break;
6754
6755 default:
6756 break;
6757 }
6758}
6759
Francois Romieu3b6cf252012-03-08 09:59:04 +01006760static int __devinit
6761rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6762{
6763 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6764 const unsigned int region = cfg->region;
6765 struct rtl8169_private *tp;
6766 struct mii_if_info *mii;
6767 struct net_device *dev;
6768 void __iomem *ioaddr;
6769 int chipset, i;
6770 int rc;
6771
6772 if (netif_msg_drv(&debug)) {
6773 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6774 MODULENAME, RTL8169_VERSION);
6775 }
6776
6777 dev = alloc_etherdev(sizeof (*tp));
6778 if (!dev) {
6779 rc = -ENOMEM;
6780 goto out;
6781 }
6782
6783 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006784 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006785 tp = netdev_priv(dev);
6786 tp->dev = dev;
6787 tp->pci_dev = pdev;
6788 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6789
6790 mii = &tp->mii;
6791 mii->dev = dev;
6792 mii->mdio_read = rtl_mdio_read;
6793 mii->mdio_write = rtl_mdio_write;
6794 mii->phy_id_mask = 0x1f;
6795 mii->reg_num_mask = 0x1f;
6796 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6797
6798 /* disable ASPM completely as that cause random device stop working
6799 * problems as well as full system hangs for some PCIe devices users */
6800 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6801 PCIE_LINK_STATE_CLKPM);
6802
6803 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6804 rc = pci_enable_device(pdev);
6805 if (rc < 0) {
6806 netif_err(tp, probe, dev, "enable failure\n");
6807 goto err_out_free_dev_1;
6808 }
6809
6810 if (pci_set_mwi(pdev) < 0)
6811 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6812
6813 /* make sure PCI base addr 1 is MMIO */
6814 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6815 netif_err(tp, probe, dev,
6816 "region #%d not an MMIO resource, aborting\n",
6817 region);
6818 rc = -ENODEV;
6819 goto err_out_mwi_2;
6820 }
6821
6822 /* check for weird/broken PCI region reporting */
6823 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6824 netif_err(tp, probe, dev,
6825 "Invalid PCI region size(s), aborting\n");
6826 rc = -ENODEV;
6827 goto err_out_mwi_2;
6828 }
6829
6830 rc = pci_request_regions(pdev, MODULENAME);
6831 if (rc < 0) {
6832 netif_err(tp, probe, dev, "could not request regions\n");
6833 goto err_out_mwi_2;
6834 }
6835
6836 tp->cp_cmd = RxChkSum;
6837
6838 if ((sizeof(dma_addr_t) > 4) &&
6839 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6840 tp->cp_cmd |= PCIDAC;
6841 dev->features |= NETIF_F_HIGHDMA;
6842 } else {
6843 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6844 if (rc < 0) {
6845 netif_err(tp, probe, dev, "DMA configuration failed\n");
6846 goto err_out_free_res_3;
6847 }
6848 }
6849
6850 /* ioremap MMIO region */
6851 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6852 if (!ioaddr) {
6853 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6854 rc = -EIO;
6855 goto err_out_free_res_3;
6856 }
6857 tp->mmio_addr = ioaddr;
6858
6859 if (!pci_is_pcie(pdev))
6860 netif_info(tp, probe, dev, "not PCI Express\n");
6861
6862 /* Identify chip attached to board */
6863 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6864
6865 rtl_init_rxcfg(tp);
6866
6867 rtl_irq_disable(tp);
6868
Hayes Wangc5583862012-07-02 17:23:22 +08006869 rtl_hw_initialize(tp);
6870
Francois Romieu3b6cf252012-03-08 09:59:04 +01006871 rtl_hw_reset(tp);
6872
6873 rtl_ack_events(tp, 0xffff);
6874
6875 pci_set_master(pdev);
6876
6877 /*
6878 * Pretend we are using VLANs; This bypasses a nasty bug where
6879 * Interrupts stop flowing on high load on 8110SCd controllers.
6880 */
6881 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6882 tp->cp_cmd |= RxVlan;
6883
6884 rtl_init_mdio_ops(tp);
6885 rtl_init_pll_power_ops(tp);
6886 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006887 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006888
6889 rtl8169_print_mac_version(tp);
6890
6891 chipset = tp->mac_version;
6892 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6893
6894 RTL_W8(Cfg9346, Cfg9346_Unlock);
6895 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6896 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6897 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6898 tp->features |= RTL_FEATURE_WOL;
6899 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6900 tp->features |= RTL_FEATURE_WOL;
6901 tp->features |= rtl_try_msi(tp, cfg);
6902 RTL_W8(Cfg9346, Cfg9346_Lock);
6903
6904 if (rtl_tbi_enabled(tp)) {
6905 tp->set_speed = rtl8169_set_speed_tbi;
6906 tp->get_settings = rtl8169_gset_tbi;
6907 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6908 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6909 tp->link_ok = rtl8169_tbi_link_ok;
6910 tp->do_ioctl = rtl_tbi_ioctl;
6911 } else {
6912 tp->set_speed = rtl8169_set_speed_xmii;
6913 tp->get_settings = rtl8169_gset_xmii;
6914 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6915 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6916 tp->link_ok = rtl8169_xmii_link_ok;
6917 tp->do_ioctl = rtl_xmii_ioctl;
6918 }
6919
6920 mutex_init(&tp->wk.mutex);
6921
6922 /* Get MAC address */
6923 for (i = 0; i < ETH_ALEN; i++)
6924 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6925 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6926
6927 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6928 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006929
6930 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6931
6932 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6933 * properly for all devices */
6934 dev->features |= NETIF_F_RXCSUM |
6935 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6936
6937 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6938 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6939 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6940 NETIF_F_HIGHDMA;
6941
6942 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6943 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6944 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6945
6946 dev->hw_features |= NETIF_F_RXALL;
6947 dev->hw_features |= NETIF_F_RXFCS;
6948
6949 tp->hw_start = cfg->hw_start;
6950 tp->event_slow = cfg->event_slow;
6951
6952 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6953 ~(RxBOVF | RxFOVF) : ~0;
6954
6955 init_timer(&tp->timer);
6956 tp->timer.data = (unsigned long) dev;
6957 tp->timer.function = rtl8169_phy_timer;
6958
6959 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6960
6961 rc = register_netdev(dev);
6962 if (rc < 0)
6963 goto err_out_msi_4;
6964
6965 pci_set_drvdata(pdev, dev);
6966
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006967 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6968 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6969 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006970 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6971 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6972 "tx checksumming: %s]\n",
6973 rtl_chip_infos[chipset].jumbo_max,
6974 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6975 }
6976
6977 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6978 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6979 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6980 rtl8168_driver_start(tp);
6981 }
6982
6983 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6984
6985 if (pci_dev_run_wake(pdev))
6986 pm_runtime_put_noidle(&pdev->dev);
6987
6988 netif_carrier_off(dev);
6989
6990out:
6991 return rc;
6992
6993err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006994 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006995 rtl_disable_msi(pdev, tp);
6996 iounmap(ioaddr);
6997err_out_free_res_3:
6998 pci_release_regions(pdev);
6999err_out_mwi_2:
7000 pci_clear_mwi(pdev);
7001 pci_disable_device(pdev);
7002err_out_free_dev_1:
7003 free_netdev(dev);
7004 goto out;
7005}
7006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007static struct pci_driver rtl8169_pci_driver = {
7008 .name = MODULENAME,
7009 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01007010 .probe = rtl_init_one,
Francois Romieue27566e2012-03-08 09:54:01 +01007011 .remove = __devexit_p(rtl_remove_one),
Francois Romieu1765f952008-09-13 17:21:40 +02007012 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00007013 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014};
7015
Francois Romieu07d3f512007-02-21 22:40:46 +01007016static int __init rtl8169_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017{
Jeff Garzik29917622006-08-19 17:48:59 -04007018 return pci_register_driver(&rtl8169_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007019}
7020
Francois Romieu07d3f512007-02-21 22:40:46 +01007021static void __exit rtl8169_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022{
7023 pci_unregister_driver(&rtl8169_pci_driver);
7024}
7025
7026module_init(rtl8169_init_module);
7027module_exit(rtl8169_cleanup_module);