blob: a7cc56007b330457c53b49ef4c51145d4990221d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Francois Romieu07d3f512007-02-21 22:40:46 +01002 * r8169.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/delay.h>
17#include <linux/ethtool.h>
18#include <linux/mii.h>
19#include <linux/if_vlan.h>
20#include <linux/crc32.h>
21#include <linux/in.h>
22#include <linux/ip.h>
23#include <linux/tcp.h>
24#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000025#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/dma-mapping.h>
Rafael J. Wysockie1759442010-03-14 14:33:51 +000027#include <linux/pm_runtime.h>
françois romieubca03d52011-01-03 15:07:31 +000028#include <linux/firmware.h>
Stanislaw Gruszkaba04c7c2011-02-22 02:00:11 +000029#include <linux/pci-aspm.h>
Paul Gortmaker70c71602011-05-22 16:47:17 -040030#include <linux/prefetch.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <asm/io.h>
33#include <asm/irq.h>
34
Francois Romieu865c6522008-05-11 14:51:00 +020035#define RTL8169_VERSION "2.3LK-NAPI"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MODULENAME "r8169"
37#define PFX MODULENAME ": "
38
françois romieubca03d52011-01-03 15:07:31 +000039#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
40#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
hayeswang01dc7fe2011-03-21 01:50:28 +000041#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
42#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
Hayes Wang70090422011-07-06 15:58:06 +080043#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
Hayes Wangc2218922011-09-06 16:55:18 +080044#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
45#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
Hayes Wang5a5e4442011-02-22 17:26:21 +080046#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
Hayes Wang7e18dca2012-03-30 14:33:02 +080047#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
Hayes Wangb3d7b2f2012-03-30 14:48:06 +080048#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
Hayes Wang5598bfe2012-07-02 17:23:21 +080049#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
Hayes Wangc5583862012-07-02 17:23:22 +080050#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
françois romieubca03d52011-01-03 15:07:31 +000051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#ifdef RTL8169_DEBUG
53#define assert(expr) \
Francois Romieu5b0384f2006-08-16 16:00:01 +020054 if (!(expr)) { \
55 printk( "Assertion failed! %s,%s,%s,line=%d\n", \
Harvey Harrisonb39d66a2008-08-20 16:52:04 -070056 #expr,__FILE__,__func__,__LINE__); \
Francois Romieu5b0384f2006-08-16 16:00:01 +020057 }
Joe Perches06fa7352007-10-18 21:15:00 +020058#define dprintk(fmt, args...) \
59 do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#else
61#define assert(expr) do {} while (0)
62#define dprintk(fmt, args...) do {} while (0)
63#endif /* RTL8169_DEBUG */
64
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020065#define R8169_MSG_DEFAULT \
Francois Romieuf0e837d2005-09-30 16:54:02 -070066 (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020067
Julien Ducourthial477206a2012-05-09 00:00:06 +020068#define TX_SLOTS_AVAIL(tp) \
69 (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
70
71/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
72#define TX_FRAGS_READY_FOR(tp,nr_frags) \
73 (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
76 The RTL chips use a 64 element hash table based on the Ethernet CRC. */
Arjan van de Venf71e1302006-03-03 21:33:57 -050077static const int multicast_filter_limit = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Francois Romieu9c14cea2008-07-05 00:21:15 +020079#define MAX_READ_REQUEST_SHIFT 12
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 },
290 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
Lennart Sorensen93a3aa22011-07-28 13:18:11 +0000291 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 },
Francois Romieubc1660b2007-10-12 23:58:09 +0200292 { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200293 { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
294 { PCI_VENDOR_ID_LINKSYS, 0x1032,
295 PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
Ciaran McCreesh11d2e282007-11-01 22:48:15 +0100296 { 0x0001, 0x8168,
297 PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 {0,},
299};
300
301MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
302
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000303static int rx_buf_sz = 16383;
David S. Miller4300e8c2010-03-26 10:23:30 -0700304static int use_dac;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200305static struct {
306 u32 msg_enable;
307} debug = { -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Francois Romieu07d3f512007-02-21 22:40:46 +0100309enum rtl_registers {
310 MAC0 = 0, /* Ethernet hardware address. */
Francois Romieu773d2022007-01-31 23:47:43 +0100311 MAC4 = 4,
Francois Romieu07d3f512007-02-21 22:40:46 +0100312 MAR0 = 8, /* Multicast filter. */
313 CounterAddrLow = 0x10,
314 CounterAddrHigh = 0x14,
315 TxDescStartAddrLow = 0x20,
316 TxDescStartAddrHigh = 0x24,
317 TxHDescStartAddrLow = 0x28,
318 TxHDescStartAddrHigh = 0x2c,
319 FLASH = 0x30,
320 ERSR = 0x36,
321 ChipCmd = 0x37,
322 TxPoll = 0x38,
323 IntrMask = 0x3c,
324 IntrStatus = 0x3e,
Francois Romieu2b7b4312011-04-18 22:53:24 -0700325
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800326 TxConfig = 0x40,
327#define TXCFG_AUTO_FIFO (1 << 7) /* 8111e-vl */
328#define TXCFG_EMPTY (1 << 11) /* 8111e-vl */
329
330 RxConfig = 0x44,
331#define RX128_INT_EN (1 << 15) /* 8111c and later */
332#define RX_MULTI_EN (1 << 14) /* 8111c only */
333#define RXCFG_FIFO_SHIFT 13
334 /* No threshold before first PCI xfer */
335#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
336#define RXCFG_DMA_SHIFT 8
337 /* Unlimited maximum PCI burst. */
338#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
Francois Romieu2b7b4312011-04-18 22:53:24 -0700339
Francois Romieu07d3f512007-02-21 22:40:46 +0100340 RxMissed = 0x4c,
341 Cfg9346 = 0x50,
342 Config0 = 0x51,
343 Config1 = 0x52,
344 Config2 = 0x53,
Francois Romieud387b422012-04-17 11:12:01 +0200345#define PME_SIGNAL (1 << 5) /* 8168c and later */
346
Francois Romieu07d3f512007-02-21 22:40:46 +0100347 Config3 = 0x54,
348 Config4 = 0x55,
349 Config5 = 0x56,
350 MultiIntr = 0x5c,
351 PHYAR = 0x60,
Francois Romieu07d3f512007-02-21 22:40:46 +0100352 PHYstatus = 0x6c,
353 RxMaxSize = 0xda,
354 CPlusCmd = 0xe0,
355 IntrMitigate = 0xe2,
356 RxDescAddrLow = 0xe4,
357 RxDescAddrHigh = 0xe8,
françois romieuf0298f82011-01-03 15:07:42 +0000358 EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
359
360#define NoEarlyTx 0x3f /* Max value : no early transmit. */
361
362 MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
363
364#define TxPacketMax (8064 >> 7)
Hayes Wang3090bd92011-09-06 16:55:15 +0800365#define EarlySize 0x27
françois romieuf0298f82011-01-03 15:07:42 +0000366
Francois Romieu07d3f512007-02-21 22:40:46 +0100367 FuncEvent = 0xf0,
368 FuncEventMask = 0xf4,
369 FuncPresetState = 0xf8,
370 FuncForceEvent = 0xfc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371};
372
Francois Romieuf162a5d2008-06-01 22:37:49 +0200373enum rtl8110_registers {
374 TBICSR = 0x64,
375 TBI_ANAR = 0x68,
376 TBI_LPAR = 0x6a,
377};
378
379enum rtl8168_8101_registers {
380 CSIDR = 0x64,
381 CSIAR = 0x68,
382#define CSIAR_FLAG 0x80000000
383#define CSIAR_WRITE_CMD 0x80000000
384#define CSIAR_BYTE_ENABLE 0x0f
385#define CSIAR_BYTE_ENABLE_SHIFT 12
386#define CSIAR_ADDR_MASK 0x0fff
Hayes Wang7e18dca2012-03-30 14:33:02 +0800387#define CSIAR_FUNC_CARD 0x00000000
388#define CSIAR_FUNC_SDIO 0x00010000
389#define CSIAR_FUNC_NIC 0x00020000
françois romieu065c27c2011-01-03 15:08:12 +0000390 PMCH = 0x6f,
Francois Romieuf162a5d2008-06-01 22:37:49 +0200391 EPHYAR = 0x80,
392#define EPHYAR_FLAG 0x80000000
393#define EPHYAR_WRITE_CMD 0x80000000
394#define EPHYAR_REG_MASK 0x1f
395#define EPHYAR_REG_SHIFT 16
396#define EPHYAR_DATA_MASK 0xffff
Hayes Wang5a5e4442011-02-22 17:26:21 +0800397 DLLPR = 0xd0,
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800398#define PFM_EN (1 << 6)
Francois Romieuf162a5d2008-06-01 22:37:49 +0200399 DBG_REG = 0xd1,
400#define FIX_NAK_1 (1 << 4)
401#define FIX_NAK_2 (1 << 3)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800402 TWSI = 0xd2,
403 MCU = 0xd3,
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800404#define NOW_IS_OOB (1 << 7)
Hayes Wangc5583862012-07-02 17:23:22 +0800405#define TX_EMPTY (1 << 5)
406#define RX_EMPTY (1 << 4)
407#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800408#define EN_NDP (1 << 3)
409#define EN_OOB_RESET (1 << 2)
Hayes Wangc5583862012-07-02 17:23:22 +0800410#define LINK_LIST_RDY (1 << 1)
françois romieudaf9df62009-10-07 12:44:20 +0000411 EFUSEAR = 0xdc,
412#define EFUSEAR_FLAG 0x80000000
413#define EFUSEAR_WRITE_CMD 0x80000000
414#define EFUSEAR_READ_CMD 0x00000000
415#define EFUSEAR_REG_MASK 0x03ff
416#define EFUSEAR_REG_SHIFT 8
417#define EFUSEAR_DATA_MASK 0xff
Francois Romieuf162a5d2008-06-01 22:37:49 +0200418};
419
françois romieuc0e45c12011-01-03 15:08:04 +0000420enum rtl8168_registers {
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800421 LED_FREQ = 0x1a,
422 EEE_LED = 0x1b,
françois romieub646d902011-01-03 15:08:21 +0000423 ERIDR = 0x70,
424 ERIAR = 0x74,
425#define ERIAR_FLAG 0x80000000
426#define ERIAR_WRITE_CMD 0x80000000
427#define ERIAR_READ_CMD 0x00000000
428#define ERIAR_ADDR_BYTE_ALIGN 4
françois romieub646d902011-01-03 15:08:21 +0000429#define ERIAR_TYPE_SHIFT 16
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800430#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT)
431#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT)
432#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT)
433#define ERIAR_MASK_SHIFT 12
434#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT)
435#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT)
Hayes Wangc5583862012-07-02 17:23:22 +0800436#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT)
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800437#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT)
françois romieuc0e45c12011-01-03 15:08:04 +0000438 EPHY_RXER_NUM = 0x7c,
439 OCPDR = 0xb0, /* OCP GPHY access */
440#define OCPDR_WRITE_CMD 0x80000000
441#define OCPDR_READ_CMD 0x00000000
442#define OCPDR_REG_MASK 0x7f
443#define OCPDR_GPHY_REG_SHIFT 16
444#define OCPDR_DATA_MASK 0xffff
445 OCPAR = 0xb4,
446#define OCPAR_FLAG 0x80000000
447#define OCPAR_GPHY_WRITE_CMD 0x8000f060
448#define OCPAR_GPHY_READ_CMD 0x0000f060
Hayes Wangc5583862012-07-02 17:23:22 +0800449 GPHY_OCP = 0xb8,
hayeswang01dc7fe2011-03-21 01:50:28 +0000450 RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */
451 MISC = 0xf0, /* 8168e only. */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200452#define TXPLA_RST (1 << 29)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800453#define DISABLE_LAN_EN (1 << 23) /* Enable GPIO pin */
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800454#define PWM_EN (1 << 22)
Hayes Wangc5583862012-07-02 17:23:22 +0800455#define RXDV_GATED_EN (1 << 19)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800456#define EARLY_TALLY_EN (1 << 16)
françois romieuc0e45c12011-01-03 15:08:04 +0000457};
458
Francois Romieu07d3f512007-02-21 22:40:46 +0100459enum rtl_register_content {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 /* InterruptStatusBits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100461 SYSErr = 0x8000,
462 PCSTimeout = 0x4000,
463 SWInt = 0x0100,
464 TxDescUnavail = 0x0080,
465 RxFIFOOver = 0x0040,
466 LinkChg = 0x0020,
467 RxOverflow = 0x0010,
468 TxErr = 0x0008,
469 TxOK = 0x0004,
470 RxErr = 0x0002,
471 RxOK = 0x0001,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473 /* RxStatusDesc */
David S. Miller8decf862011-09-22 03:23:13 -0400474 RxBOVF = (1 << 24),
Francois Romieu9dccf612006-05-14 12:31:17 +0200475 RxFOVF = (1 << 23),
476 RxRWT = (1 << 22),
477 RxRES = (1 << 21),
478 RxRUNT = (1 << 20),
479 RxCRC = (1 << 19),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 /* ChipCmdBits */
Hayes Wang4f6b00e52011-07-06 15:58:02 +0800482 StopReq = 0x80,
Francois Romieu07d3f512007-02-21 22:40:46 +0100483 CmdReset = 0x10,
484 CmdRxEnb = 0x08,
485 CmdTxEnb = 0x04,
486 RxBufEmpty = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Francois Romieu275391a2007-02-23 23:50:28 +0100488 /* TXPoll register p.5 */
489 HPQ = 0x80, /* Poll cmd on the high prio queue */
490 NPQ = 0x40, /* Poll cmd on the low prio queue */
491 FSWInt = 0x01, /* Forced software interrupt */
492
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 /* Cfg9346Bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100494 Cfg9346_Lock = 0x00,
495 Cfg9346_Unlock = 0xc0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
497 /* rx_mode_bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100498 AcceptErr = 0x20,
499 AcceptRunt = 0x10,
500 AcceptBroadcast = 0x08,
501 AcceptMulticast = 0x04,
502 AcceptMyPhys = 0x02,
503 AcceptAllPhys = 0x01,
Francois Romieu1687b562011-07-19 17:21:29 +0200504#define RX_CONFIG_ACCEPT_MASK 0x3f
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 /* TxConfigBits */
507 TxInterFrameGapShift = 24,
508 TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
509
Francois Romieu5d06a992006-02-23 00:47:58 +0100510 /* Config1 register p.24 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200511 LEDS1 = (1 << 7),
512 LEDS0 = (1 << 6),
Francois Romieuf162a5d2008-06-01 22:37:49 +0200513 Speed_down = (1 << 4),
514 MEMMAP = (1 << 3),
515 IOMAP = (1 << 2),
516 VPD = (1 << 1),
Francois Romieu5d06a992006-02-23 00:47:58 +0100517 PMEnable = (1 << 0), /* Power Management Enable */
518
Francois Romieu6dccd162007-02-13 23:38:05 +0100519 /* Config2 register p. 25 */
françois romieu2ca6cf02011-12-15 08:37:43 +0000520 MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
Francois Romieu6dccd162007-02-13 23:38:05 +0100521 PCI_Clock_66MHz = 0x01,
522 PCI_Clock_33MHz = 0x00,
523
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100524 /* Config3 register p.25 */
525 MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
526 LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
Francois Romieud58d46b2011-05-03 16:38:29 +0200527 Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200528 Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100529
Francois Romieud58d46b2011-05-03 16:38:29 +0200530 /* Config4 register */
531 Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */
532
Francois Romieu5d06a992006-02-23 00:47:58 +0100533 /* Config5 register p.27 */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100534 BWF = (1 << 6), /* Accept Broadcast wakeup frame */
535 MWF = (1 << 5), /* Accept Multicast wakeup frame */
536 UWF = (1 << 4), /* Accept Unicast wakeup frame */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200537 Spi_en = (1 << 3),
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100538 LanWake = (1 << 1), /* LanWake enable/disable */
Francois Romieu5d06a992006-02-23 00:47:58 +0100539 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 /* TBICSR p.28 */
542 TBIReset = 0x80000000,
543 TBILoopback = 0x40000000,
544 TBINwEnable = 0x20000000,
545 TBINwRestart = 0x10000000,
546 TBILinkOk = 0x02000000,
547 TBINwComplete = 0x01000000,
548
549 /* CPlusCmd p.31 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200550 EnableBist = (1 << 15), // 8168 8101
551 Mac_dbgo_oe = (1 << 14), // 8168 8101
552 Normal_mode = (1 << 13), // unused
553 Force_half_dup = (1 << 12), // 8168 8101
554 Force_rxflow_en = (1 << 11), // 8168 8101
555 Force_txflow_en = (1 << 10), // 8168 8101
556 Cxpl_dbg_sel = (1 << 9), // 8168 8101
557 ASF = (1 << 8), // 8168 8101
558 PktCntrDisable = (1 << 7), // 8168 8101
559 Mac_dbgo_sel = 0x001c, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 RxVlan = (1 << 6),
561 RxChkSum = (1 << 5),
562 PCIDAC = (1 << 4),
563 PCIMulRW = (1 << 3),
Francois Romieu0e485152007-02-20 00:00:26 +0100564 INTT_0 = 0x0000, // 8168
565 INTT_1 = 0x0001, // 8168
566 INTT_2 = 0x0002, // 8168
567 INTT_3 = 0x0003, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 /* rtl8169_PHYstatus */
Francois Romieu07d3f512007-02-21 22:40:46 +0100570 TBI_Enable = 0x80,
571 TxFlowCtrl = 0x40,
572 RxFlowCtrl = 0x20,
573 _1000bpsF = 0x10,
574 _100bps = 0x08,
575 _10bps = 0x04,
576 LinkStatus = 0x02,
577 FullDup = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 /* _TBICSRBit */
Francois Romieu07d3f512007-02-21 22:40:46 +0100580 TBILinkOK = 0x02000000,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +0200581
582 /* DumpCounterCommand */
Francois Romieu07d3f512007-02-21 22:40:46 +0100583 CounterDump = 0x8,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584};
585
Francois Romieu2b7b4312011-04-18 22:53:24 -0700586enum rtl_desc_bit {
587 /* First doubleword. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 DescOwn = (1 << 31), /* Descriptor is owned by NIC */
589 RingEnd = (1 << 30), /* End of descriptor ring */
590 FirstFrag = (1 << 29), /* First segment of a packet */
591 LastFrag = (1 << 28), /* Final segment of a packet */
Francois Romieu2b7b4312011-04-18 22:53:24 -0700592};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Francois Romieu2b7b4312011-04-18 22:53:24 -0700594/* Generic case. */
595enum rtl_tx_desc_bit {
596 /* First doubleword. */
597 TD_LSO = (1 << 27), /* Large Send Offload */
598#define TD_MSS_MAX 0x07ffu /* MSS value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Francois Romieu2b7b4312011-04-18 22:53:24 -0700600 /* Second doubleword. */
601 TxVlanTag = (1 << 17), /* Add VLAN tag */
602};
603
604/* 8169, 8168b and 810x except 8102e. */
605enum rtl_tx_desc_bit_0 {
606 /* First doubleword. */
607#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */
608 TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */
609 TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */
610 TD0_IP_CS = (1 << 18), /* Calculate IP checksum */
611};
612
613/* 8102e, 8168c and beyond. */
614enum rtl_tx_desc_bit_1 {
615 /* Second doubleword. */
616#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */
617 TD1_IP_CS = (1 << 29), /* Calculate IP checksum */
618 TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */
619 TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */
620};
621
622static const struct rtl_tx_desc_info {
623 struct {
624 u32 udp;
625 u32 tcp;
626 } checksum;
627 u16 mss_shift;
628 u16 opts_offset;
629} tx_desc_info [] = {
630 [RTL_TD_0] = {
631 .checksum = {
632 .udp = TD0_IP_CS | TD0_UDP_CS,
633 .tcp = TD0_IP_CS | TD0_TCP_CS
634 },
635 .mss_shift = TD0_MSS_SHIFT,
636 .opts_offset = 0
637 },
638 [RTL_TD_1] = {
639 .checksum = {
640 .udp = TD1_IP_CS | TD1_UDP_CS,
641 .tcp = TD1_IP_CS | TD1_TCP_CS
642 },
643 .mss_shift = TD1_MSS_SHIFT,
644 .opts_offset = 1
645 }
646};
647
648enum rtl_rx_desc_bit {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* Rx private */
650 PID1 = (1 << 18), /* Protocol ID bit 1/2 */
651 PID0 = (1 << 17), /* Protocol ID bit 2/2 */
652
653#define RxProtoUDP (PID1)
654#define RxProtoTCP (PID0)
655#define RxProtoIP (PID1 | PID0)
656#define RxProtoMask RxProtoIP
657
658 IPFail = (1 << 16), /* IP checksum failed */
659 UDPFail = (1 << 15), /* UDP/IP checksum failed */
660 TCPFail = (1 << 14), /* TCP/IP checksum failed */
661 RxVlanTag = (1 << 16), /* VLAN tag available */
662};
663
664#define RsvdMask 0x3fffc000
665
666struct TxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200667 __le32 opts1;
668 __le32 opts2;
669 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670};
671
672struct RxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200673 __le32 opts1;
674 __le32 opts2;
675 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676};
677
678struct ring_info {
679 struct sk_buff *skb;
680 u32 len;
681 u8 __pad[sizeof(void *) - sizeof(u32)];
682};
683
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200684enum features {
Francois Romieuccdffb92008-07-26 14:26:06 +0200685 RTL_FEATURE_WOL = (1 << 0),
686 RTL_FEATURE_MSI = (1 << 1),
687 RTL_FEATURE_GMII = (1 << 2),
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200688};
689
Ivan Vecera355423d2009-02-06 21:49:57 -0800690struct rtl8169_counters {
691 __le64 tx_packets;
692 __le64 rx_packets;
693 __le64 tx_errors;
694 __le32 rx_errors;
695 __le16 rx_missed;
696 __le16 align_errors;
697 __le32 tx_one_collision;
698 __le32 tx_multi_collision;
699 __le64 rx_unicast;
700 __le64 rx_broadcast;
701 __le32 rx_multicast;
702 __le16 tx_aborted;
703 __le16 tx_underun;
704};
705
Francois Romieuda78dbf2012-01-26 14:18:23 +0100706enum rtl_flag {
Francois Romieu6c4a70c2012-01-31 10:56:44 +0100707 RTL_FLAG_TASK_ENABLED,
Francois Romieuda78dbf2012-01-26 14:18:23 +0100708 RTL_FLAG_TASK_SLOW_PENDING,
709 RTL_FLAG_TASK_RESET_PENDING,
710 RTL_FLAG_TASK_PHY_PENDING,
711 RTL_FLAG_MAX
712};
713
Junchang Wang8027aa22012-03-04 23:30:32 +0100714struct rtl8169_stats {
715 u64 packets;
716 u64 bytes;
717 struct u64_stats_sync syncp;
718};
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720struct rtl8169_private {
721 void __iomem *mmio_addr; /* memory map physical address */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200722 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000723 struct net_device *dev;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700724 struct napi_struct napi;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200725 u32 msg_enable;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700726 u16 txd_version;
727 u16 mac_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
729 u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
730 u32 dirty_rx;
731 u32 dirty_tx;
Junchang Wang8027aa22012-03-04 23:30:32 +0100732 struct rtl8169_stats rx_stats;
733 struct rtl8169_stats tx_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
735 struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
736 dma_addr_t TxPhyAddr;
737 dma_addr_t RxPhyAddr;
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000738 void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 struct timer_list timer;
741 u16 cp_cmd;
Francois Romieuda78dbf2012-01-26 14:18:23 +0100742
743 u16 event_slow;
françois romieuc0e45c12011-01-03 15:08:04 +0000744
745 struct mdio_ops {
Francois Romieu24192212012-07-06 20:19:42 +0200746 void (*write)(struct rtl8169_private *, int, int);
747 int (*read)(struct rtl8169_private *, int);
françois romieuc0e45c12011-01-03 15:08:04 +0000748 } mdio_ops;
749
françois romieu065c27c2011-01-03 15:08:12 +0000750 struct pll_power_ops {
751 void (*down)(struct rtl8169_private *);
752 void (*up)(struct rtl8169_private *);
753 } pll_power_ops;
754
Francois Romieud58d46b2011-05-03 16:38:29 +0200755 struct jumbo_ops {
756 void (*enable)(struct rtl8169_private *);
757 void (*disable)(struct rtl8169_private *);
758 } jumbo_ops;
759
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800760 struct csi_ops {
Francois Romieu52989f02012-07-06 13:37:00 +0200761 void (*write)(struct rtl8169_private *, int, int);
762 u32 (*read)(struct rtl8169_private *, int);
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800763 } csi_ops;
764
Oliver Neukum54405cd2011-01-06 21:55:13 +0100765 int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
Francois Romieuccdffb92008-07-26 14:26:06 +0200766 int (*get_settings)(struct net_device *, struct ethtool_cmd *);
françois romieu4da19632011-01-03 15:07:55 +0000767 void (*phy_reset_enable)(struct rtl8169_private *tp);
Francois Romieu07ce4062007-02-23 23:36:39 +0100768 void (*hw_start)(struct net_device *);
françois romieu4da19632011-01-03 15:07:55 +0000769 unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 unsigned int (*link_ok)(void __iomem *);
Francois Romieu8b4ab282008-11-19 22:05:25 -0800771 int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
Francois Romieu4422bcd2012-01-26 11:23:32 +0100772
773 struct {
Francois Romieuda78dbf2012-01-26 14:18:23 +0100774 DECLARE_BITMAP(flags, RTL_FLAG_MAX);
775 struct mutex mutex;
Francois Romieu4422bcd2012-01-26 11:23:32 +0100776 struct work_struct work;
777 } wk;
778
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200779 unsigned features;
Francois Romieuccdffb92008-07-26 14:26:06 +0200780
781 struct mii_if_info mii;
Ivan Vecera355423d2009-02-06 21:49:57 -0800782 struct rtl8169_counters counters;
Rafael J. Wysockie1759442010-03-14 14:33:51 +0000783 u32 saved_wolopts;
David S. Miller8decf862011-09-22 03:23:13 -0400784 u32 opts1_mask;
françois romieuf1e02ed2011-01-13 13:07:53 +0000785
Francois Romieub6ffd972011-06-17 17:00:05 +0200786 struct rtl_fw {
787 const struct firmware *fw;
Francois Romieu1c361ef2011-06-17 17:16:24 +0200788
789#define RTL_VER_SIZE 32
790
791 char version[RTL_VER_SIZE];
792
793 struct rtl_fw_phy_action {
794 __le32 *code;
795 size_t size;
796 } phy_action;
Francois Romieub6ffd972011-06-17 17:00:05 +0200797 } *rtl_fw;
Phil Carmody497888c2011-07-14 15:07:13 +0300798#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
Hayes Wangc5583862012-07-02 17:23:22 +0800799
800 u32 ocp_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801};
802
Ralf Baechle979b6c12005-06-13 14:30:40 -0700803MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805module_param(use_dac, int, 0);
David S. Miller4300e8c2010-03-26 10:23:30 -0700806MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200807module_param_named(debug, debug.msg_enable, int, 0);
808MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809MODULE_LICENSE("GPL");
810MODULE_VERSION(RTL8169_VERSION);
françois romieubca03d52011-01-03 15:07:31 +0000811MODULE_FIRMWARE(FIRMWARE_8168D_1);
812MODULE_FIRMWARE(FIRMWARE_8168D_2);
hayeswang01dc7fe2011-03-21 01:50:28 +0000813MODULE_FIRMWARE(FIRMWARE_8168E_1);
814MODULE_FIRMWARE(FIRMWARE_8168E_2);
David S. Miller8decf862011-09-22 03:23:13 -0400815MODULE_FIRMWARE(FIRMWARE_8168E_3);
Hayes Wang5a5e4442011-02-22 17:26:21 +0800816MODULE_FIRMWARE(FIRMWARE_8105E_1);
Hayes Wangc2218922011-09-06 16:55:18 +0800817MODULE_FIRMWARE(FIRMWARE_8168F_1);
818MODULE_FIRMWARE(FIRMWARE_8168F_2);
Hayes Wang7e18dca2012-03-30 14:33:02 +0800819MODULE_FIRMWARE(FIRMWARE_8402_1);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800820MODULE_FIRMWARE(FIRMWARE_8411_1);
Hayes Wang5598bfe2012-07-02 17:23:21 +0800821MODULE_FIRMWARE(FIRMWARE_8106E_1);
Hayes Wangc5583862012-07-02 17:23:22 +0800822MODULE_FIRMWARE(FIRMWARE_8168G_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
Francois Romieuda78dbf2012-01-26 14:18:23 +0100824static void rtl_lock_work(struct rtl8169_private *tp)
825{
826 mutex_lock(&tp->wk.mutex);
827}
828
829static void rtl_unlock_work(struct rtl8169_private *tp)
830{
831 mutex_unlock(&tp->wk.mutex);
832}
833
Francois Romieud58d46b2011-05-03 16:38:29 +0200834static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
835{
Jiang Liu7d7903b2012-07-24 17:20:16 +0800836 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
837 PCI_EXP_DEVCTL_READRQ, force);
Francois Romieud58d46b2011-05-03 16:38:29 +0200838}
839
Francois Romieuffc46952012-07-06 14:19:23 +0200840struct rtl_cond {
841 bool (*check)(struct rtl8169_private *);
842 const char *msg;
843};
844
845static void rtl_udelay(unsigned int d)
846{
847 udelay(d);
848}
849
850static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
851 void (*delay)(unsigned int), unsigned int d, int n,
852 bool high)
853{
854 int i;
855
856 for (i = 0; i < n; i++) {
857 delay(d);
858 if (c->check(tp) == high)
859 return true;
860 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200861 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
862 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200863 return false;
864}
865
866static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
867 const struct rtl_cond *c,
868 unsigned int d, int n)
869{
870 return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
871}
872
873static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
874 const struct rtl_cond *c,
875 unsigned int d, int n)
876{
877 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
878}
879
880static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
881 const struct rtl_cond *c,
882 unsigned int d, int n)
883{
884 return rtl_loop_wait(tp, c, msleep, d, n, true);
885}
886
887static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
888 const struct rtl_cond *c,
889 unsigned int d, int n)
890{
891 return rtl_loop_wait(tp, c, msleep, d, n, false);
892}
893
894#define DECLARE_RTL_COND(name) \
895static bool name ## _check(struct rtl8169_private *); \
896 \
897static const struct rtl_cond name = { \
898 .check = name ## _check, \
899 .msg = #name \
900}; \
901 \
902static bool name ## _check(struct rtl8169_private *tp)
903
904DECLARE_RTL_COND(rtl_ocpar_cond)
905{
906 void __iomem *ioaddr = tp->mmio_addr;
907
908 return RTL_R32(OCPAR) & OCPAR_FLAG;
909}
910
françois romieub646d902011-01-03 15:08:21 +0000911static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
912{
913 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000914
915 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200916
917 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
918 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000919}
920
921static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
922{
923 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000924
925 RTL_W32(OCPDR, data);
926 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200927
928 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
929}
930
931DECLARE_RTL_COND(rtl_eriar_cond)
932{
933 void __iomem *ioaddr = tp->mmio_addr;
934
935 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000936}
937
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800938static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000939{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800940 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000941
942 RTL_W8(ERIDR, cmd);
943 RTL_W32(ERIAR, 0x800010e8);
944 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200945
946 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
947 return;
françois romieub646d902011-01-03 15:08:21 +0000948
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800949 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000950}
951
952#define OOB_CMD_RESET 0x00
953#define OOB_CMD_DRIVER_START 0x05
954#define OOB_CMD_DRIVER_STOP 0x06
955
Francois Romieucecb5fd2011-04-01 10:21:07 +0200956static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
957{
958 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
959}
960
Francois Romieuffc46952012-07-06 14:19:23 +0200961DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000962{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200963 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000964
Francois Romieucecb5fd2011-04-01 10:21:07 +0200965 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000966
Francois Romieuffc46952012-07-06 14:19:23 +0200967 return ocp_read(tp, 0x0f, reg) & 0x00000800;
968}
969
970static void rtl8168_driver_start(struct rtl8169_private *tp)
971{
972 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
973
974 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000975}
976
977static void rtl8168_driver_stop(struct rtl8169_private *tp)
978{
françois romieub646d902011-01-03 15:08:21 +0000979 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
980
Francois Romieuffc46952012-07-06 14:19:23 +0200981 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000982}
983
hayeswang4804b3b2011-03-21 01:50:29 +0000984static int r8168dp_check_dash(struct rtl8169_private *tp)
985{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200986 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000987
Francois Romieucecb5fd2011-04-01 10:21:07 +0200988 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000989}
françois romieub646d902011-01-03 15:08:21 +0000990
Hayes Wangc5583862012-07-02 17:23:22 +0800991static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
992{
993 if (reg & 0xffff0001) {
994 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
995 return true;
996 }
997 return false;
998}
999
1000DECLARE_RTL_COND(rtl_ocp_gphy_cond)
1001{
1002 void __iomem *ioaddr = tp->mmio_addr;
1003
1004 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1005}
1006
1007static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1008{
1009 void __iomem *ioaddr = tp->mmio_addr;
1010
1011 if (rtl_ocp_reg_failure(tp, reg))
1012 return;
1013
1014 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1015
1016 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1017}
1018
1019static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1020{
1021 void __iomem *ioaddr = tp->mmio_addr;
1022
1023 if (rtl_ocp_reg_failure(tp, reg))
1024 return 0;
1025
1026 RTL_W32(GPHY_OCP, reg << 15);
1027
1028 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1029 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1030}
1031
1032static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1033{
1034 int val;
1035
1036 val = r8168_phy_ocp_read(tp, reg);
1037 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1038}
1039
Hayes Wangc5583862012-07-02 17:23:22 +08001040static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1041{
1042 void __iomem *ioaddr = tp->mmio_addr;
1043
1044 if (rtl_ocp_reg_failure(tp, reg))
1045 return;
1046
1047 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001048}
1049
1050static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1051{
1052 void __iomem *ioaddr = tp->mmio_addr;
1053
1054 if (rtl_ocp_reg_failure(tp, reg))
1055 return 0;
1056
1057 RTL_W32(OCPDR, reg << 15);
1058
Hayes Wang3a83ad12012-07-11 20:31:56 +08001059 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001060}
1061
1062#define OCP_STD_PHY_BASE 0xa400
1063
1064static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1065{
1066 if (reg == 0x1f) {
1067 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1068 return;
1069 }
1070
1071 if (tp->ocp_base != OCP_STD_PHY_BASE)
1072 reg -= 0x10;
1073
1074 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1075}
1076
1077static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1078{
1079 if (tp->ocp_base != OCP_STD_PHY_BASE)
1080 reg -= 0x10;
1081
1082 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1083}
1084
Francois Romieuffc46952012-07-06 14:19:23 +02001085DECLARE_RTL_COND(rtl_phyar_cond)
1086{
1087 void __iomem *ioaddr = tp->mmio_addr;
1088
1089 return RTL_R32(PHYAR) & 0x80000000;
1090}
1091
Francois Romieu24192212012-07-06 20:19:42 +02001092static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093{
Francois Romieu24192212012-07-06 20:19:42 +02001094 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Francois Romieu24192212012-07-06 20:19:42 +02001096 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Francois Romieuffc46952012-07-06 14:19:23 +02001098 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001099 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001100 * According to hardware specs a 20us delay is required after write
1101 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001102 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001103 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
Francois Romieu24192212012-07-06 20:19:42 +02001106static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Francois Romieu24192212012-07-06 20:19:42 +02001108 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001109 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Francois Romieu24192212012-07-06 20:19:42 +02001111 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Francois Romieuffc46952012-07-06 14:19:23 +02001113 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1114 RTL_R32(PHYAR) & 0xffff : ~0;
1115
Timo Teräs81a95f02010-06-09 17:31:48 -07001116 /*
1117 * According to hardware specs a 20us delay is required after read
1118 * complete indication, but before sending next command.
1119 */
1120 udelay(20);
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return value;
1123}
1124
Francois Romieu24192212012-07-06 20:19:42 +02001125static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001126{
Francois Romieu24192212012-07-06 20:19:42 +02001127 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001128
Francois Romieu24192212012-07-06 20:19:42 +02001129 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001130 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1131 RTL_W32(EPHY_RXER_NUM, 0);
1132
Francois Romieuffc46952012-07-06 14:19:23 +02001133 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001134}
1135
Francois Romieu24192212012-07-06 20:19:42 +02001136static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001137{
Francois Romieu24192212012-07-06 20:19:42 +02001138 r8168dp_1_mdio_access(tp, reg,
1139 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001140}
1141
Francois Romieu24192212012-07-06 20:19:42 +02001142static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001143{
Francois Romieu24192212012-07-06 20:19:42 +02001144 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001145
Francois Romieu24192212012-07-06 20:19:42 +02001146 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001147
1148 mdelay(1);
1149 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1150 RTL_W32(EPHY_RXER_NUM, 0);
1151
Francois Romieuffc46952012-07-06 14:19:23 +02001152 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1153 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001154}
1155
françois romieue6de30d2011-01-03 15:08:37 +00001156#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1157
1158static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1159{
1160 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1161}
1162
1163static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1164{
1165 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1166}
1167
Francois Romieu24192212012-07-06 20:19:42 +02001168static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001169{
Francois Romieu24192212012-07-06 20:19:42 +02001170 void __iomem *ioaddr = tp->mmio_addr;
1171
françois romieue6de30d2011-01-03 15:08:37 +00001172 r8168dp_2_mdio_start(ioaddr);
1173
Francois Romieu24192212012-07-06 20:19:42 +02001174 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001175
1176 r8168dp_2_mdio_stop(ioaddr);
1177}
1178
Francois Romieu24192212012-07-06 20:19:42 +02001179static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001180{
Francois Romieu24192212012-07-06 20:19:42 +02001181 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001182 int value;
1183
1184 r8168dp_2_mdio_start(ioaddr);
1185
Francois Romieu24192212012-07-06 20:19:42 +02001186 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001187
1188 r8168dp_2_mdio_stop(ioaddr);
1189
1190 return value;
1191}
1192
françois romieu4da19632011-01-03 15:07:55 +00001193static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001194{
Francois Romieu24192212012-07-06 20:19:42 +02001195 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001196}
1197
françois romieu4da19632011-01-03 15:07:55 +00001198static int rtl_readphy(struct rtl8169_private *tp, int location)
1199{
Francois Romieu24192212012-07-06 20:19:42 +02001200 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001201}
1202
1203static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1204{
1205 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1206}
1207
1208static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001209{
1210 int val;
1211
françois romieu4da19632011-01-03 15:07:55 +00001212 val = rtl_readphy(tp, reg_addr);
1213 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001214}
1215
Francois Romieuccdffb92008-07-26 14:26:06 +02001216static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1217 int val)
1218{
1219 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001220
françois romieu4da19632011-01-03 15:07:55 +00001221 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001222}
1223
1224static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1225{
1226 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001227
françois romieu4da19632011-01-03 15:07:55 +00001228 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001229}
1230
Francois Romieuffc46952012-07-06 14:19:23 +02001231DECLARE_RTL_COND(rtl_ephyar_cond)
1232{
1233 void __iomem *ioaddr = tp->mmio_addr;
1234
1235 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1236}
1237
Francois Romieufdf6fc02012-07-06 22:40:38 +02001238static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001239{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001240 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001241
1242 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1243 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1244
Francois Romieuffc46952012-07-06 14:19:23 +02001245 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1246
1247 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001248}
1249
Francois Romieufdf6fc02012-07-06 22:40:38 +02001250static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001251{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001252 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001253
1254 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1255
Francois Romieuffc46952012-07-06 14:19:23 +02001256 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1257 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001258}
1259
Francois Romieufdf6fc02012-07-06 22:40:38 +02001260static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1261 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001262{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001263 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001264
1265 BUG_ON((addr & 3) || (mask == 0));
1266 RTL_W32(ERIDR, val);
1267 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1268
Francois Romieuffc46952012-07-06 14:19:23 +02001269 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001270}
1271
Francois Romieufdf6fc02012-07-06 22:40:38 +02001272static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001273{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001274 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001275
1276 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1277
Francois Romieuffc46952012-07-06 14:19:23 +02001278 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1279 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001280}
1281
Francois Romieufdf6fc02012-07-06 22:40:38 +02001282static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1283 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001284{
1285 u32 val;
1286
Francois Romieufdf6fc02012-07-06 22:40:38 +02001287 val = rtl_eri_read(tp, addr, type);
1288 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001289}
1290
françois romieuc28aa382011-08-02 03:53:43 +00001291struct exgmac_reg {
1292 u16 addr;
1293 u16 mask;
1294 u32 val;
1295};
1296
Francois Romieufdf6fc02012-07-06 22:40:38 +02001297static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001298 const struct exgmac_reg *r, int len)
1299{
1300 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001301 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001302 r++;
1303 }
1304}
1305
Francois Romieuffc46952012-07-06 14:19:23 +02001306DECLARE_RTL_COND(rtl_efusear_cond)
1307{
1308 void __iomem *ioaddr = tp->mmio_addr;
1309
1310 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1311}
1312
Francois Romieufdf6fc02012-07-06 22:40:38 +02001313static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001314{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001315 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001316
1317 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1318
Francois Romieuffc46952012-07-06 14:19:23 +02001319 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1320 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001321}
1322
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001323static u16 rtl_get_events(struct rtl8169_private *tp)
1324{
1325 void __iomem *ioaddr = tp->mmio_addr;
1326
1327 return RTL_R16(IntrStatus);
1328}
1329
1330static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1331{
1332 void __iomem *ioaddr = tp->mmio_addr;
1333
1334 RTL_W16(IntrStatus, bits);
1335 mmiowb();
1336}
1337
1338static void rtl_irq_disable(struct rtl8169_private *tp)
1339{
1340 void __iomem *ioaddr = tp->mmio_addr;
1341
1342 RTL_W16(IntrMask, 0);
1343 mmiowb();
1344}
1345
Francois Romieu3e990ff2012-01-26 12:50:01 +01001346static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1347{
1348 void __iomem *ioaddr = tp->mmio_addr;
1349
1350 RTL_W16(IntrMask, bits);
1351}
1352
Francois Romieuda78dbf2012-01-26 14:18:23 +01001353#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1354#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1355#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1356
1357static void rtl_irq_enable_all(struct rtl8169_private *tp)
1358{
1359 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1360}
1361
françois romieu811fd302011-12-04 20:30:45 +00001362static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
françois romieu811fd302011-12-04 20:30:45 +00001364 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001366 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001367 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001368 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369}
1370
françois romieu4da19632011-01-03 15:07:55 +00001371static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
françois romieu4da19632011-01-03 15:07:55 +00001373 void __iomem *ioaddr = tp->mmio_addr;
1374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return RTL_R32(TBICSR) & TBIReset;
1376}
1377
françois romieu4da19632011-01-03 15:07:55 +00001378static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379{
françois romieu4da19632011-01-03 15:07:55 +00001380 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381}
1382
1383static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1384{
1385 return RTL_R32(TBICSR) & TBILinkOk;
1386}
1387
1388static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1389{
1390 return RTL_R8(PHYstatus) & LinkStatus;
1391}
1392
françois romieu4da19632011-01-03 15:07:55 +00001393static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
françois romieu4da19632011-01-03 15:07:55 +00001395 void __iomem *ioaddr = tp->mmio_addr;
1396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1398}
1399
françois romieu4da19632011-01-03 15:07:55 +00001400static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
1402 unsigned int val;
1403
françois romieu4da19632011-01-03 15:07:55 +00001404 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1405 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406}
1407
Hayes Wang70090422011-07-06 15:58:06 +08001408static void rtl_link_chg_patch(struct rtl8169_private *tp)
1409{
1410 void __iomem *ioaddr = tp->mmio_addr;
1411 struct net_device *dev = tp->dev;
1412
1413 if (!netif_running(dev))
1414 return;
1415
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001416 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1417 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001418 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001419 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1420 ERIAR_EXGMAC);
1421 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1422 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001423 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001424 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1425 ERIAR_EXGMAC);
1426 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1427 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001428 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001429 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1430 ERIAR_EXGMAC);
1431 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1432 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001433 }
1434 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001435 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001436 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001437 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001438 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001439 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1440 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1441 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001442 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1443 ERIAR_EXGMAC);
1444 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1445 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001446 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001447 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1448 ERIAR_EXGMAC);
1449 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1450 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001451 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001452 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1453 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001454 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1455 ERIAR_EXGMAC);
1456 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1457 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001458 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001459 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1460 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001461 }
Hayes Wang70090422011-07-06 15:58:06 +08001462 }
1463}
1464
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001465static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001466 struct rtl8169_private *tp,
1467 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001470 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001471 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001472 if (pm)
1473 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001475 if (net_ratelimit())
1476 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001477 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001479 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001480 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001481 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483}
1484
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001485static void rtl8169_check_link_status(struct net_device *dev,
1486 struct rtl8169_private *tp,
1487 void __iomem *ioaddr)
1488{
1489 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1490}
1491
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001492#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1493
1494static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1495{
1496 void __iomem *ioaddr = tp->mmio_addr;
1497 u8 options;
1498 u32 wolopts = 0;
1499
1500 options = RTL_R8(Config1);
1501 if (!(options & PMEnable))
1502 return 0;
1503
1504 options = RTL_R8(Config3);
1505 if (options & LinkUp)
1506 wolopts |= WAKE_PHY;
1507 if (options & MagicPacket)
1508 wolopts |= WAKE_MAGIC;
1509
1510 options = RTL_R8(Config5);
1511 if (options & UWF)
1512 wolopts |= WAKE_UCAST;
1513 if (options & BWF)
1514 wolopts |= WAKE_BCAST;
1515 if (options & MWF)
1516 wolopts |= WAKE_MCAST;
1517
1518 return wolopts;
1519}
1520
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001521static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1522{
1523 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001524
Francois Romieuda78dbf2012-01-26 14:18:23 +01001525 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001526
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001527 wol->supported = WAKE_ANY;
1528 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001529
Francois Romieuda78dbf2012-01-26 14:18:23 +01001530 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001531}
1532
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001533static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001534{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001535 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001536 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001537 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001538 u32 opt;
1539 u16 reg;
1540 u8 mask;
1541 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001542 { WAKE_PHY, Config3, LinkUp },
1543 { WAKE_MAGIC, Config3, MagicPacket },
1544 { WAKE_UCAST, Config5, UWF },
1545 { WAKE_BCAST, Config5, BWF },
1546 { WAKE_MCAST, Config5, MWF },
1547 { WAKE_ANY, Config5, LanWake }
1548 };
Francois Romieu851e6022012-04-17 11:10:11 +02001549 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001550
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001551 RTL_W8(Cfg9346, Cfg9346_Unlock);
1552
1553 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001554 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001555 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001556 options |= cfg[i].mask;
1557 RTL_W8(cfg[i].reg, options);
1558 }
1559
Francois Romieu851e6022012-04-17 11:10:11 +02001560 switch (tp->mac_version) {
1561 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1562 options = RTL_R8(Config1) & ~PMEnable;
1563 if (wolopts)
1564 options |= PMEnable;
1565 RTL_W8(Config1, options);
1566 break;
1567 default:
Francois Romieud387b422012-04-17 11:12:01 +02001568 options = RTL_R8(Config2) & ~PME_SIGNAL;
1569 if (wolopts)
1570 options |= PME_SIGNAL;
1571 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001572 break;
1573 }
1574
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001575 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001576}
1577
1578static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1579{
1580 struct rtl8169_private *tp = netdev_priv(dev);
1581
Francois Romieuda78dbf2012-01-26 14:18:23 +01001582 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001583
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001584 if (wol->wolopts)
1585 tp->features |= RTL_FEATURE_WOL;
1586 else
1587 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001588 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001589
1590 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001591
françois romieuea809072010-11-08 13:23:58 +00001592 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1593
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001594 return 0;
1595}
1596
Francois Romieu31bd2042011-04-26 18:58:59 +02001597static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1598{
Francois Romieu85bffe62011-04-27 08:22:39 +02001599 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001600}
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602static void rtl8169_get_drvinfo(struct net_device *dev,
1603 struct ethtool_drvinfo *info)
1604{
1605 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001606 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
Rick Jones68aad782011-11-07 13:29:27 +00001608 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1609 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1610 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001611 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001612 if (!IS_ERR_OR_NULL(rtl_fw))
1613 strlcpy(info->fw_version, rtl_fw->version,
1614 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615}
1616
1617static int rtl8169_get_regs_len(struct net_device *dev)
1618{
1619 return R8169_REGS_SIZE;
1620}
1621
1622static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001623 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624{
1625 struct rtl8169_private *tp = netdev_priv(dev);
1626 void __iomem *ioaddr = tp->mmio_addr;
1627 int ret = 0;
1628 u32 reg;
1629
1630 reg = RTL_R32(TBICSR);
1631 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1632 (duplex == DUPLEX_FULL)) {
1633 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1634 } else if (autoneg == AUTONEG_ENABLE)
1635 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1636 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001637 netif_warn(tp, link, dev,
1638 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 ret = -EOPNOTSUPP;
1640 }
1641
1642 return ret;
1643}
1644
1645static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001646 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647{
1648 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001649 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001650 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Hayes Wang716b50a2011-02-22 17:26:18 +08001652 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001655 int auto_nego;
1656
françois romieu4da19632011-01-03 15:07:55 +00001657 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001658 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1659 ADVERTISE_100HALF | ADVERTISE_100FULL);
1660
1661 if (adv & ADVERTISED_10baseT_Half)
1662 auto_nego |= ADVERTISE_10HALF;
1663 if (adv & ADVERTISED_10baseT_Full)
1664 auto_nego |= ADVERTISE_10FULL;
1665 if (adv & ADVERTISED_100baseT_Half)
1666 auto_nego |= ADVERTISE_100HALF;
1667 if (adv & ADVERTISED_100baseT_Full)
1668 auto_nego |= ADVERTISE_100FULL;
1669
françois romieu3577aa12009-05-19 10:46:48 +00001670 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1671
françois romieu4da19632011-01-03 15:07:55 +00001672 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001673 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1674
1675 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001676 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001677 if (adv & ADVERTISED_1000baseT_Half)
1678 giga_ctrl |= ADVERTISE_1000HALF;
1679 if (adv & ADVERTISED_1000baseT_Full)
1680 giga_ctrl |= ADVERTISE_1000FULL;
1681 } else if (adv & (ADVERTISED_1000baseT_Half |
1682 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001683 netif_info(tp, link, dev,
1684 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001685 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
françois romieu3577aa12009-05-19 10:46:48 +00001688 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001689
françois romieu4da19632011-01-03 15:07:55 +00001690 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1691 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001692 } else {
1693 giga_ctrl = 0;
1694
1695 if (speed == SPEED_10)
1696 bmcr = 0;
1697 else if (speed == SPEED_100)
1698 bmcr = BMCR_SPEED100;
1699 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001700 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001701
1702 if (duplex == DUPLEX_FULL)
1703 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001704 }
1705
françois romieu4da19632011-01-03 15:07:55 +00001706 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001707
Francois Romieucecb5fd2011-04-01 10:21:07 +02001708 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1709 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001710 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001711 rtl_writephy(tp, 0x17, 0x2138);
1712 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001713 } else {
françois romieu4da19632011-01-03 15:07:55 +00001714 rtl_writephy(tp, 0x17, 0x2108);
1715 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001716 }
1717 }
1718
Oliver Neukum54405cd2011-01-06 21:55:13 +01001719 rc = 0;
1720out:
1721 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
1724static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001725 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726{
1727 struct rtl8169_private *tp = netdev_priv(dev);
1728 int ret;
1729
Oliver Neukum54405cd2011-01-06 21:55:13 +01001730 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001731 if (ret < 0)
1732 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Francois Romieu4876cc12011-03-11 21:07:11 +01001734 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1735 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001737 }
1738out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 return ret;
1740}
1741
1742static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1743{
1744 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 int ret;
1746
Francois Romieu4876cc12011-03-11 21:07:11 +01001747 del_timer_sync(&tp->timer);
1748
Francois Romieuda78dbf2012-01-26 14:18:23 +01001749 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001750 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001751 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001752 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001753
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 return ret;
1755}
1756
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001757static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1758 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
Francois Romieud58d46b2011-05-03 16:38:29 +02001760 struct rtl8169_private *tp = netdev_priv(dev);
1761
Francois Romieu2b7b4312011-04-18 22:53:24 -07001762 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001763 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
Francois Romieud58d46b2011-05-03 16:38:29 +02001765 if (dev->mtu > JUMBO_1K &&
1766 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1767 features &= ~NETIF_F_IP_CSUM;
1768
Michał Mirosław350fb322011-04-08 06:35:56 +00001769 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770}
1771
Francois Romieuda78dbf2012-01-26 14:18:23 +01001772static void __rtl8169_set_features(struct net_device *dev,
1773 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774{
1775 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001776 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001777 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Ben Greear6bbe0212012-02-10 15:04:33 +00001779 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1780 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Ben Greear6bbe0212012-02-10 15:04:33 +00001782 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1783 if (features & NETIF_F_RXCSUM)
1784 tp->cp_cmd |= RxChkSum;
1785 else
1786 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001787
Ben Greear6bbe0212012-02-10 15:04:33 +00001788 if (dev->features & NETIF_F_HW_VLAN_RX)
1789 tp->cp_cmd |= RxVlan;
1790 else
1791 tp->cp_cmd &= ~RxVlan;
1792
1793 RTL_W16(CPlusCmd, tp->cp_cmd);
1794 RTL_R16(CPlusCmd);
1795 }
1796 if (changed & NETIF_F_RXALL) {
1797 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1798 if (features & NETIF_F_RXALL)
1799 tmp |= (AcceptErr | AcceptRunt);
1800 RTL_W32(RxConfig, tmp);
1801 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001802}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Francois Romieuda78dbf2012-01-26 14:18:23 +01001804static int rtl8169_set_features(struct net_device *dev,
1805 netdev_features_t features)
1806{
1807 struct rtl8169_private *tp = netdev_priv(dev);
1808
1809 rtl_lock_work(tp);
1810 __rtl8169_set_features(dev, features);
1811 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
1813 return 0;
1814}
1815
Francois Romieuda78dbf2012-01-26 14:18:23 +01001816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1818 struct sk_buff *skb)
1819{
Jesse Grosseab6d182010-10-20 13:56:03 +00001820 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1822}
1823
Francois Romieu7a8fc772011-03-01 17:18:33 +01001824static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
1826 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Francois Romieu7a8fc772011-03-01 17:18:33 +01001828 if (opts2 & RxVlanTag)
1829 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Eric Dumazet2edae082010-09-06 18:46:39 +00001830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 desc->opts2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832}
1833
Francois Romieuccdffb92008-07-26 14:26:06 +02001834static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835{
1836 struct rtl8169_private *tp = netdev_priv(dev);
1837 void __iomem *ioaddr = tp->mmio_addr;
1838 u32 status;
1839
1840 cmd->supported =
1841 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1842 cmd->port = PORT_FIBRE;
1843 cmd->transceiver = XCVR_INTERNAL;
1844
1845 status = RTL_R32(TBICSR);
1846 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1847 cmd->autoneg = !!(status & TBINwEnable);
1848
David Decotigny70739492011-04-27 18:32:40 +00001849 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001851
1852 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
Francois Romieuccdffb92008-07-26 14:26:06 +02001855static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856{
1857 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
Francois Romieuccdffb92008-07-26 14:26:06 +02001859 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860}
1861
1862static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1863{
1864 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001865 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Francois Romieuda78dbf2012-01-26 14:18:23 +01001867 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001868 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001869 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Francois Romieuccdffb92008-07-26 14:26:06 +02001871 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872}
1873
1874static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1875 void *p)
1876{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001877 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
Francois Romieu5b0384f2006-08-16 16:00:01 +02001879 if (regs->len > R8169_REGS_SIZE)
1880 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Francois Romieuda78dbf2012-01-26 14:18:23 +01001882 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001883 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001884 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885}
1886
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001887static u32 rtl8169_get_msglevel(struct net_device *dev)
1888{
1889 struct rtl8169_private *tp = netdev_priv(dev);
1890
1891 return tp->msg_enable;
1892}
1893
1894static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1895{
1896 struct rtl8169_private *tp = netdev_priv(dev);
1897
1898 tp->msg_enable = value;
1899}
1900
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001901static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1902 "tx_packets",
1903 "rx_packets",
1904 "tx_errors",
1905 "rx_errors",
1906 "rx_missed",
1907 "align_errors",
1908 "tx_single_collisions",
1909 "tx_multi_collisions",
1910 "unicast",
1911 "broadcast",
1912 "multicast",
1913 "tx_aborted",
1914 "tx_underrun",
1915};
1916
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001917static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001918{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001919 switch (sset) {
1920 case ETH_SS_STATS:
1921 return ARRAY_SIZE(rtl8169_gstrings);
1922 default:
1923 return -EOPNOTSUPP;
1924 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001925}
1926
Francois Romieuffc46952012-07-06 14:19:23 +02001927DECLARE_RTL_COND(rtl_counters_cond)
1928{
1929 void __iomem *ioaddr = tp->mmio_addr;
1930
1931 return RTL_R32(CounterAddrLow) & CounterDump;
1932}
1933
Ivan Vecera355423d2009-02-06 21:49:57 -08001934static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001935{
1936 struct rtl8169_private *tp = netdev_priv(dev);
1937 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001938 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001939 struct rtl8169_counters *counters;
1940 dma_addr_t paddr;
1941 u32 cmd;
1942
Ivan Vecera355423d2009-02-06 21:49:57 -08001943 /*
1944 * Some chips are unable to dump tally counters when the receiver
1945 * is disabled.
1946 */
1947 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1948 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001949
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001950 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001951 if (!counters)
1952 return;
1953
1954 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001955 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001956 RTL_W32(CounterAddrLow, cmd);
1957 RTL_W32(CounterAddrLow, cmd | CounterDump);
1958
Francois Romieuffc46952012-07-06 14:19:23 +02001959 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1960 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001961
1962 RTL_W32(CounterAddrLow, 0);
1963 RTL_W32(CounterAddrHigh, 0);
1964
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001965 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001966}
1967
Ivan Vecera355423d2009-02-06 21:49:57 -08001968static void rtl8169_get_ethtool_stats(struct net_device *dev,
1969 struct ethtool_stats *stats, u64 *data)
1970{
1971 struct rtl8169_private *tp = netdev_priv(dev);
1972
1973 ASSERT_RTNL();
1974
1975 rtl8169_update_counters(dev);
1976
1977 data[0] = le64_to_cpu(tp->counters.tx_packets);
1978 data[1] = le64_to_cpu(tp->counters.rx_packets);
1979 data[2] = le64_to_cpu(tp->counters.tx_errors);
1980 data[3] = le32_to_cpu(tp->counters.rx_errors);
1981 data[4] = le16_to_cpu(tp->counters.rx_missed);
1982 data[5] = le16_to_cpu(tp->counters.align_errors);
1983 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1984 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1985 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1986 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1987 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1988 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1989 data[12] = le16_to_cpu(tp->counters.tx_underun);
1990}
1991
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001992static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
1993{
1994 switch(stringset) {
1995 case ETH_SS_STATS:
1996 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
1997 break;
1998 }
1999}
2000
Jeff Garzik7282d492006-09-13 14:30:00 -04002001static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 .get_drvinfo = rtl8169_get_drvinfo,
2003 .get_regs_len = rtl8169_get_regs_len,
2004 .get_link = ethtool_op_get_link,
2005 .get_settings = rtl8169_get_settings,
2006 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002007 .get_msglevel = rtl8169_get_msglevel,
2008 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002010 .get_wol = rtl8169_get_wol,
2011 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002012 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002013 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002014 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002015 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016};
2017
Francois Romieu07d3f512007-02-21 22:40:46 +01002018static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002019 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020{
Francois Romieu5d320a22011-05-08 17:47:36 +02002021 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002022 /*
2023 * The driver currently handles the 8168Bf and the 8168Be identically
2024 * but they can be identified more specifically through the test below
2025 * if needed:
2026 *
2027 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002028 *
2029 * Same thing for the 8101Eb and the 8101Ec:
2030 *
2031 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002032 */
Francois Romieu37441002011-06-17 22:58:54 +02002033 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002035 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 int mac_version;
2037 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002038 /* 8168G family. */
2039 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2040 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2041
Hayes Wangc2218922011-09-06 16:55:18 +08002042 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002043 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002044 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2045 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2046
hayeswang01dc7fe2011-03-21 01:50:28 +00002047 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002048 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002049 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2050 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2051 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2052
Francois Romieu5b538df2008-07-20 16:22:45 +02002053 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002054 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2055 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002056 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002057
françois romieue6de30d2011-01-03 15:08:37 +00002058 /* 8168DP family. */
2059 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2060 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002061 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002062
Francois Romieuef808d52008-06-29 13:10:54 +02002063 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002064 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002065 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002066 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002067 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002068 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2069 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002070 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002071 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002072 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002073
2074 /* 8168B family. */
2075 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2076 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2077 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2078 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2079
2080 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002081 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2082 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002083 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002084 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002085 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2086 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2087 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002088 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2089 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2090 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2091 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2092 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2093 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002094 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002095 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002096 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002097 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2098 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002099 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2100 /* FIXME: where did these entries come from ? -- FR */
2101 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2102 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2103
2104 /* 8110 family. */
2105 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2106 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2107 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2108 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2109 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2110 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2111
Jean Delvaref21b75e2009-05-26 20:54:48 -07002112 /* Catch-all */
2113 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002114 };
2115 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 u32 reg;
2117
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002118 reg = RTL_R32(TxConfig);
2119 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 p++;
2121 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002122
2123 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2124 netif_notice(tp, probe, dev,
2125 "unknown MAC, using family default\n");
2126 tp->mac_version = default_version;
2127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128}
2129
2130static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2131{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002132 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133}
2134
Francois Romieu867763c2007-08-17 18:21:58 +02002135struct phy_reg {
2136 u16 reg;
2137 u16 val;
2138};
2139
françois romieu4da19632011-01-03 15:07:55 +00002140static void rtl_writephy_batch(struct rtl8169_private *tp,
2141 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002142{
2143 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002144 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002145 regs++;
2146 }
2147}
2148
françois romieubca03d52011-01-03 15:07:31 +00002149#define PHY_READ 0x00000000
2150#define PHY_DATA_OR 0x10000000
2151#define PHY_DATA_AND 0x20000000
2152#define PHY_BJMPN 0x30000000
2153#define PHY_READ_EFUSE 0x40000000
2154#define PHY_READ_MAC_BYTE 0x50000000
2155#define PHY_WRITE_MAC_BYTE 0x60000000
2156#define PHY_CLEAR_READCOUNT 0x70000000
2157#define PHY_WRITE 0x80000000
2158#define PHY_READCOUNT_EQ_SKIP 0x90000000
2159#define PHY_COMP_EQ_SKIPN 0xa0000000
2160#define PHY_COMP_NEQ_SKIPN 0xb0000000
2161#define PHY_WRITE_PREVIOUS 0xc0000000
2162#define PHY_SKIPN 0xd0000000
2163#define PHY_DELAY_MS 0xe0000000
2164#define PHY_WRITE_ERI_WORD 0xf0000000
2165
Hayes Wang960aee62011-06-18 11:37:48 +02002166struct fw_info {
2167 u32 magic;
2168 char version[RTL_VER_SIZE];
2169 __le32 fw_start;
2170 __le32 fw_len;
2171 u8 chksum;
2172} __packed;
2173
Francois Romieu1c361ef2011-06-17 17:16:24 +02002174#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2175
2176static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002177{
Francois Romieub6ffd972011-06-17 17:00:05 +02002178 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002179 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002180 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2181 char *version = rtl_fw->version;
2182 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002183
Francois Romieu1c361ef2011-06-17 17:16:24 +02002184 if (fw->size < FW_OPCODE_SIZE)
2185 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002186
2187 if (!fw_info->magic) {
2188 size_t i, size, start;
2189 u8 checksum = 0;
2190
2191 if (fw->size < sizeof(*fw_info))
2192 goto out;
2193
2194 for (i = 0; i < fw->size; i++)
2195 checksum += fw->data[i];
2196 if (checksum != 0)
2197 goto out;
2198
2199 start = le32_to_cpu(fw_info->fw_start);
2200 if (start > fw->size)
2201 goto out;
2202
2203 size = le32_to_cpu(fw_info->fw_len);
2204 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2205 goto out;
2206
2207 memcpy(version, fw_info->version, RTL_VER_SIZE);
2208
2209 pa->code = (__le32 *)(fw->data + start);
2210 pa->size = size;
2211 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002212 if (fw->size % FW_OPCODE_SIZE)
2213 goto out;
2214
2215 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2216
2217 pa->code = (__le32 *)fw->data;
2218 pa->size = fw->size / FW_OPCODE_SIZE;
2219 }
2220 version[RTL_VER_SIZE - 1] = 0;
2221
2222 rc = true;
2223out:
2224 return rc;
2225}
2226
Francois Romieufd112f22011-06-18 00:10:29 +02002227static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2228 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002229{
Francois Romieufd112f22011-06-18 00:10:29 +02002230 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002231 size_t index;
2232
Francois Romieu1c361ef2011-06-17 17:16:24 +02002233 for (index = 0; index < pa->size; index++) {
2234 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002235 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002236
hayeswang42b82dc2011-01-10 02:07:25 +00002237 switch(action & 0xf0000000) {
2238 case PHY_READ:
2239 case PHY_DATA_OR:
2240 case PHY_DATA_AND:
2241 case PHY_READ_EFUSE:
2242 case PHY_CLEAR_READCOUNT:
2243 case PHY_WRITE:
2244 case PHY_WRITE_PREVIOUS:
2245 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002246 break;
2247
hayeswang42b82dc2011-01-10 02:07:25 +00002248 case PHY_BJMPN:
2249 if (regno > index) {
Francois Romieufd112f22011-06-18 00:10:29 +02002250 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002251 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002252 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002253 }
2254 break;
2255 case PHY_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002256 if (index + 2 >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002257 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002258 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002259 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002260 }
2261 break;
2262 case PHY_COMP_EQ_SKIPN:
2263 case PHY_COMP_NEQ_SKIPN:
2264 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002265 if (index + 1 + regno >= 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
2272 case PHY_READ_MAC_BYTE:
2273 case PHY_WRITE_MAC_BYTE:
2274 case PHY_WRITE_ERI_WORD:
2275 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002276 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002277 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002278 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002279 }
2280 }
Francois Romieufd112f22011-06-18 00:10:29 +02002281 rc = true;
2282out:
2283 return rc;
2284}
françois romieubca03d52011-01-03 15:07:31 +00002285
Francois Romieufd112f22011-06-18 00:10:29 +02002286static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2287{
2288 struct net_device *dev = tp->dev;
2289 int rc = -EINVAL;
2290
2291 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2292 netif_err(tp, ifup, dev, "invalid firwmare\n");
2293 goto out;
2294 }
2295
2296 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2297 rc = 0;
2298out:
2299 return rc;
2300}
2301
2302static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2303{
2304 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2305 u32 predata, count;
2306 size_t index;
2307
2308 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002309
Francois Romieu1c361ef2011-06-17 17:16:24 +02002310 for (index = 0; index < pa->size; ) {
2311 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002312 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002313 u32 regno = (action & 0x0fff0000) >> 16;
2314
2315 if (!action)
2316 break;
françois romieubca03d52011-01-03 15:07:31 +00002317
2318 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002319 case PHY_READ:
2320 predata = rtl_readphy(tp, regno);
2321 count++;
2322 index++;
françois romieubca03d52011-01-03 15:07:31 +00002323 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002324 case PHY_DATA_OR:
2325 predata |= data;
2326 index++;
2327 break;
2328 case PHY_DATA_AND:
2329 predata &= data;
2330 index++;
2331 break;
2332 case PHY_BJMPN:
2333 index -= regno;
2334 break;
2335 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002336 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002337 index++;
2338 break;
2339 case PHY_CLEAR_READCOUNT:
2340 count = 0;
2341 index++;
2342 break;
2343 case PHY_WRITE:
2344 rtl_writephy(tp, regno, data);
2345 index++;
2346 break;
2347 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002348 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002349 break;
2350 case PHY_COMP_EQ_SKIPN:
2351 if (predata == data)
2352 index += regno;
2353 index++;
2354 break;
2355 case PHY_COMP_NEQ_SKIPN:
2356 if (predata != data)
2357 index += regno;
2358 index++;
2359 break;
2360 case PHY_WRITE_PREVIOUS:
2361 rtl_writephy(tp, regno, predata);
2362 index++;
2363 break;
2364 case PHY_SKIPN:
2365 index += regno + 1;
2366 break;
2367 case PHY_DELAY_MS:
2368 mdelay(data);
2369 index++;
2370 break;
2371
2372 case PHY_READ_MAC_BYTE:
2373 case PHY_WRITE_MAC_BYTE:
2374 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002375 default:
2376 BUG();
2377 }
2378 }
2379}
2380
françois romieuf1e02ed2011-01-13 13:07:53 +00002381static void rtl_release_firmware(struct rtl8169_private *tp)
2382{
Francois Romieub6ffd972011-06-17 17:00:05 +02002383 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2384 release_firmware(tp->rtl_fw->fw);
2385 kfree(tp->rtl_fw);
2386 }
2387 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002388}
2389
François Romieu953a12c2011-04-24 17:38:48 +02002390static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002391{
Francois Romieub6ffd972011-06-17 17:00:05 +02002392 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002393
2394 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
Francois Romieub6ffd972011-06-17 17:00:05 +02002395 if (!IS_ERR_OR_NULL(rtl_fw))
2396 rtl_phy_write_fw(tp, rtl_fw);
François Romieu953a12c2011-04-24 17:38:48 +02002397}
2398
2399static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2400{
2401 if (rtl_readphy(tp, reg) != val)
2402 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2403 else
2404 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002405}
2406
françois romieu4da19632011-01-03 15:07:55 +00002407static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002409 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002410 { 0x1f, 0x0001 },
2411 { 0x06, 0x006e },
2412 { 0x08, 0x0708 },
2413 { 0x15, 0x4000 },
2414 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
françois romieu0b9b5712009-08-10 19:44:56 +00002416 { 0x1f, 0x0001 },
2417 { 0x03, 0x00a1 },
2418 { 0x02, 0x0008 },
2419 { 0x01, 0x0120 },
2420 { 0x00, 0x1000 },
2421 { 0x04, 0x0800 },
2422 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
françois romieu0b9b5712009-08-10 19:44:56 +00002424 { 0x03, 0xff41 },
2425 { 0x02, 0xdf60 },
2426 { 0x01, 0x0140 },
2427 { 0x00, 0x0077 },
2428 { 0x04, 0x7800 },
2429 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
françois romieu0b9b5712009-08-10 19:44:56 +00002431 { 0x03, 0x802f },
2432 { 0x02, 0x4f02 },
2433 { 0x01, 0x0409 },
2434 { 0x00, 0xf0f9 },
2435 { 0x04, 0x9800 },
2436 { 0x04, 0x9000 },
2437
2438 { 0x03, 0xdf01 },
2439 { 0x02, 0xdf20 },
2440 { 0x01, 0xff95 },
2441 { 0x00, 0xba00 },
2442 { 0x04, 0xa800 },
2443 { 0x04, 0xa000 },
2444
2445 { 0x03, 0xff41 },
2446 { 0x02, 0xdf20 },
2447 { 0x01, 0x0140 },
2448 { 0x00, 0x00bb },
2449 { 0x04, 0xb800 },
2450 { 0x04, 0xb000 },
2451
2452 { 0x03, 0xdf41 },
2453 { 0x02, 0xdc60 },
2454 { 0x01, 0x6340 },
2455 { 0x00, 0x007d },
2456 { 0x04, 0xd800 },
2457 { 0x04, 0xd000 },
2458
2459 { 0x03, 0xdf01 },
2460 { 0x02, 0xdf20 },
2461 { 0x01, 0x100a },
2462 { 0x00, 0xa0ff },
2463 { 0x04, 0xf800 },
2464 { 0x04, 0xf000 },
2465
2466 { 0x1f, 0x0000 },
2467 { 0x0b, 0x0000 },
2468 { 0x00, 0x9200 }
2469 };
2470
françois romieu4da19632011-01-03 15:07:55 +00002471 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472}
2473
françois romieu4da19632011-01-03 15:07:55 +00002474static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002475{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002476 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002477 { 0x1f, 0x0002 },
2478 { 0x01, 0x90d0 },
2479 { 0x1f, 0x0000 }
2480 };
2481
françois romieu4da19632011-01-03 15:07:55 +00002482 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002483}
2484
françois romieu4da19632011-01-03 15:07:55 +00002485static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002486{
2487 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002488
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002489 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2490 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002491 return;
2492
françois romieu4da19632011-01-03 15:07:55 +00002493 rtl_writephy(tp, 0x1f, 0x0001);
2494 rtl_writephy(tp, 0x10, 0xf01b);
2495 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002496}
2497
françois romieu4da19632011-01-03 15:07:55 +00002498static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002499{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002500 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002501 { 0x1f, 0x0001 },
2502 { 0x04, 0x0000 },
2503 { 0x03, 0x00a1 },
2504 { 0x02, 0x0008 },
2505 { 0x01, 0x0120 },
2506 { 0x00, 0x1000 },
2507 { 0x04, 0x0800 },
2508 { 0x04, 0x9000 },
2509 { 0x03, 0x802f },
2510 { 0x02, 0x4f02 },
2511 { 0x01, 0x0409 },
2512 { 0x00, 0xf099 },
2513 { 0x04, 0x9800 },
2514 { 0x04, 0xa000 },
2515 { 0x03, 0xdf01 },
2516 { 0x02, 0xdf20 },
2517 { 0x01, 0xff95 },
2518 { 0x00, 0xba00 },
2519 { 0x04, 0xa800 },
2520 { 0x04, 0xf000 },
2521 { 0x03, 0xdf01 },
2522 { 0x02, 0xdf20 },
2523 { 0x01, 0x101a },
2524 { 0x00, 0xa0ff },
2525 { 0x04, 0xf800 },
2526 { 0x04, 0x0000 },
2527 { 0x1f, 0x0000 },
2528
2529 { 0x1f, 0x0001 },
2530 { 0x10, 0xf41b },
2531 { 0x14, 0xfb54 },
2532 { 0x18, 0xf5c7 },
2533 { 0x1f, 0x0000 },
2534
2535 { 0x1f, 0x0001 },
2536 { 0x17, 0x0cc0 },
2537 { 0x1f, 0x0000 }
2538 };
2539
françois romieu4da19632011-01-03 15:07:55 +00002540 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002541
françois romieu4da19632011-01-03 15:07:55 +00002542 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002543}
2544
françois romieu4da19632011-01-03 15:07:55 +00002545static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002546{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002547 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002548 { 0x1f, 0x0001 },
2549 { 0x04, 0x0000 },
2550 { 0x03, 0x00a1 },
2551 { 0x02, 0x0008 },
2552 { 0x01, 0x0120 },
2553 { 0x00, 0x1000 },
2554 { 0x04, 0x0800 },
2555 { 0x04, 0x9000 },
2556 { 0x03, 0x802f },
2557 { 0x02, 0x4f02 },
2558 { 0x01, 0x0409 },
2559 { 0x00, 0xf099 },
2560 { 0x04, 0x9800 },
2561 { 0x04, 0xa000 },
2562 { 0x03, 0xdf01 },
2563 { 0x02, 0xdf20 },
2564 { 0x01, 0xff95 },
2565 { 0x00, 0xba00 },
2566 { 0x04, 0xa800 },
2567 { 0x04, 0xf000 },
2568 { 0x03, 0xdf01 },
2569 { 0x02, 0xdf20 },
2570 { 0x01, 0x101a },
2571 { 0x00, 0xa0ff },
2572 { 0x04, 0xf800 },
2573 { 0x04, 0x0000 },
2574 { 0x1f, 0x0000 },
2575
2576 { 0x1f, 0x0001 },
2577 { 0x0b, 0x8480 },
2578 { 0x1f, 0x0000 },
2579
2580 { 0x1f, 0x0001 },
2581 { 0x18, 0x67c7 },
2582 { 0x04, 0x2000 },
2583 { 0x03, 0x002f },
2584 { 0x02, 0x4360 },
2585 { 0x01, 0x0109 },
2586 { 0x00, 0x3022 },
2587 { 0x04, 0x2800 },
2588 { 0x1f, 0x0000 },
2589
2590 { 0x1f, 0x0001 },
2591 { 0x17, 0x0cc0 },
2592 { 0x1f, 0x0000 }
2593 };
2594
françois romieu4da19632011-01-03 15:07:55 +00002595 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002596}
2597
françois romieu4da19632011-01-03 15:07:55 +00002598static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002599{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002600 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002601 { 0x10, 0xf41b },
2602 { 0x1f, 0x0000 }
2603 };
2604
françois romieu4da19632011-01-03 15:07:55 +00002605 rtl_writephy(tp, 0x1f, 0x0001);
2606 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002607
françois romieu4da19632011-01-03 15:07:55 +00002608 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002609}
2610
françois romieu4da19632011-01-03 15:07:55 +00002611static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002612{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002613 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002614 { 0x1f, 0x0001 },
2615 { 0x10, 0xf41b },
2616 { 0x1f, 0x0000 }
2617 };
2618
françois romieu4da19632011-01-03 15:07:55 +00002619 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002620}
2621
françois romieu4da19632011-01-03 15:07:55 +00002622static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002623{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002624 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002625 { 0x1f, 0x0000 },
2626 { 0x1d, 0x0f00 },
2627 { 0x1f, 0x0002 },
2628 { 0x0c, 0x1ec8 },
2629 { 0x1f, 0x0000 }
2630 };
2631
françois romieu4da19632011-01-03 15:07:55 +00002632 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002633}
2634
françois romieu4da19632011-01-03 15:07:55 +00002635static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002636{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002637 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002638 { 0x1f, 0x0001 },
2639 { 0x1d, 0x3d98 },
2640 { 0x1f, 0x0000 }
2641 };
2642
françois romieu4da19632011-01-03 15:07:55 +00002643 rtl_writephy(tp, 0x1f, 0x0000);
2644 rtl_patchphy(tp, 0x14, 1 << 5);
2645 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002646
françois romieu4da19632011-01-03 15:07:55 +00002647 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002648}
2649
françois romieu4da19632011-01-03 15:07:55 +00002650static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002651{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002652 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002653 { 0x1f, 0x0001 },
2654 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002655 { 0x1f, 0x0002 },
2656 { 0x00, 0x88d4 },
2657 { 0x01, 0x82b1 },
2658 { 0x03, 0x7002 },
2659 { 0x08, 0x9e30 },
2660 { 0x09, 0x01f0 },
2661 { 0x0a, 0x5500 },
2662 { 0x0c, 0x00c8 },
2663 { 0x1f, 0x0003 },
2664 { 0x12, 0xc096 },
2665 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002666 { 0x1f, 0x0000 },
2667 { 0x1f, 0x0000 },
2668 { 0x09, 0x2000 },
2669 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002670 };
2671
françois romieu4da19632011-01-03 15:07:55 +00002672 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002673
françois romieu4da19632011-01-03 15:07:55 +00002674 rtl_patchphy(tp, 0x14, 1 << 5);
2675 rtl_patchphy(tp, 0x0d, 1 << 5);
2676 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002677}
2678
françois romieu4da19632011-01-03 15:07:55 +00002679static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002680{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002681 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002682 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002683 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002684 { 0x03, 0x802f },
2685 { 0x02, 0x4f02 },
2686 { 0x01, 0x0409 },
2687 { 0x00, 0xf099 },
2688 { 0x04, 0x9800 },
2689 { 0x04, 0x9000 },
2690 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002691 { 0x1f, 0x0002 },
2692 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002693 { 0x06, 0x0761 },
2694 { 0x1f, 0x0003 },
2695 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002696 { 0x1f, 0x0000 }
2697 };
2698
françois romieu4da19632011-01-03 15:07:55 +00002699 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002700
françois romieu4da19632011-01-03 15:07:55 +00002701 rtl_patchphy(tp, 0x16, 1 << 0);
2702 rtl_patchphy(tp, 0x14, 1 << 5);
2703 rtl_patchphy(tp, 0x0d, 1 << 5);
2704 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002705}
2706
françois romieu4da19632011-01-03 15:07:55 +00002707static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002708{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002709 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002710 { 0x1f, 0x0001 },
2711 { 0x12, 0x2300 },
2712 { 0x1d, 0x3d98 },
2713 { 0x1f, 0x0002 },
2714 { 0x0c, 0x7eb8 },
2715 { 0x06, 0x5461 },
2716 { 0x1f, 0x0003 },
2717 { 0x16, 0x0f0a },
2718 { 0x1f, 0x0000 }
2719 };
2720
françois romieu4da19632011-01-03 15:07:55 +00002721 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002722
françois romieu4da19632011-01-03 15:07:55 +00002723 rtl_patchphy(tp, 0x16, 1 << 0);
2724 rtl_patchphy(tp, 0x14, 1 << 5);
2725 rtl_patchphy(tp, 0x0d, 1 << 5);
2726 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002727}
2728
françois romieu4da19632011-01-03 15:07:55 +00002729static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002730{
françois romieu4da19632011-01-03 15:07:55 +00002731 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002732}
2733
françois romieubca03d52011-01-03 15:07:31 +00002734static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002735{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002736 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002737 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002738 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002739 { 0x06, 0x4064 },
2740 { 0x07, 0x2863 },
2741 { 0x08, 0x059c },
2742 { 0x09, 0x26b4 },
2743 { 0x0a, 0x6a19 },
2744 { 0x0b, 0xdcc8 },
2745 { 0x10, 0xf06d },
2746 { 0x14, 0x7f68 },
2747 { 0x18, 0x7fd9 },
2748 { 0x1c, 0xf0ff },
2749 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002750 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002751 { 0x12, 0xf49f },
2752 { 0x13, 0x070b },
2753 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002754 { 0x14, 0x94c0 },
2755
2756 /*
2757 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002758 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002759 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002760 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002761 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002762 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002763 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002764 { 0x06, 0x5561 },
2765
2766 /*
2767 * Can not link to 1Gbps with bad cable
2768 * Decrease SNR threshold form 21.07dB to 19.04dB
2769 */
2770 { 0x1f, 0x0001 },
2771 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002772
2773 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002774 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002775 };
2776
françois romieu4da19632011-01-03 15:07:55 +00002777 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002778
françois romieubca03d52011-01-03 15:07:31 +00002779 /*
2780 * Rx Error Issue
2781 * Fine Tune Switching regulator parameter
2782 */
françois romieu4da19632011-01-03 15:07:55 +00002783 rtl_writephy(tp, 0x1f, 0x0002);
2784 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2785 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002786
Francois Romieufdf6fc02012-07-06 22:40:38 +02002787 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002788 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002789 { 0x1f, 0x0002 },
2790 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002791 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002792 { 0x05, 0x8330 },
2793 { 0x06, 0x669a },
2794 { 0x1f, 0x0002 }
2795 };
2796 int val;
2797
françois romieu4da19632011-01-03 15:07:55 +00002798 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002799
françois romieu4da19632011-01-03 15:07:55 +00002800 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002801
2802 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002803 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002804 0x0065, 0x0066, 0x0067, 0x0068,
2805 0x0069, 0x006a, 0x006b, 0x006c
2806 };
2807 int i;
2808
françois romieu4da19632011-01-03 15:07:55 +00002809 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002810
2811 val &= 0xff00;
2812 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002813 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002814 }
2815 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002816 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002817 { 0x1f, 0x0002 },
2818 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002819 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002820 { 0x05, 0x8330 },
2821 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002822 };
2823
françois romieu4da19632011-01-03 15:07:55 +00002824 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002825 }
2826
françois romieubca03d52011-01-03 15:07:31 +00002827 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002828 rtl_writephy(tp, 0x1f, 0x0002);
2829 rtl_patchphy(tp, 0x0d, 0x0300);
2830 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002831
françois romieubca03d52011-01-03 15:07:31 +00002832 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002833 rtl_writephy(tp, 0x1f, 0x0002);
2834 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2835 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002836
françois romieu4da19632011-01-03 15:07:55 +00002837 rtl_writephy(tp, 0x1f, 0x0005);
2838 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002839
2840 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002841
françois romieu4da19632011-01-03 15:07:55 +00002842 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002843}
2844
françois romieubca03d52011-01-03 15:07:31 +00002845static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002846{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002847 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002848 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002849 { 0x1f, 0x0001 },
2850 { 0x06, 0x4064 },
2851 { 0x07, 0x2863 },
2852 { 0x08, 0x059c },
2853 { 0x09, 0x26b4 },
2854 { 0x0a, 0x6a19 },
2855 { 0x0b, 0xdcc8 },
2856 { 0x10, 0xf06d },
2857 { 0x14, 0x7f68 },
2858 { 0x18, 0x7fd9 },
2859 { 0x1c, 0xf0ff },
2860 { 0x1d, 0x3d9c },
2861 { 0x1f, 0x0003 },
2862 { 0x12, 0xf49f },
2863 { 0x13, 0x070b },
2864 { 0x1a, 0x05ad },
2865 { 0x14, 0x94c0 },
2866
françois romieubca03d52011-01-03 15:07:31 +00002867 /*
2868 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002869 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002870 */
françois romieudaf9df62009-10-07 12:44:20 +00002871 { 0x1f, 0x0002 },
2872 { 0x06, 0x5561 },
2873 { 0x1f, 0x0005 },
2874 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002875 { 0x06, 0x5561 },
2876
2877 /*
2878 * Can not link to 1Gbps with bad cable
2879 * Decrease SNR threshold form 21.07dB to 19.04dB
2880 */
2881 { 0x1f, 0x0001 },
2882 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002883
2884 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002885 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002886 };
2887
françois romieu4da19632011-01-03 15:07:55 +00002888 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002889
Francois Romieufdf6fc02012-07-06 22:40:38 +02002890 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002891 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002892 { 0x1f, 0x0002 },
2893 { 0x05, 0x669a },
2894 { 0x1f, 0x0005 },
2895 { 0x05, 0x8330 },
2896 { 0x06, 0x669a },
2897
2898 { 0x1f, 0x0002 }
2899 };
2900 int val;
2901
françois romieu4da19632011-01-03 15:07:55 +00002902 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002903
françois romieu4da19632011-01-03 15:07:55 +00002904 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002905 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002906 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002907 0x0065, 0x0066, 0x0067, 0x0068,
2908 0x0069, 0x006a, 0x006b, 0x006c
2909 };
2910 int i;
2911
françois romieu4da19632011-01-03 15:07:55 +00002912 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002913
2914 val &= 0xff00;
2915 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002916 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002917 }
2918 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002919 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002920 { 0x1f, 0x0002 },
2921 { 0x05, 0x2642 },
2922 { 0x1f, 0x0005 },
2923 { 0x05, 0x8330 },
2924 { 0x06, 0x2642 }
2925 };
2926
françois romieu4da19632011-01-03 15:07:55 +00002927 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002928 }
2929
françois romieubca03d52011-01-03 15:07:31 +00002930 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002931 rtl_writephy(tp, 0x1f, 0x0002);
2932 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2933 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002934
françois romieubca03d52011-01-03 15:07:31 +00002935 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002936 rtl_writephy(tp, 0x1f, 0x0002);
2937 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002938
françois romieu4da19632011-01-03 15:07:55 +00002939 rtl_writephy(tp, 0x1f, 0x0005);
2940 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002941
2942 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002943
françois romieu4da19632011-01-03 15:07:55 +00002944 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002945}
2946
françois romieu4da19632011-01-03 15:07:55 +00002947static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002948{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002949 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002950 { 0x1f, 0x0002 },
2951 { 0x10, 0x0008 },
2952 { 0x0d, 0x006c },
2953
2954 { 0x1f, 0x0000 },
2955 { 0x0d, 0xf880 },
2956
2957 { 0x1f, 0x0001 },
2958 { 0x17, 0x0cc0 },
2959
2960 { 0x1f, 0x0001 },
2961 { 0x0b, 0xa4d8 },
2962 { 0x09, 0x281c },
2963 { 0x07, 0x2883 },
2964 { 0x0a, 0x6b35 },
2965 { 0x1d, 0x3da4 },
2966 { 0x1c, 0xeffd },
2967 { 0x14, 0x7f52 },
2968 { 0x18, 0x7fc6 },
2969 { 0x08, 0x0601 },
2970 { 0x06, 0x4063 },
2971 { 0x10, 0xf074 },
2972 { 0x1f, 0x0003 },
2973 { 0x13, 0x0789 },
2974 { 0x12, 0xf4bd },
2975 { 0x1a, 0x04fd },
2976 { 0x14, 0x84b0 },
2977 { 0x1f, 0x0000 },
2978 { 0x00, 0x9200 },
2979
2980 { 0x1f, 0x0005 },
2981 { 0x01, 0x0340 },
2982 { 0x1f, 0x0001 },
2983 { 0x04, 0x4000 },
2984 { 0x03, 0x1d21 },
2985 { 0x02, 0x0c32 },
2986 { 0x01, 0x0200 },
2987 { 0x00, 0x5554 },
2988 { 0x04, 0x4800 },
2989 { 0x04, 0x4000 },
2990 { 0x04, 0xf000 },
2991 { 0x03, 0xdf01 },
2992 { 0x02, 0xdf20 },
2993 { 0x01, 0x101a },
2994 { 0x00, 0xa0ff },
2995 { 0x04, 0xf800 },
2996 { 0x04, 0xf000 },
2997 { 0x1f, 0x0000 },
2998
2999 { 0x1f, 0x0007 },
3000 { 0x1e, 0x0023 },
3001 { 0x16, 0x0000 },
3002 { 0x1f, 0x0000 }
3003 };
3004
françois romieu4da19632011-01-03 15:07:55 +00003005 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02003006}
3007
françois romieue6de30d2011-01-03 15:08:37 +00003008static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3009{
3010 static const struct phy_reg phy_reg_init[] = {
3011 { 0x1f, 0x0001 },
3012 { 0x17, 0x0cc0 },
3013
3014 { 0x1f, 0x0007 },
3015 { 0x1e, 0x002d },
3016 { 0x18, 0x0040 },
3017 { 0x1f, 0x0000 }
3018 };
3019
3020 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3021 rtl_patchphy(tp, 0x0d, 1 << 5);
3022}
3023
Hayes Wang70090422011-07-06 15:58:06 +08003024static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003025{
3026 static const struct phy_reg phy_reg_init[] = {
3027 /* Enable Delay cap */
3028 { 0x1f, 0x0005 },
3029 { 0x05, 0x8b80 },
3030 { 0x06, 0xc896 },
3031 { 0x1f, 0x0000 },
3032
3033 /* Channel estimation fine tune */
3034 { 0x1f, 0x0001 },
3035 { 0x0b, 0x6c20 },
3036 { 0x07, 0x2872 },
3037 { 0x1c, 0xefff },
3038 { 0x1f, 0x0003 },
3039 { 0x14, 0x6420 },
3040 { 0x1f, 0x0000 },
3041
3042 /* Update PFM & 10M TX idle timer */
3043 { 0x1f, 0x0007 },
3044 { 0x1e, 0x002f },
3045 { 0x15, 0x1919 },
3046 { 0x1f, 0x0000 },
3047
3048 { 0x1f, 0x0007 },
3049 { 0x1e, 0x00ac },
3050 { 0x18, 0x0006 },
3051 { 0x1f, 0x0000 }
3052 };
3053
Francois Romieu15ecd032011-04-27 13:52:22 -07003054 rtl_apply_firmware(tp);
3055
hayeswang01dc7fe2011-03-21 01:50:28 +00003056 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3057
3058 /* DCO enable for 10M IDLE Power */
3059 rtl_writephy(tp, 0x1f, 0x0007);
3060 rtl_writephy(tp, 0x1e, 0x0023);
3061 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3062 rtl_writephy(tp, 0x1f, 0x0000);
3063
3064 /* For impedance matching */
3065 rtl_writephy(tp, 0x1f, 0x0002);
3066 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003067 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003068
3069 /* PHY auto speed down */
3070 rtl_writephy(tp, 0x1f, 0x0007);
3071 rtl_writephy(tp, 0x1e, 0x002d);
3072 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3073 rtl_writephy(tp, 0x1f, 0x0000);
3074 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3075
3076 rtl_writephy(tp, 0x1f, 0x0005);
3077 rtl_writephy(tp, 0x05, 0x8b86);
3078 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3079 rtl_writephy(tp, 0x1f, 0x0000);
3080
3081 rtl_writephy(tp, 0x1f, 0x0005);
3082 rtl_writephy(tp, 0x05, 0x8b85);
3083 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3084 rtl_writephy(tp, 0x1f, 0x0007);
3085 rtl_writephy(tp, 0x1e, 0x0020);
3086 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3087 rtl_writephy(tp, 0x1f, 0x0006);
3088 rtl_writephy(tp, 0x00, 0x5a00);
3089 rtl_writephy(tp, 0x1f, 0x0000);
3090 rtl_writephy(tp, 0x0d, 0x0007);
3091 rtl_writephy(tp, 0x0e, 0x003c);
3092 rtl_writephy(tp, 0x0d, 0x4007);
3093 rtl_writephy(tp, 0x0e, 0x0000);
3094 rtl_writephy(tp, 0x0d, 0x0000);
3095}
3096
Hayes Wang70090422011-07-06 15:58:06 +08003097static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3098{
3099 static const struct phy_reg phy_reg_init[] = {
3100 /* Enable Delay cap */
3101 { 0x1f, 0x0004 },
3102 { 0x1f, 0x0007 },
3103 { 0x1e, 0x00ac },
3104 { 0x18, 0x0006 },
3105 { 0x1f, 0x0002 },
3106 { 0x1f, 0x0000 },
3107 { 0x1f, 0x0000 },
3108
3109 /* Channel estimation fine tune */
3110 { 0x1f, 0x0003 },
3111 { 0x09, 0xa20f },
3112 { 0x1f, 0x0000 },
3113 { 0x1f, 0x0000 },
3114
3115 /* Green Setting */
3116 { 0x1f, 0x0005 },
3117 { 0x05, 0x8b5b },
3118 { 0x06, 0x9222 },
3119 { 0x05, 0x8b6d },
3120 { 0x06, 0x8000 },
3121 { 0x05, 0x8b76 },
3122 { 0x06, 0x8000 },
3123 { 0x1f, 0x0000 }
3124 };
3125
3126 rtl_apply_firmware(tp);
3127
3128 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3129
3130 /* For 4-corner performance improve */
3131 rtl_writephy(tp, 0x1f, 0x0005);
3132 rtl_writephy(tp, 0x05, 0x8b80);
3133 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3134 rtl_writephy(tp, 0x1f, 0x0000);
3135
3136 /* PHY auto speed down */
3137 rtl_writephy(tp, 0x1f, 0x0004);
3138 rtl_writephy(tp, 0x1f, 0x0007);
3139 rtl_writephy(tp, 0x1e, 0x002d);
3140 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3141 rtl_writephy(tp, 0x1f, 0x0002);
3142 rtl_writephy(tp, 0x1f, 0x0000);
3143 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3144
3145 /* improve 10M EEE waveform */
3146 rtl_writephy(tp, 0x1f, 0x0005);
3147 rtl_writephy(tp, 0x05, 0x8b86);
3148 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3149 rtl_writephy(tp, 0x1f, 0x0000);
3150
3151 /* Improve 2-pair detection performance */
3152 rtl_writephy(tp, 0x1f, 0x0005);
3153 rtl_writephy(tp, 0x05, 0x8b85);
3154 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3155 rtl_writephy(tp, 0x1f, 0x0000);
3156
3157 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003158 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003159 rtl_writephy(tp, 0x1f, 0x0005);
3160 rtl_writephy(tp, 0x05, 0x8b85);
3161 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3162 rtl_writephy(tp, 0x1f, 0x0004);
3163 rtl_writephy(tp, 0x1f, 0x0007);
3164 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003165 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003166 rtl_writephy(tp, 0x1f, 0x0002);
3167 rtl_writephy(tp, 0x1f, 0x0000);
3168 rtl_writephy(tp, 0x0d, 0x0007);
3169 rtl_writephy(tp, 0x0e, 0x003c);
3170 rtl_writephy(tp, 0x0d, 0x4007);
3171 rtl_writephy(tp, 0x0e, 0x0000);
3172 rtl_writephy(tp, 0x0d, 0x0000);
3173
3174 /* Green feature */
3175 rtl_writephy(tp, 0x1f, 0x0003);
3176 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3177 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3178 rtl_writephy(tp, 0x1f, 0x0000);
3179}
3180
Hayes Wang5f886e02012-03-30 14:33:03 +08003181static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3182{
3183 /* For 4-corner performance improve */
3184 rtl_writephy(tp, 0x1f, 0x0005);
3185 rtl_writephy(tp, 0x05, 0x8b80);
3186 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3187 rtl_writephy(tp, 0x1f, 0x0000);
3188
3189 /* PHY auto speed down */
3190 rtl_writephy(tp, 0x1f, 0x0007);
3191 rtl_writephy(tp, 0x1e, 0x002d);
3192 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3193 rtl_writephy(tp, 0x1f, 0x0000);
3194 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3195
3196 /* Improve 10M EEE waveform */
3197 rtl_writephy(tp, 0x1f, 0x0005);
3198 rtl_writephy(tp, 0x05, 0x8b86);
3199 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3200 rtl_writephy(tp, 0x1f, 0x0000);
3201}
3202
Hayes Wangc2218922011-09-06 16:55:18 +08003203static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3204{
3205 static const struct phy_reg phy_reg_init[] = {
3206 /* Channel estimation fine tune */
3207 { 0x1f, 0x0003 },
3208 { 0x09, 0xa20f },
3209 { 0x1f, 0x0000 },
3210
3211 /* Modify green table for giga & fnet */
3212 { 0x1f, 0x0005 },
3213 { 0x05, 0x8b55 },
3214 { 0x06, 0x0000 },
3215 { 0x05, 0x8b5e },
3216 { 0x06, 0x0000 },
3217 { 0x05, 0x8b67 },
3218 { 0x06, 0x0000 },
3219 { 0x05, 0x8b70 },
3220 { 0x06, 0x0000 },
3221 { 0x1f, 0x0000 },
3222 { 0x1f, 0x0007 },
3223 { 0x1e, 0x0078 },
3224 { 0x17, 0x0000 },
3225 { 0x19, 0x00fb },
3226 { 0x1f, 0x0000 },
3227
3228 /* Modify green table for 10M */
3229 { 0x1f, 0x0005 },
3230 { 0x05, 0x8b79 },
3231 { 0x06, 0xaa00 },
3232 { 0x1f, 0x0000 },
3233
3234 /* Disable hiimpedance detection (RTCT) */
3235 { 0x1f, 0x0003 },
3236 { 0x01, 0x328a },
3237 { 0x1f, 0x0000 }
3238 };
3239
3240 rtl_apply_firmware(tp);
3241
3242 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3243
Hayes Wang5f886e02012-03-30 14:33:03 +08003244 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003245
3246 /* Improve 2-pair detection performance */
3247 rtl_writephy(tp, 0x1f, 0x0005);
3248 rtl_writephy(tp, 0x05, 0x8b85);
3249 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3250 rtl_writephy(tp, 0x1f, 0x0000);
3251}
3252
3253static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3254{
3255 rtl_apply_firmware(tp);
3256
Hayes Wang5f886e02012-03-30 14:33:03 +08003257 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003258}
3259
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003260static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3261{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003262 static const struct phy_reg phy_reg_init[] = {
3263 /* Channel estimation fine tune */
3264 { 0x1f, 0x0003 },
3265 { 0x09, 0xa20f },
3266 { 0x1f, 0x0000 },
3267
3268 /* Modify green table for giga & fnet */
3269 { 0x1f, 0x0005 },
3270 { 0x05, 0x8b55 },
3271 { 0x06, 0x0000 },
3272 { 0x05, 0x8b5e },
3273 { 0x06, 0x0000 },
3274 { 0x05, 0x8b67 },
3275 { 0x06, 0x0000 },
3276 { 0x05, 0x8b70 },
3277 { 0x06, 0x0000 },
3278 { 0x1f, 0x0000 },
3279 { 0x1f, 0x0007 },
3280 { 0x1e, 0x0078 },
3281 { 0x17, 0x0000 },
3282 { 0x19, 0x00aa },
3283 { 0x1f, 0x0000 },
3284
3285 /* Modify green table for 10M */
3286 { 0x1f, 0x0005 },
3287 { 0x05, 0x8b79 },
3288 { 0x06, 0xaa00 },
3289 { 0x1f, 0x0000 },
3290
3291 /* Disable hiimpedance detection (RTCT) */
3292 { 0x1f, 0x0003 },
3293 { 0x01, 0x328a },
3294 { 0x1f, 0x0000 }
3295 };
3296
3297
3298 rtl_apply_firmware(tp);
3299
3300 rtl8168f_hw_phy_config(tp);
3301
3302 /* Improve 2-pair detection performance */
3303 rtl_writephy(tp, 0x1f, 0x0005);
3304 rtl_writephy(tp, 0x05, 0x8b85);
3305 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3306 rtl_writephy(tp, 0x1f, 0x0000);
3307
3308 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3309
3310 /* Modify green table for giga */
3311 rtl_writephy(tp, 0x1f, 0x0005);
3312 rtl_writephy(tp, 0x05, 0x8b54);
3313 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3314 rtl_writephy(tp, 0x05, 0x8b5d);
3315 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3316 rtl_writephy(tp, 0x05, 0x8a7c);
3317 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3318 rtl_writephy(tp, 0x05, 0x8a7f);
3319 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3320 rtl_writephy(tp, 0x05, 0x8a82);
3321 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3322 rtl_writephy(tp, 0x05, 0x8a85);
3323 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3324 rtl_writephy(tp, 0x05, 0x8a88);
3325 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3326 rtl_writephy(tp, 0x1f, 0x0000);
3327
3328 /* uc same-seed solution */
3329 rtl_writephy(tp, 0x1f, 0x0005);
3330 rtl_writephy(tp, 0x05, 0x8b85);
3331 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3332 rtl_writephy(tp, 0x1f, 0x0000);
3333
3334 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003335 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003336 rtl_writephy(tp, 0x1f, 0x0005);
3337 rtl_writephy(tp, 0x05, 0x8b85);
3338 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3339 rtl_writephy(tp, 0x1f, 0x0004);
3340 rtl_writephy(tp, 0x1f, 0x0007);
3341 rtl_writephy(tp, 0x1e, 0x0020);
3342 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3343 rtl_writephy(tp, 0x1f, 0x0000);
3344 rtl_writephy(tp, 0x0d, 0x0007);
3345 rtl_writephy(tp, 0x0e, 0x003c);
3346 rtl_writephy(tp, 0x0d, 0x4007);
3347 rtl_writephy(tp, 0x0e, 0x0000);
3348 rtl_writephy(tp, 0x0d, 0x0000);
3349
3350 /* Green feature */
3351 rtl_writephy(tp, 0x1f, 0x0003);
3352 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3353 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3354 rtl_writephy(tp, 0x1f, 0x0000);
3355}
3356
Hayes Wangc5583862012-07-02 17:23:22 +08003357static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3358{
3359 static const u16 mac_ocp_patch[] = {
3360 0xe008, 0xe01b, 0xe01d, 0xe01f,
3361 0xe021, 0xe023, 0xe025, 0xe027,
3362 0x49d2, 0xf10d, 0x766c, 0x49e2,
3363 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3364
3365 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3366 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3367 0xbe00, 0xb416, 0x0076, 0xe86c,
3368 0xc602, 0xbe00, 0x0000, 0xc602,
3369
3370 0xbe00, 0x0000, 0xc602, 0xbe00,
3371 0x0000, 0xc602, 0xbe00, 0x0000,
3372 0xc602, 0xbe00, 0x0000, 0xc602,
3373 0xbe00, 0x0000, 0xc602, 0xbe00,
3374
3375 0x0000, 0x0000, 0x0000, 0x0000
3376 };
3377 u32 i;
3378
3379 /* Patch code for GPHY reset */
3380 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3381 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3382 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3383 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3384
3385 rtl_apply_firmware(tp);
3386
3387 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3388 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3389 else
3390 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3391
3392 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3393 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3394 else
3395 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3396
3397 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3398 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3399
3400 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3401 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3402
3403 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3404}
3405
françois romieu4da19632011-01-03 15:07:55 +00003406static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003407{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003408 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003409 { 0x1f, 0x0003 },
3410 { 0x08, 0x441d },
3411 { 0x01, 0x9100 },
3412 { 0x1f, 0x0000 }
3413 };
3414
françois romieu4da19632011-01-03 15:07:55 +00003415 rtl_writephy(tp, 0x1f, 0x0000);
3416 rtl_patchphy(tp, 0x11, 1 << 12);
3417 rtl_patchphy(tp, 0x19, 1 << 13);
3418 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003419
françois romieu4da19632011-01-03 15:07:55 +00003420 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003421}
3422
Hayes Wang5a5e4442011-02-22 17:26:21 +08003423static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3424{
3425 static const struct phy_reg phy_reg_init[] = {
3426 { 0x1f, 0x0005 },
3427 { 0x1a, 0x0000 },
3428 { 0x1f, 0x0000 },
3429
3430 { 0x1f, 0x0004 },
3431 { 0x1c, 0x0000 },
3432 { 0x1f, 0x0000 },
3433
3434 { 0x1f, 0x0001 },
3435 { 0x15, 0x7701 },
3436 { 0x1f, 0x0000 }
3437 };
3438
3439 /* Disable ALDPS before ram code */
3440 rtl_writephy(tp, 0x1f, 0x0000);
3441 rtl_writephy(tp, 0x18, 0x0310);
3442 msleep(100);
3443
François Romieu953a12c2011-04-24 17:38:48 +02003444 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003445
3446 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3447}
3448
Hayes Wang7e18dca2012-03-30 14:33:02 +08003449static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3450{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003451 /* Disable ALDPS before setting firmware */
3452 rtl_writephy(tp, 0x1f, 0x0000);
3453 rtl_writephy(tp, 0x18, 0x0310);
3454 msleep(20);
3455
3456 rtl_apply_firmware(tp);
3457
3458 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003459 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003460 rtl_writephy(tp, 0x1f, 0x0004);
3461 rtl_writephy(tp, 0x10, 0x401f);
3462 rtl_writephy(tp, 0x19, 0x7030);
3463 rtl_writephy(tp, 0x1f, 0x0000);
3464}
3465
Hayes Wang5598bfe2012-07-02 17:23:21 +08003466static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3467{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003468 static const struct phy_reg phy_reg_init[] = {
3469 { 0x1f, 0x0004 },
3470 { 0x10, 0xc07f },
3471 { 0x19, 0x7030 },
3472 { 0x1f, 0x0000 }
3473 };
3474
3475 /* Disable ALDPS before ram code */
3476 rtl_writephy(tp, 0x1f, 0x0000);
3477 rtl_writephy(tp, 0x18, 0x0310);
3478 msleep(100);
3479
3480 rtl_apply_firmware(tp);
3481
Francois Romieufdf6fc02012-07-06 22:40:38 +02003482 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003483 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3484
Francois Romieufdf6fc02012-07-06 22:40:38 +02003485 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003486}
3487
Francois Romieu5615d9f2007-08-17 17:50:46 +02003488static void rtl_hw_phy_config(struct net_device *dev)
3489{
3490 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003491
3492 rtl8169_print_mac_version(tp);
3493
3494 switch (tp->mac_version) {
3495 case RTL_GIGA_MAC_VER_01:
3496 break;
3497 case RTL_GIGA_MAC_VER_02:
3498 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003499 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003500 break;
3501 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003502 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003503 break;
françois romieu2e9558562009-08-10 19:44:19 +00003504 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003505 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003506 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003507 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003508 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003509 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003510 case RTL_GIGA_MAC_VER_07:
3511 case RTL_GIGA_MAC_VER_08:
3512 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003513 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003514 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003515 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003516 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003517 break;
3518 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003519 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003520 break;
3521 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003522 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003523 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003524 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003525 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003526 break;
3527 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003528 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003529 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003530 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003531 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003532 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003533 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003534 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003535 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003536 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003537 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003538 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003539 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003540 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003541 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003542 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003543 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003544 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003545 break;
3546 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003547 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003548 break;
3549 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003550 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003551 break;
françois romieue6de30d2011-01-03 15:08:37 +00003552 case RTL_GIGA_MAC_VER_28:
3553 rtl8168d_4_hw_phy_config(tp);
3554 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003555 case RTL_GIGA_MAC_VER_29:
3556 case RTL_GIGA_MAC_VER_30:
3557 rtl8105e_hw_phy_config(tp);
3558 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003559 case RTL_GIGA_MAC_VER_31:
3560 /* None. */
3561 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003562 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003563 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003564 rtl8168e_1_hw_phy_config(tp);
3565 break;
3566 case RTL_GIGA_MAC_VER_34:
3567 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003568 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003569 case RTL_GIGA_MAC_VER_35:
3570 rtl8168f_1_hw_phy_config(tp);
3571 break;
3572 case RTL_GIGA_MAC_VER_36:
3573 rtl8168f_2_hw_phy_config(tp);
3574 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003575
Hayes Wang7e18dca2012-03-30 14:33:02 +08003576 case RTL_GIGA_MAC_VER_37:
3577 rtl8402_hw_phy_config(tp);
3578 break;
3579
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003580 case RTL_GIGA_MAC_VER_38:
3581 rtl8411_hw_phy_config(tp);
3582 break;
3583
Hayes Wang5598bfe2012-07-02 17:23:21 +08003584 case RTL_GIGA_MAC_VER_39:
3585 rtl8106e_hw_phy_config(tp);
3586 break;
3587
Hayes Wangc5583862012-07-02 17:23:22 +08003588 case RTL_GIGA_MAC_VER_40:
3589 rtl8168g_1_hw_phy_config(tp);
3590 break;
3591
3592 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003593 default:
3594 break;
3595 }
3596}
3597
Francois Romieuda78dbf2012-01-26 14:18:23 +01003598static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 struct timer_list *timer = &tp->timer;
3601 void __iomem *ioaddr = tp->mmio_addr;
3602 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3603
Francois Romieubcf0bf92006-07-26 23:14:13 +02003604 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
françois romieu4da19632011-01-03 15:07:55 +00003606 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003607 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 * A busy loop could burn quite a few cycles on nowadays CPU.
3609 * Let's delay the execution of the timer for a few ticks.
3610 */
3611 timeout = HZ/10;
3612 goto out_mod_timer;
3613 }
3614
3615 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003616 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
Francois Romieuda78dbf2012-01-26 14:18:23 +01003618 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
françois romieu4da19632011-01-03 15:07:55 +00003620 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
3622out_mod_timer:
3623 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003624}
3625
3626static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3627{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003628 if (!test_and_set_bit(flag, tp->wk.flags))
3629 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003630}
3631
3632static void rtl8169_phy_timer(unsigned long __opaque)
3633{
3634 struct net_device *dev = (struct net_device *)__opaque;
3635 struct rtl8169_private *tp = netdev_priv(dev);
3636
Francois Romieu98ddf982012-01-31 10:47:34 +01003637 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638}
3639
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3641 void __iomem *ioaddr)
3642{
3643 iounmap(ioaddr);
3644 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003645 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 pci_disable_device(pdev);
3647 free_netdev(dev);
3648}
3649
Francois Romieuffc46952012-07-06 14:19:23 +02003650DECLARE_RTL_COND(rtl_phy_reset_cond)
3651{
3652 return tp->phy_reset_pending(tp);
3653}
3654
Francois Romieubf793292006-11-01 00:53:05 +01003655static void rtl8169_phy_reset(struct net_device *dev,
3656 struct rtl8169_private *tp)
3657{
françois romieu4da19632011-01-03 15:07:55 +00003658 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003659 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003660}
3661
David S. Miller8decf862011-09-22 03:23:13 -04003662static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3663{
3664 void __iomem *ioaddr = tp->mmio_addr;
3665
3666 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3667 (RTL_R8(PHYstatus) & TBI_Enable);
3668}
3669
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003670static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003672 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003673
Francois Romieu5615d9f2007-08-17 17:50:46 +02003674 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003675
Marcus Sundberg773328942008-07-10 21:28:08 +02003676 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3677 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3678 RTL_W8(0x82, 0x01);
3679 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003680
Francois Romieu6dccd162007-02-13 23:38:05 +01003681 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3682
3683 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3684 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003685
Francois Romieubcf0bf92006-07-26 23:14:13 +02003686 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003687 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3688 RTL_W8(0x82, 0x01);
3689 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003690 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003691 }
3692
Francois Romieubf793292006-11-01 00:53:05 +01003693 rtl8169_phy_reset(dev, tp);
3694
Oliver Neukum54405cd2011-01-06 21:55:13 +01003695 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003696 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3697 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3698 (tp->mii.supports_gmii ?
3699 ADVERTISED_1000baseT_Half |
3700 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003701
David S. Miller8decf862011-09-22 03:23:13 -04003702 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003703 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003704}
3705
Francois Romieu773d2022007-01-31 23:47:43 +01003706static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3707{
3708 void __iomem *ioaddr = tp->mmio_addr;
3709 u32 high;
3710 u32 low;
3711
3712 low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
3713 high = addr[4] | (addr[5] << 8);
3714
Francois Romieuda78dbf2012-01-26 14:18:23 +01003715 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003716
3717 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2b2010-04-26 11:42:58 +00003718
Francois Romieu773d2022007-01-31 23:47:43 +01003719 RTL_W32(MAC4, high);
françois romieu908ba2b2010-04-26 11:42:58 +00003720 RTL_R32(MAC4);
3721
Francois Romieu78f1cd02010-03-27 19:35:46 -07003722 RTL_W32(MAC0, low);
françois romieu908ba2b2010-04-26 11:42:58 +00003723 RTL_R32(MAC0);
3724
françois romieuc28aa382011-08-02 03:53:43 +00003725 if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
3726 const struct exgmac_reg e[] = {
3727 { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
3728 { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
3729 { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
3730 { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
3731 low >> 16 },
3732 };
3733
Francois Romieufdf6fc02012-07-06 22:40:38 +02003734 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
françois romieuc28aa382011-08-02 03:53:43 +00003735 }
3736
Francois Romieu773d2022007-01-31 23:47:43 +01003737 RTL_W8(Cfg9346, Cfg9346_Lock);
3738
Francois Romieuda78dbf2012-01-26 14:18:23 +01003739 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003740}
3741
3742static int rtl_set_mac_address(struct net_device *dev, void *p)
3743{
3744 struct rtl8169_private *tp = netdev_priv(dev);
3745 struct sockaddr *addr = p;
3746
3747 if (!is_valid_ether_addr(addr->sa_data))
3748 return -EADDRNOTAVAIL;
3749
3750 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3751
3752 rtl_rar_set(tp, dev->dev_addr);
3753
3754 return 0;
3755}
3756
Francois Romieu5f787a12006-08-17 13:02:36 +02003757static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3758{
3759 struct rtl8169_private *tp = netdev_priv(dev);
3760 struct mii_ioctl_data *data = if_mii(ifr);
3761
Francois Romieu8b4ab282008-11-19 22:05:25 -08003762 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3763}
Francois Romieu5f787a12006-08-17 13:02:36 +02003764
Francois Romieucecb5fd2011-04-01 10:21:07 +02003765static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3766 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003767{
Francois Romieu5f787a12006-08-17 13:02:36 +02003768 switch (cmd) {
3769 case SIOCGMIIPHY:
3770 data->phy_id = 32; /* Internal PHY */
3771 return 0;
3772
3773 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003774 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003775 return 0;
3776
3777 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003778 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003779 return 0;
3780 }
3781 return -EOPNOTSUPP;
3782}
3783
Francois Romieu8b4ab282008-11-19 22:05:25 -08003784static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3785{
3786 return -EOPNOTSUPP;
3787}
3788
Francois Romieufbac58f2007-10-04 22:51:38 +02003789static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3790{
3791 if (tp->features & RTL_FEATURE_MSI) {
3792 pci_disable_msi(pdev);
3793 tp->features &= ~RTL_FEATURE_MSI;
3794 }
3795}
3796
françois romieuc0e45c12011-01-03 15:08:04 +00003797static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
3798{
3799 struct mdio_ops *ops = &tp->mdio_ops;
3800
3801 switch (tp->mac_version) {
3802 case RTL_GIGA_MAC_VER_27:
3803 ops->write = r8168dp_1_mdio_write;
3804 ops->read = r8168dp_1_mdio_read;
3805 break;
françois romieue6de30d2011-01-03 15:08:37 +00003806 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003807 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003808 ops->write = r8168dp_2_mdio_write;
3809 ops->read = r8168dp_2_mdio_read;
3810 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003811 case RTL_GIGA_MAC_VER_40:
3812 case RTL_GIGA_MAC_VER_41:
3813 ops->write = r8168g_mdio_write;
3814 ops->read = r8168g_mdio_read;
3815 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003816 default:
3817 ops->write = r8169_mdio_write;
3818 ops->read = r8169_mdio_read;
3819 break;
3820 }
3821}
3822
David S. Miller1805b2f2011-10-24 18:18:09 -04003823static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3824{
3825 void __iomem *ioaddr = tp->mmio_addr;
3826
3827 switch (tp->mac_version) {
3828 case RTL_GIGA_MAC_VER_29:
3829 case RTL_GIGA_MAC_VER_30:
3830 case RTL_GIGA_MAC_VER_32:
3831 case RTL_GIGA_MAC_VER_33:
3832 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003833 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003834 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003835 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003836 case RTL_GIGA_MAC_VER_40:
3837 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003838 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3839 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3840 break;
3841 default:
3842 break;
3843 }
3844}
3845
3846static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3847{
3848 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3849 return false;
3850
3851 rtl_writephy(tp, 0x1f, 0x0000);
3852 rtl_writephy(tp, MII_BMCR, 0x0000);
3853
3854 rtl_wol_suspend_quirk(tp);
3855
3856 return true;
3857}
3858
françois romieu065c27c2011-01-03 15:08:12 +00003859static void r810x_phy_power_down(struct rtl8169_private *tp)
3860{
3861 rtl_writephy(tp, 0x1f, 0x0000);
3862 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3863}
3864
3865static void r810x_phy_power_up(struct rtl8169_private *tp)
3866{
3867 rtl_writephy(tp, 0x1f, 0x0000);
3868 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3869}
3870
3871static void r810x_pll_power_down(struct rtl8169_private *tp)
3872{
Hayes Wang00042992012-03-30 14:33:00 +08003873 void __iomem *ioaddr = tp->mmio_addr;
3874
David S. Miller1805b2f2011-10-24 18:18:09 -04003875 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003876 return;
françois romieu065c27c2011-01-03 15:08:12 +00003877
3878 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003879
3880 switch (tp->mac_version) {
3881 case RTL_GIGA_MAC_VER_07:
3882 case RTL_GIGA_MAC_VER_08:
3883 case RTL_GIGA_MAC_VER_09:
3884 case RTL_GIGA_MAC_VER_10:
3885 case RTL_GIGA_MAC_VER_13:
3886 case RTL_GIGA_MAC_VER_16:
3887 break;
3888 default:
3889 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3890 break;
3891 }
françois romieu065c27c2011-01-03 15:08:12 +00003892}
3893
3894static void r810x_pll_power_up(struct rtl8169_private *tp)
3895{
Hayes Wang00042992012-03-30 14:33:00 +08003896 void __iomem *ioaddr = tp->mmio_addr;
3897
françois romieu065c27c2011-01-03 15:08:12 +00003898 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003899
3900 switch (tp->mac_version) {
3901 case RTL_GIGA_MAC_VER_07:
3902 case RTL_GIGA_MAC_VER_08:
3903 case RTL_GIGA_MAC_VER_09:
3904 case RTL_GIGA_MAC_VER_10:
3905 case RTL_GIGA_MAC_VER_13:
3906 case RTL_GIGA_MAC_VER_16:
3907 break;
3908 default:
3909 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3910 break;
3911 }
françois romieu065c27c2011-01-03 15:08:12 +00003912}
3913
3914static void r8168_phy_power_up(struct rtl8169_private *tp)
3915{
3916 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003917 switch (tp->mac_version) {
3918 case RTL_GIGA_MAC_VER_11:
3919 case RTL_GIGA_MAC_VER_12:
3920 case RTL_GIGA_MAC_VER_17:
3921 case RTL_GIGA_MAC_VER_18:
3922 case RTL_GIGA_MAC_VER_19:
3923 case RTL_GIGA_MAC_VER_20:
3924 case RTL_GIGA_MAC_VER_21:
3925 case RTL_GIGA_MAC_VER_22:
3926 case RTL_GIGA_MAC_VER_23:
3927 case RTL_GIGA_MAC_VER_24:
3928 case RTL_GIGA_MAC_VER_25:
3929 case RTL_GIGA_MAC_VER_26:
3930 case RTL_GIGA_MAC_VER_27:
3931 case RTL_GIGA_MAC_VER_28:
3932 case RTL_GIGA_MAC_VER_31:
3933 rtl_writephy(tp, 0x0e, 0x0000);
3934 break;
3935 default:
3936 break;
3937 }
françois romieu065c27c2011-01-03 15:08:12 +00003938 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3939}
3940
3941static void r8168_phy_power_down(struct rtl8169_private *tp)
3942{
3943 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003944 switch (tp->mac_version) {
3945 case RTL_GIGA_MAC_VER_32:
3946 case RTL_GIGA_MAC_VER_33:
3947 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3948 break;
3949
3950 case RTL_GIGA_MAC_VER_11:
3951 case RTL_GIGA_MAC_VER_12:
3952 case RTL_GIGA_MAC_VER_17:
3953 case RTL_GIGA_MAC_VER_18:
3954 case RTL_GIGA_MAC_VER_19:
3955 case RTL_GIGA_MAC_VER_20:
3956 case RTL_GIGA_MAC_VER_21:
3957 case RTL_GIGA_MAC_VER_22:
3958 case RTL_GIGA_MAC_VER_23:
3959 case RTL_GIGA_MAC_VER_24:
3960 case RTL_GIGA_MAC_VER_25:
3961 case RTL_GIGA_MAC_VER_26:
3962 case RTL_GIGA_MAC_VER_27:
3963 case RTL_GIGA_MAC_VER_28:
3964 case RTL_GIGA_MAC_VER_31:
3965 rtl_writephy(tp, 0x0e, 0x0200);
3966 default:
3967 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3968 break;
3969 }
françois romieu065c27c2011-01-03 15:08:12 +00003970}
3971
3972static void r8168_pll_power_down(struct rtl8169_private *tp)
3973{
3974 void __iomem *ioaddr = tp->mmio_addr;
3975
Francois Romieucecb5fd2011-04-01 10:21:07 +02003976 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
3977 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
3978 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00003979 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00003980 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08003981 }
françois romieu065c27c2011-01-03 15:08:12 +00003982
Francois Romieucecb5fd2011-04-01 10:21:07 +02003983 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
3984 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00003985 (RTL_R16(CPlusCmd) & ASF)) {
3986 return;
3987 }
3988
hayeswang01dc7fe2011-03-21 01:50:28 +00003989 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
3990 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02003991 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00003992
David S. Miller1805b2f2011-10-24 18:18:09 -04003993 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003994 return;
françois romieu065c27c2011-01-03 15:08:12 +00003995
3996 r8168_phy_power_down(tp);
3997
3998 switch (tp->mac_version) {
3999 case RTL_GIGA_MAC_VER_25:
4000 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004001 case RTL_GIGA_MAC_VER_27:
4002 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004003 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004004 case RTL_GIGA_MAC_VER_32:
4005 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004006 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4007 break;
4008 }
4009}
4010
4011static void r8168_pll_power_up(struct rtl8169_private *tp)
4012{
4013 void __iomem *ioaddr = tp->mmio_addr;
4014
françois romieu065c27c2011-01-03 15:08:12 +00004015 switch (tp->mac_version) {
4016 case RTL_GIGA_MAC_VER_25:
4017 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004018 case RTL_GIGA_MAC_VER_27:
4019 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004020 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004021 case RTL_GIGA_MAC_VER_32:
4022 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004023 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4024 break;
4025 }
4026
4027 r8168_phy_power_up(tp);
4028}
4029
Francois Romieud58d46b2011-05-03 16:38:29 +02004030static void rtl_generic_op(struct rtl8169_private *tp,
4031 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004032{
4033 if (op)
4034 op(tp);
4035}
4036
4037static void rtl_pll_power_down(struct rtl8169_private *tp)
4038{
Francois Romieud58d46b2011-05-03 16:38:29 +02004039 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004040}
4041
4042static void rtl_pll_power_up(struct rtl8169_private *tp)
4043{
Francois Romieud58d46b2011-05-03 16:38:29 +02004044 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004045}
4046
4047static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
4048{
4049 struct pll_power_ops *ops = &tp->pll_power_ops;
4050
4051 switch (tp->mac_version) {
4052 case RTL_GIGA_MAC_VER_07:
4053 case RTL_GIGA_MAC_VER_08:
4054 case RTL_GIGA_MAC_VER_09:
4055 case RTL_GIGA_MAC_VER_10:
4056 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004057 case RTL_GIGA_MAC_VER_29:
4058 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004059 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004060 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004061 ops->down = r810x_pll_power_down;
4062 ops->up = r810x_pll_power_up;
4063 break;
4064
4065 case RTL_GIGA_MAC_VER_11:
4066 case RTL_GIGA_MAC_VER_12:
4067 case RTL_GIGA_MAC_VER_17:
4068 case RTL_GIGA_MAC_VER_18:
4069 case RTL_GIGA_MAC_VER_19:
4070 case RTL_GIGA_MAC_VER_20:
4071 case RTL_GIGA_MAC_VER_21:
4072 case RTL_GIGA_MAC_VER_22:
4073 case RTL_GIGA_MAC_VER_23:
4074 case RTL_GIGA_MAC_VER_24:
4075 case RTL_GIGA_MAC_VER_25:
4076 case RTL_GIGA_MAC_VER_26:
4077 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004078 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004079 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004080 case RTL_GIGA_MAC_VER_32:
4081 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004082 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004083 case RTL_GIGA_MAC_VER_35:
4084 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004085 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004086 case RTL_GIGA_MAC_VER_40:
4087 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004088 ops->down = r8168_pll_power_down;
4089 ops->up = r8168_pll_power_up;
4090 break;
4091
4092 default:
4093 ops->down = NULL;
4094 ops->up = NULL;
4095 break;
4096 }
4097}
4098
Hayes Wange542a222011-07-06 15:58:04 +08004099static void rtl_init_rxcfg(struct rtl8169_private *tp)
4100{
4101 void __iomem *ioaddr = tp->mmio_addr;
4102
4103 switch (tp->mac_version) {
4104 case RTL_GIGA_MAC_VER_01:
4105 case RTL_GIGA_MAC_VER_02:
4106 case RTL_GIGA_MAC_VER_03:
4107 case RTL_GIGA_MAC_VER_04:
4108 case RTL_GIGA_MAC_VER_05:
4109 case RTL_GIGA_MAC_VER_06:
4110 case RTL_GIGA_MAC_VER_10:
4111 case RTL_GIGA_MAC_VER_11:
4112 case RTL_GIGA_MAC_VER_12:
4113 case RTL_GIGA_MAC_VER_13:
4114 case RTL_GIGA_MAC_VER_14:
4115 case RTL_GIGA_MAC_VER_15:
4116 case RTL_GIGA_MAC_VER_16:
4117 case RTL_GIGA_MAC_VER_17:
4118 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4119 break;
4120 case RTL_GIGA_MAC_VER_18:
4121 case RTL_GIGA_MAC_VER_19:
4122 case RTL_GIGA_MAC_VER_20:
4123 case RTL_GIGA_MAC_VER_21:
4124 case RTL_GIGA_MAC_VER_22:
4125 case RTL_GIGA_MAC_VER_23:
4126 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004127 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004128 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4129 break;
4130 default:
4131 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4132 break;
4133 }
4134}
4135
Hayes Wang92fc43b2011-07-06 15:58:03 +08004136static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4137{
4138 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4139}
4140
Francois Romieud58d46b2011-05-03 16:38:29 +02004141static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4142{
françois romieu9c5028e2012-03-02 04:43:14 +00004143 void __iomem *ioaddr = tp->mmio_addr;
4144
4145 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004146 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004147 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004148}
4149
4150static void rtl_hw_jumbo_disable(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.disable);
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 r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4160{
4161 void __iomem *ioaddr = tp->mmio_addr;
4162
4163 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4164 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4165 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4166}
4167
4168static void r8168c_hw_jumbo_disable(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, 0x5 << MAX_READ_REQUEST_SHIFT);
4175}
4176
4177static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
4178{
4179 void __iomem *ioaddr = tp->mmio_addr;
4180
4181 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4182}
4183
4184static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4185{
4186 void __iomem *ioaddr = tp->mmio_addr;
4187
4188 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4189}
4190
4191static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4192{
4193 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004194
4195 RTL_W8(MaxTxPacketSize, 0x3f);
4196 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4197 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004198 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004199}
4200
4201static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4202{
4203 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004204
4205 RTL_W8(MaxTxPacketSize, 0x0c);
4206 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4207 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004208 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004209}
4210
4211static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4212{
4213 rtl_tx_performance_tweak(tp->pci_dev,
4214 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4215}
4216
4217static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4218{
4219 rtl_tx_performance_tweak(tp->pci_dev,
4220 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4221}
4222
4223static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4224{
4225 void __iomem *ioaddr = tp->mmio_addr;
4226
4227 r8168b_0_hw_jumbo_enable(tp);
4228
4229 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4230}
4231
4232static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4233{
4234 void __iomem *ioaddr = tp->mmio_addr;
4235
4236 r8168b_0_hw_jumbo_disable(tp);
4237
4238 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4239}
4240
4241static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
4242{
4243 struct jumbo_ops *ops = &tp->jumbo_ops;
4244
4245 switch (tp->mac_version) {
4246 case RTL_GIGA_MAC_VER_11:
4247 ops->disable = r8168b_0_hw_jumbo_disable;
4248 ops->enable = r8168b_0_hw_jumbo_enable;
4249 break;
4250 case RTL_GIGA_MAC_VER_12:
4251 case RTL_GIGA_MAC_VER_17:
4252 ops->disable = r8168b_1_hw_jumbo_disable;
4253 ops->enable = r8168b_1_hw_jumbo_enable;
4254 break;
4255 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4256 case RTL_GIGA_MAC_VER_19:
4257 case RTL_GIGA_MAC_VER_20:
4258 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4259 case RTL_GIGA_MAC_VER_22:
4260 case RTL_GIGA_MAC_VER_23:
4261 case RTL_GIGA_MAC_VER_24:
4262 case RTL_GIGA_MAC_VER_25:
4263 case RTL_GIGA_MAC_VER_26:
4264 ops->disable = r8168c_hw_jumbo_disable;
4265 ops->enable = r8168c_hw_jumbo_enable;
4266 break;
4267 case RTL_GIGA_MAC_VER_27:
4268 case RTL_GIGA_MAC_VER_28:
4269 ops->disable = r8168dp_hw_jumbo_disable;
4270 ops->enable = r8168dp_hw_jumbo_enable;
4271 break;
4272 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4273 case RTL_GIGA_MAC_VER_32:
4274 case RTL_GIGA_MAC_VER_33:
4275 case RTL_GIGA_MAC_VER_34:
4276 ops->disable = r8168e_hw_jumbo_disable;
4277 ops->enable = r8168e_hw_jumbo_enable;
4278 break;
4279
4280 /*
4281 * No action needed for jumbo frames with 8169.
4282 * No jumbo for 810x at all.
4283 */
Hayes Wangc5583862012-07-02 17:23:22 +08004284 case RTL_GIGA_MAC_VER_40:
4285 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004286 default:
4287 ops->disable = NULL;
4288 ops->enable = NULL;
4289 break;
4290 }
4291}
4292
Francois Romieuffc46952012-07-06 14:19:23 +02004293DECLARE_RTL_COND(rtl_chipcmd_cond)
4294{
4295 void __iomem *ioaddr = tp->mmio_addr;
4296
4297 return RTL_R8(ChipCmd) & CmdReset;
4298}
4299
Francois Romieu6f43adc2011-04-29 15:05:51 +02004300static void rtl_hw_reset(struct rtl8169_private *tp)
4301{
4302 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004303
Francois Romieu6f43adc2011-04-29 15:05:51 +02004304 RTL_W8(ChipCmd, CmdReset);
4305
Francois Romieuffc46952012-07-06 14:19:23 +02004306 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004307}
4308
Francois Romieub6ffd972011-06-17 17:00:05 +02004309static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4310{
4311 struct rtl_fw *rtl_fw;
4312 const char *name;
4313 int rc = -ENOMEM;
4314
4315 name = rtl_lookup_firmware_name(tp);
4316 if (!name)
4317 goto out_no_firmware;
4318
4319 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4320 if (!rtl_fw)
4321 goto err_warn;
4322
4323 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4324 if (rc < 0)
4325 goto err_free;
4326
Francois Romieufd112f22011-06-18 00:10:29 +02004327 rc = rtl_check_firmware(tp, rtl_fw);
4328 if (rc < 0)
4329 goto err_release_firmware;
4330
Francois Romieub6ffd972011-06-17 17:00:05 +02004331 tp->rtl_fw = rtl_fw;
4332out:
4333 return;
4334
Francois Romieufd112f22011-06-18 00:10:29 +02004335err_release_firmware:
4336 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004337err_free:
4338 kfree(rtl_fw);
4339err_warn:
4340 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4341 name, rc);
4342out_no_firmware:
4343 tp->rtl_fw = NULL;
4344 goto out;
4345}
4346
François Romieu953a12c2011-04-24 17:38:48 +02004347static void rtl_request_firmware(struct rtl8169_private *tp)
4348{
Francois Romieub6ffd972011-06-17 17:00:05 +02004349 if (IS_ERR(tp->rtl_fw))
4350 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004351}
4352
Hayes Wang92fc43b2011-07-06 15:58:03 +08004353static void rtl_rx_close(struct rtl8169_private *tp)
4354{
4355 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004356
Francois Romieu1687b562011-07-19 17:21:29 +02004357 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004358}
4359
Francois Romieuffc46952012-07-06 14:19:23 +02004360DECLARE_RTL_COND(rtl_npq_cond)
4361{
4362 void __iomem *ioaddr = tp->mmio_addr;
4363
4364 return RTL_R8(TxPoll) & NPQ;
4365}
4366
4367DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4368{
4369 void __iomem *ioaddr = tp->mmio_addr;
4370
4371 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4372}
4373
françois romieue6de30d2011-01-03 15:08:37 +00004374static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
françois romieue6de30d2011-01-03 15:08:37 +00004376 void __iomem *ioaddr = tp->mmio_addr;
4377
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004379 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Hayes Wang92fc43b2011-07-06 15:58:03 +08004381 rtl_rx_close(tp);
4382
Hayes Wang5d2e1952011-02-22 17:26:22 +08004383 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004384 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4385 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004386 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004387 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4388 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004389 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004390 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004391 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4392 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004393 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004394 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004395 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004396 } else {
4397 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4398 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004399 }
4400
Hayes Wang92fc43b2011-07-06 15:58:03 +08004401 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402}
4403
Francois Romieu7f796d832007-06-11 23:04:41 +02004404static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004405{
4406 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004407
4408 /* Set DMA burst size and Interframe Gap Time */
4409 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4410 (InterFrameGap << TxInterFrameGapShift));
4411}
4412
Francois Romieu07ce4062007-02-23 23:36:39 +01004413static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414{
4415 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
Francois Romieu07ce4062007-02-23 23:36:39 +01004417 tp->hw_start(dev);
4418
Francois Romieuda78dbf2012-01-26 14:18:23 +01004419 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004420}
4421
Francois Romieu7f796d832007-06-11 23:04:41 +02004422static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4423 void __iomem *ioaddr)
4424{
4425 /*
4426 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4427 * register to be written before TxDescAddrLow to work.
4428 * Switching from MMIO to I/O access fixes the issue as well.
4429 */
4430 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004431 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004432 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004433 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004434}
4435
4436static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4437{
4438 u16 cmd;
4439
4440 cmd = RTL_R16(CPlusCmd);
4441 RTL_W16(CPlusCmd, cmd);
4442 return cmd;
4443}
4444
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004445static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004446{
4447 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e872009-10-26 10:52:37 +00004448 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004449}
4450
Francois Romieu6dccd162007-02-13 23:38:05 +01004451static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4452{
Francois Romieu37441002011-06-17 22:58:54 +02004453 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004454 u32 mac_version;
4455 u32 clk;
4456 u32 val;
4457 } cfg2_info [] = {
4458 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4459 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4460 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4461 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004462 };
4463 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004464 unsigned int i;
4465 u32 clk;
4466
4467 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004468 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004469 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4470 RTL_W32(0x7c, p->val);
4471 break;
4472 }
4473 }
4474}
4475
Francois Romieue6b763e2012-03-08 09:35:39 +01004476static void rtl_set_rx_mode(struct net_device *dev)
4477{
4478 struct rtl8169_private *tp = netdev_priv(dev);
4479 void __iomem *ioaddr = tp->mmio_addr;
4480 u32 mc_filter[2]; /* Multicast hash filter */
4481 int rx_mode;
4482 u32 tmp = 0;
4483
4484 if (dev->flags & IFF_PROMISC) {
4485 /* Unconditionally log net taps. */
4486 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4487 rx_mode =
4488 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4489 AcceptAllPhys;
4490 mc_filter[1] = mc_filter[0] = 0xffffffff;
4491 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4492 (dev->flags & IFF_ALLMULTI)) {
4493 /* Too many to filter perfectly -- accept all multicasts. */
4494 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4495 mc_filter[1] = mc_filter[0] = 0xffffffff;
4496 } else {
4497 struct netdev_hw_addr *ha;
4498
4499 rx_mode = AcceptBroadcast | AcceptMyPhys;
4500 mc_filter[1] = mc_filter[0] = 0;
4501 netdev_for_each_mc_addr(ha, dev) {
4502 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4503 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4504 rx_mode |= AcceptMulticast;
4505 }
4506 }
4507
4508 if (dev->features & NETIF_F_RXALL)
4509 rx_mode |= (AcceptErr | AcceptRunt);
4510
4511 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4512
4513 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4514 u32 data = mc_filter[0];
4515
4516 mc_filter[0] = swab32(mc_filter[1]);
4517 mc_filter[1] = swab32(data);
4518 }
4519
4520 RTL_W32(MAR0 + 4, mc_filter[1]);
4521 RTL_W32(MAR0 + 0, mc_filter[0]);
4522
4523 RTL_W32(RxConfig, tmp);
4524}
4525
Francois Romieu07ce4062007-02-23 23:36:39 +01004526static void rtl_hw_start_8169(struct net_device *dev)
4527{
4528 struct rtl8169_private *tp = netdev_priv(dev);
4529 void __iomem *ioaddr = tp->mmio_addr;
4530 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004531
Francois Romieu9cb427b2006-11-02 00:10:16 +01004532 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4533 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4534 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4535 }
4536
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004538 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4539 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4540 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4541 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004542 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4543
Hayes Wange542a222011-07-06 15:58:04 +08004544 rtl_init_rxcfg(tp);
4545
françois romieuf0298f82011-01-03 15:07:42 +00004546 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004548 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Francois Romieucecb5fd2011-04-01 10:21:07 +02004550 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4551 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4552 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4553 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004554 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Francois Romieu7f796d832007-06-11 23:04:41 +02004556 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004557
Francois Romieucecb5fd2011-04-01 10:21:07 +02004558 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4559 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004560 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004562 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 }
4564
Francois Romieubcf0bf92006-07-26 23:14:13 +02004565 RTL_W16(CPlusCmd, tp->cp_cmd);
4566
Francois Romieu6dccd162007-02-13 23:38:05 +01004567 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4568
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 /*
4570 * Undocumented corner. Supposedly:
4571 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4572 */
4573 RTL_W16(IntrMitigate, 0x0000);
4574
Francois Romieu7f796d832007-06-11 23:04:41 +02004575 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004576
Francois Romieucecb5fd2011-04-01 10:21:07 +02004577 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4578 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4579 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4580 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004581 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4582 rtl_set_rx_tx_config_registers(tp);
4583 }
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004586
4587 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4588 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589
4590 RTL_W32(RxMissed, 0);
4591
Francois Romieu07ce4062007-02-23 23:36:39 +01004592 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593
4594 /* no early-rx interrupts */
4595 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004596}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004598static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4599{
4600 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004601 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004602}
4603
4604static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4605{
Francois Romieu52989f02012-07-06 13:37:00 +02004606 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004607}
4608
4609static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004610{
4611 u32 csi;
4612
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004613 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4614 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004615}
4616
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004617static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004618{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004619 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004620}
4621
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004622static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004623{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004624 rtl_csi_access_enable(tp, 0x27000000);
4625}
4626
Francois Romieuffc46952012-07-06 14:19:23 +02004627DECLARE_RTL_COND(rtl_csiar_cond)
4628{
4629 void __iomem *ioaddr = tp->mmio_addr;
4630
4631 return RTL_R32(CSIAR) & CSIAR_FLAG;
4632}
4633
Francois Romieu52989f02012-07-06 13:37:00 +02004634static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004635{
Francois Romieu52989f02012-07-06 13:37:00 +02004636 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004637
4638 RTL_W32(CSIDR, value);
4639 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4640 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4641
Francois Romieuffc46952012-07-06 14:19:23 +02004642 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004643}
4644
Francois Romieu52989f02012-07-06 13:37:00 +02004645static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004646{
Francois Romieu52989f02012-07-06 13:37:00 +02004647 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004648
4649 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4650 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4651
Francois Romieuffc46952012-07-06 14:19:23 +02004652 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4653 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004654}
4655
Francois Romieu52989f02012-07-06 13:37:00 +02004656static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004657{
Francois Romieu52989f02012-07-06 13:37:00 +02004658 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004659
4660 RTL_W32(CSIDR, value);
4661 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4662 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4663 CSIAR_FUNC_NIC);
4664
Francois Romieuffc46952012-07-06 14:19:23 +02004665 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004666}
4667
Francois Romieu52989f02012-07-06 13:37:00 +02004668static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004669{
Francois Romieu52989f02012-07-06 13:37:00 +02004670 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004671
4672 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4673 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4674
Francois Romieuffc46952012-07-06 14:19:23 +02004675 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4676 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004677}
4678
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004679static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
4680{
4681 struct csi_ops *ops = &tp->csi_ops;
4682
4683 switch (tp->mac_version) {
4684 case RTL_GIGA_MAC_VER_01:
4685 case RTL_GIGA_MAC_VER_02:
4686 case RTL_GIGA_MAC_VER_03:
4687 case RTL_GIGA_MAC_VER_04:
4688 case RTL_GIGA_MAC_VER_05:
4689 case RTL_GIGA_MAC_VER_06:
4690 case RTL_GIGA_MAC_VER_10:
4691 case RTL_GIGA_MAC_VER_11:
4692 case RTL_GIGA_MAC_VER_12:
4693 case RTL_GIGA_MAC_VER_13:
4694 case RTL_GIGA_MAC_VER_14:
4695 case RTL_GIGA_MAC_VER_15:
4696 case RTL_GIGA_MAC_VER_16:
4697 case RTL_GIGA_MAC_VER_17:
4698 ops->write = NULL;
4699 ops->read = NULL;
4700 break;
4701
Hayes Wang7e18dca2012-03-30 14:33:02 +08004702 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004703 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004704 ops->write = r8402_csi_write;
4705 ops->read = r8402_csi_read;
4706 break;
4707
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004708 default:
4709 ops->write = r8169_csi_write;
4710 ops->read = r8169_csi_read;
4711 break;
4712 }
Francois Romieudacf8152008-08-02 20:44:13 +02004713}
4714
4715struct ephy_info {
4716 unsigned int offset;
4717 u16 mask;
4718 u16 bits;
4719};
4720
Francois Romieufdf6fc02012-07-06 22:40:38 +02004721static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4722 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004723{
4724 u16 w;
4725
4726 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004727 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4728 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004729 e++;
4730 }
4731}
4732
Francois Romieub726e492008-06-28 12:22:59 +02004733static void rtl_disable_clock_request(struct pci_dev *pdev)
4734{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004735 pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
4736 PCI_EXP_LNKCTL_CLKREQ_EN);
Francois Romieub726e492008-06-28 12:22:59 +02004737}
4738
françois romieue6de30d2011-01-03 15:08:37 +00004739static void rtl_enable_clock_request(struct pci_dev *pdev)
4740{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004741 pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
4742 PCI_EXP_LNKCTL_CLKREQ_EN);
françois romieue6de30d2011-01-03 15:08:37 +00004743}
4744
Francois Romieub726e492008-06-28 12:22:59 +02004745#define R8168_CPCMD_QUIRK_MASK (\
4746 EnableBist | \
4747 Mac_dbgo_oe | \
4748 Force_half_dup | \
4749 Force_rxflow_en | \
4750 Force_txflow_en | \
4751 Cxpl_dbg_sel | \
4752 ASF | \
4753 PktCntrDisable | \
4754 Mac_dbgo_sel)
4755
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004756static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004757{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004758 void __iomem *ioaddr = tp->mmio_addr;
4759 struct pci_dev *pdev = tp->pci_dev;
4760
Francois Romieub726e492008-06-28 12:22:59 +02004761 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4762
4763 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4764
Francois Romieu2e68ae42008-06-28 12:00:55 +02004765 rtl_tx_performance_tweak(pdev,
4766 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004767}
4768
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004769static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004770{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004771 void __iomem *ioaddr = tp->mmio_addr;
4772
4773 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004774
françois romieuf0298f82011-01-03 15:07:42 +00004775 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004776
4777 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004778}
4779
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004780static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004781{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004782 void __iomem *ioaddr = tp->mmio_addr;
4783 struct pci_dev *pdev = tp->pci_dev;
4784
Francois Romieub726e492008-06-28 12:22:59 +02004785 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4786
4787 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4788
Francois Romieu219a1e92008-06-28 11:58:39 +02004789 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004790
4791 rtl_disable_clock_request(pdev);
4792
4793 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004794}
4795
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004796static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004797{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004798 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004799 { 0x01, 0, 0x0001 },
4800 { 0x02, 0x0800, 0x1000 },
4801 { 0x03, 0, 0x0042 },
4802 { 0x06, 0x0080, 0x0000 },
4803 { 0x07, 0, 0x2000 }
4804 };
4805
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004806 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004807
Francois Romieufdf6fc02012-07-06 22:40:38 +02004808 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004809
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004810 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004811}
4812
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004813static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004814{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004815 void __iomem *ioaddr = tp->mmio_addr;
4816 struct pci_dev *pdev = tp->pci_dev;
4817
4818 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004819
4820 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4821
4822 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4823
4824 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4825}
4826
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004827static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004828{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004829 void __iomem *ioaddr = tp->mmio_addr;
4830 struct pci_dev *pdev = tp->pci_dev;
4831
4832 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004833
4834 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4835
4836 /* Magic. */
4837 RTL_W8(DBG_REG, 0x20);
4838
françois romieuf0298f82011-01-03 15:07:42 +00004839 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004840
4841 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4842
4843 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4844}
4845
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004846static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004847{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004848 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004849 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004850 { 0x02, 0x0800, 0x1000 },
4851 { 0x03, 0, 0x0002 },
4852 { 0x06, 0x0080, 0x0000 }
4853 };
4854
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004855 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004856
4857 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4858
Francois Romieufdf6fc02012-07-06 22:40:38 +02004859 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004860
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004861 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004862}
4863
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004864static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004865{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004866 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004867 { 0x01, 0, 0x0001 },
4868 { 0x03, 0x0400, 0x0220 }
4869 };
4870
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004871 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004872
Francois Romieufdf6fc02012-07-06 22:40:38 +02004873 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004874
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004875 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004876}
4877
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004878static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004879{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004880 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004881}
4882
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004883static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004884{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004885 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004886
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004887 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004888}
4889
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004890static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004891{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004892 void __iomem *ioaddr = tp->mmio_addr;
4893 struct pci_dev *pdev = tp->pci_dev;
4894
4895 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004896
4897 rtl_disable_clock_request(pdev);
4898
françois romieuf0298f82011-01-03 15:07:42 +00004899 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004900
4901 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4902
4903 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4904}
4905
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004906static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004907{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004908 void __iomem *ioaddr = tp->mmio_addr;
4909 struct pci_dev *pdev = tp->pci_dev;
4910
4911 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004912
4913 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4914
4915 RTL_W8(MaxTxPacketSize, TxPacketMax);
4916
4917 rtl_disable_clock_request(pdev);
4918}
4919
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004920static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004921{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004922 void __iomem *ioaddr = tp->mmio_addr;
4923 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004924 static const struct ephy_info e_info_8168d_4[] = {
4925 { 0x0b, ~0, 0x48 },
4926 { 0x19, 0x20, 0x50 },
4927 { 0x0c, ~0, 0x20 }
4928 };
4929 int i;
4930
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004931 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004932
4933 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4934
4935 RTL_W8(MaxTxPacketSize, TxPacketMax);
4936
4937 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4938 const struct ephy_info *e = e_info_8168d_4 + i;
4939 u16 w;
4940
Francois Romieufdf6fc02012-07-06 22:40:38 +02004941 w = rtl_ephy_read(tp, e->offset);
4942 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004943 }
4944
4945 rtl_enable_clock_request(pdev);
4946}
4947
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004948static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004949{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004950 void __iomem *ioaddr = tp->mmio_addr;
4951 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004952 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004953 { 0x00, 0x0200, 0x0100 },
4954 { 0x00, 0x0000, 0x0004 },
4955 { 0x06, 0x0002, 0x0001 },
4956 { 0x06, 0x0000, 0x0030 },
4957 { 0x07, 0x0000, 0x2000 },
4958 { 0x00, 0x0000, 0x0020 },
4959 { 0x03, 0x5800, 0x2000 },
4960 { 0x03, 0x0000, 0x0001 },
4961 { 0x01, 0x0800, 0x1000 },
4962 { 0x07, 0x0000, 0x4000 },
4963 { 0x1e, 0x0000, 0x2000 },
4964 { 0x19, 0xffff, 0xfe6c },
4965 { 0x0a, 0x0000, 0x0040 }
4966 };
4967
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004968 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00004969
Francois Romieufdf6fc02012-07-06 22:40:38 +02004970 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00004971
4972 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4973
4974 RTL_W8(MaxTxPacketSize, TxPacketMax);
4975
4976 rtl_disable_clock_request(pdev);
4977
4978 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02004979 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
4980 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00004981
Francois Romieucecb5fd2011-04-01 10:21:07 +02004982 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00004983}
4984
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004985static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08004986{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004987 void __iomem *ioaddr = tp->mmio_addr;
4988 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004989 static const struct ephy_info e_info_8168e_2[] = {
4990 { 0x09, 0x0000, 0x0080 },
4991 { 0x19, 0x0000, 0x0224 }
4992 };
4993
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004994 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08004995
Francois Romieufdf6fc02012-07-06 22:40:38 +02004996 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08004997
4998 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4999
Francois Romieufdf6fc02012-07-06 22:40:38 +02005000 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5001 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5002 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5003 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5004 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5005 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5006 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5007 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005008
Hayes Wang3090bd92011-09-06 16:55:15 +08005009 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005010
5011 rtl_disable_clock_request(pdev);
5012
5013 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5014 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5015
5016 /* Adjust EEE LED frequency */
5017 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5018
5019 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5020 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5021 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5022}
5023
Hayes Wang5f886e02012-03-30 14:33:03 +08005024static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005025{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005026 void __iomem *ioaddr = tp->mmio_addr;
5027 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005028
Hayes Wang5f886e02012-03-30 14:33:03 +08005029 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005030
5031 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5032
Francois Romieufdf6fc02012-07-06 22:40:38 +02005033 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5034 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5035 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5036 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5037 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5038 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5039 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5040 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5041 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5042 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005043
5044 RTL_W8(MaxTxPacketSize, EarlySize);
5045
5046 rtl_disable_clock_request(pdev);
5047
5048 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5049 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005050 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5051 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5052 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5053}
5054
Hayes Wang5f886e02012-03-30 14:33:03 +08005055static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5056{
5057 void __iomem *ioaddr = tp->mmio_addr;
5058 static const struct ephy_info e_info_8168f_1[] = {
5059 { 0x06, 0x00c0, 0x0020 },
5060 { 0x08, 0x0001, 0x0002 },
5061 { 0x09, 0x0000, 0x0080 },
5062 { 0x19, 0x0000, 0x0224 }
5063 };
5064
5065 rtl_hw_start_8168f(tp);
5066
Francois Romieufdf6fc02012-07-06 22:40:38 +02005067 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005068
Francois Romieufdf6fc02012-07-06 22:40:38 +02005069 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005070
5071 /* Adjust EEE LED frequency */
5072 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5073}
5074
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005075static void rtl_hw_start_8411(struct rtl8169_private *tp)
5076{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005077 static const struct ephy_info e_info_8168f_1[] = {
5078 { 0x06, 0x00c0, 0x0020 },
5079 { 0x0f, 0xffff, 0x5200 },
5080 { 0x1e, 0x0000, 0x4000 },
5081 { 0x19, 0x0000, 0x0224 }
5082 };
5083
5084 rtl_hw_start_8168f(tp);
5085
Francois Romieufdf6fc02012-07-06 22:40:38 +02005086 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005087
Francois Romieufdf6fc02012-07-06 22:40:38 +02005088 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005089}
5090
Hayes Wangc5583862012-07-02 17:23:22 +08005091static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5092{
5093 void __iomem *ioaddr = tp->mmio_addr;
5094 struct pci_dev *pdev = tp->pci_dev;
5095
5096 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5097 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5098 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5099 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5100
5101 rtl_csi_access_enable_1(tp);
5102
5103 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5104
5105 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5106 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5107
5108 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5109 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
5110 RTL_W8(MaxTxPacketSize, EarlySize);
5111
5112 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5113 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5114
5115 /* Adjust EEE LED frequency */
5116 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5117
5118 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5119}
5120
Francois Romieu07ce4062007-02-23 23:36:39 +01005121static void rtl_hw_start_8168(struct net_device *dev)
5122{
Francois Romieu2dd99532007-06-11 23:22:52 +02005123 struct rtl8169_private *tp = netdev_priv(dev);
5124 void __iomem *ioaddr = tp->mmio_addr;
5125
5126 RTL_W8(Cfg9346, Cfg9346_Unlock);
5127
françois romieuf0298f82011-01-03 15:07:42 +00005128 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005129
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005130 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005131
Francois Romieu0e485152007-02-20 00:00:26 +01005132 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005133
5134 RTL_W16(CPlusCmd, tp->cp_cmd);
5135
Francois Romieu0e485152007-02-20 00:00:26 +01005136 RTL_W16(IntrMitigate, 0x5151);
5137
5138 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005139 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005140 tp->event_slow |= RxFIFOOver | PCSTimeout;
5141 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005142 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005143
5144 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5145
Francois Romieub8363902008-06-01 12:31:57 +02005146 rtl_set_rx_mode(dev);
5147
5148 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5149 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005150
5151 RTL_R8(IntrMask);
5152
Francois Romieu219a1e92008-06-28 11:58:39 +02005153 switch (tp->mac_version) {
5154 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005155 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005156 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005157
5158 case RTL_GIGA_MAC_VER_12:
5159 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005160 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005161 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005162
5163 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005164 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005165 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005166
5167 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005168 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005169 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005170
5171 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005172 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005173 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005174
Francois Romieu197ff762008-06-28 13:16:02 +02005175 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005176 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005177 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005178
Francois Romieu6fb07052008-06-29 11:54:28 +02005179 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005180 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005181 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005182
Francois Romieuef3386f2008-06-29 12:24:30 +02005183 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005184 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005185 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005186
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005187 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005188 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005189 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005190
Francois Romieu5b538df2008-07-20 16:22:45 +02005191 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005192 case RTL_GIGA_MAC_VER_26:
5193 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005194 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005195 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005196
françois romieue6de30d2011-01-03 15:08:37 +00005197 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005198 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005199 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005200
hayeswang4804b3b2011-03-21 01:50:29 +00005201 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005202 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005203 break;
5204
hayeswang01dc7fe2011-03-21 01:50:28 +00005205 case RTL_GIGA_MAC_VER_32:
5206 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005207 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005208 break;
5209 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005210 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005211 break;
françois romieue6de30d2011-01-03 15:08:37 +00005212
Hayes Wangc2218922011-09-06 16:55:18 +08005213 case RTL_GIGA_MAC_VER_35:
5214 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005215 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005216 break;
5217
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005218 case RTL_GIGA_MAC_VER_38:
5219 rtl_hw_start_8411(tp);
5220 break;
5221
Hayes Wangc5583862012-07-02 17:23:22 +08005222 case RTL_GIGA_MAC_VER_40:
5223 case RTL_GIGA_MAC_VER_41:
5224 rtl_hw_start_8168g_1(tp);
5225 break;
5226
Francois Romieu219a1e92008-06-28 11:58:39 +02005227 default:
5228 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5229 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005230 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005231 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005232
Francois Romieu0e485152007-02-20 00:00:26 +01005233 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5234
Francois Romieub8363902008-06-01 12:31:57 +02005235 RTL_W8(Cfg9346, Cfg9346_Lock);
5236
Francois Romieu2dd99532007-06-11 23:22:52 +02005237 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005238}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
Francois Romieu2857ffb2008-08-02 21:08:49 +02005240#define R810X_CPCMD_QUIRK_MASK (\
5241 EnableBist | \
5242 Mac_dbgo_oe | \
5243 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005244 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005245 Force_txflow_en | \
5246 Cxpl_dbg_sel | \
5247 ASF | \
5248 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005249 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005250
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005251static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005252{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005253 void __iomem *ioaddr = tp->mmio_addr;
5254 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005255 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005256 { 0x01, 0, 0x6e65 },
5257 { 0x02, 0, 0x091f },
5258 { 0x03, 0, 0xc2f9 },
5259 { 0x06, 0, 0xafb5 },
5260 { 0x07, 0, 0x0e00 },
5261 { 0x19, 0, 0xec80 },
5262 { 0x01, 0, 0x2e65 },
5263 { 0x01, 0, 0x6e65 }
5264 };
5265 u8 cfg1;
5266
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005267 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005268
5269 RTL_W8(DBG_REG, FIX_NAK_1);
5270
5271 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5272
5273 RTL_W8(Config1,
5274 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5275 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5276
5277 cfg1 = RTL_R8(Config1);
5278 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5279 RTL_W8(Config1, cfg1 & ~LEDS0);
5280
Francois Romieufdf6fc02012-07-06 22:40:38 +02005281 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005282}
5283
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005284static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005285{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005286 void __iomem *ioaddr = tp->mmio_addr;
5287 struct pci_dev *pdev = tp->pci_dev;
5288
5289 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005290
5291 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5292
5293 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5294 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005295}
5296
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005297static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005298{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005299 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005300
Francois Romieufdf6fc02012-07-06 22:40:38 +02005301 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005302}
5303
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005304static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005305{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005306 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005307 static const struct ephy_info e_info_8105e_1[] = {
5308 { 0x07, 0, 0x4000 },
5309 { 0x19, 0, 0x0200 },
5310 { 0x19, 0, 0x0020 },
5311 { 0x1e, 0, 0x2000 },
5312 { 0x03, 0, 0x0001 },
5313 { 0x19, 0, 0x0100 },
5314 { 0x19, 0, 0x0004 },
5315 { 0x0a, 0, 0x0020 }
5316 };
5317
Francois Romieucecb5fd2011-04-01 10:21:07 +02005318 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005319 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5320
Francois Romieucecb5fd2011-04-01 10:21:07 +02005321 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005322 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5323
5324 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e52011-07-06 15:58:02 +08005325 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005326
Francois Romieufdf6fc02012-07-06 22:40:38 +02005327 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005328}
5329
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005330static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005331{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005332 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005333 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005334}
5335
Hayes Wang7e18dca2012-03-30 14:33:02 +08005336static void rtl_hw_start_8402(struct rtl8169_private *tp)
5337{
5338 void __iomem *ioaddr = tp->mmio_addr;
5339 static const struct ephy_info e_info_8402[] = {
5340 { 0x19, 0xffff, 0xff64 },
5341 { 0x1e, 0, 0x4000 }
5342 };
5343
5344 rtl_csi_access_enable_2(tp);
5345
5346 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5347 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5348
5349 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5350 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5351
Francois Romieufdf6fc02012-07-06 22:40:38 +02005352 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005353
5354 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5355
Francois Romieufdf6fc02012-07-06 22:40:38 +02005356 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5357 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5358 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5359 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5360 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5361 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5362 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005363}
5364
Hayes Wang5598bfe2012-07-02 17:23:21 +08005365static void rtl_hw_start_8106(struct rtl8169_private *tp)
5366{
5367 void __iomem *ioaddr = tp->mmio_addr;
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(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
5373 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5374 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5375}
5376
Francois Romieu07ce4062007-02-23 23:36:39 +01005377static void rtl_hw_start_8101(struct net_device *dev)
5378{
Francois Romieucdf1a602007-06-11 23:29:50 +02005379 struct rtl8169_private *tp = netdev_priv(dev);
5380 void __iomem *ioaddr = tp->mmio_addr;
5381 struct pci_dev *pdev = tp->pci_dev;
5382
Francois Romieuda78dbf2012-01-26 14:18:23 +01005383 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5384 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005385
Francois Romieucecb5fd2011-04-01 10:21:07 +02005386 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
Jiang Liu7d7903b2012-07-24 17:20:16 +08005387 tp->mac_version == RTL_GIGA_MAC_VER_16)
Bjorn Helgaas8200bc72012-08-22 10:29:42 -06005388 pcie_capability_set_word(pdev, PCI_EXP_DEVCTL,
5389 PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieucdf1a602007-06-11 23:29:50 +02005390
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005391 RTL_W8(Cfg9346, Cfg9346_Unlock);
5392
Francois Romieu2857ffb2008-08-02 21:08:49 +02005393 switch (tp->mac_version) {
5394 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005395 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005396 break;
5397
5398 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005399 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005400 break;
5401
5402 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005403 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005404 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005405
5406 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005407 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005408 break;
5409 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005410 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005411 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005412
5413 case RTL_GIGA_MAC_VER_37:
5414 rtl_hw_start_8402(tp);
5415 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005416
5417 case RTL_GIGA_MAC_VER_39:
5418 rtl_hw_start_8106(tp);
5419 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005420 }
5421
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005422 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005423
françois romieuf0298f82011-01-03 15:07:42 +00005424 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005425
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005426 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005427
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005428 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005429 RTL_W16(CPlusCmd, tp->cp_cmd);
5430
5431 RTL_W16(IntrMitigate, 0x0000);
5432
5433 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5434
5435 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5436 rtl_set_rx_tx_config_registers(tp);
5437
Francois Romieucdf1a602007-06-11 23:29:50 +02005438 RTL_R8(IntrMask);
5439
Francois Romieucdf1a602007-06-11 23:29:50 +02005440 rtl_set_rx_mode(dev);
5441
5442 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443}
5444
5445static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5446{
Francois Romieud58d46b2011-05-03 16:38:29 +02005447 struct rtl8169_private *tp = netdev_priv(dev);
5448
5449 if (new_mtu < ETH_ZLEN ||
5450 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 return -EINVAL;
5452
Francois Romieud58d46b2011-05-03 16:38:29 +02005453 if (new_mtu > ETH_DATA_LEN)
5454 rtl_hw_jumbo_enable(tp);
5455 else
5456 rtl_hw_jumbo_disable(tp);
5457
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005459 netdev_update_features(dev);
5460
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005461 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462}
5463
5464static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5465{
Al Viro95e09182007-12-22 18:55:39 +00005466 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5468}
5469
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005470static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5471 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005473 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005474 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005475
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005476 kfree(*data_buff);
5477 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 rtl8169_make_unusable_by_asic(desc);
5479}
5480
5481static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5482{
5483 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5484
5485 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5486}
5487
5488static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5489 u32 rx_buf_sz)
5490{
5491 desc->addr = cpu_to_le64(mapping);
5492 wmb();
5493 rtl8169_mark_to_asic(desc, rx_buf_sz);
5494}
5495
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005496static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005498 return (void *)ALIGN((long)data, 16);
5499}
5500
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005501static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5502 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005503{
5504 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005506 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005507 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005508 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005510 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5511 if (!data)
5512 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005513
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005514 if (rtl8169_align(data) != data) {
5515 kfree(data);
5516 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5517 if (!data)
5518 return NULL;
5519 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005520
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005521 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005522 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005523 if (unlikely(dma_mapping_error(d, mapping))) {
5524 if (net_ratelimit())
5525 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005526 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
5529 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005530 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005531
5532err_out:
5533 kfree(data);
5534 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535}
5536
5537static void rtl8169_rx_clear(struct rtl8169_private *tp)
5538{
Francois Romieu07d3f512007-02-21 22:40:46 +01005539 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
5541 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005542 if (tp->Rx_databuff[i]) {
5543 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 tp->RxDescArray + i);
5545 }
5546 }
5547}
5548
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005549static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005551 desc->opts1 |= cpu_to_le32(RingEnd);
5552}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005553
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005554static int rtl8169_rx_fill(struct rtl8169_private *tp)
5555{
5556 unsigned int i;
5557
5558 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005559 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005560
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005561 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005563
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005564 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005565 if (!data) {
5566 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005567 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005568 }
5569 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005572 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5573 return 0;
5574
5575err_out:
5576 rtl8169_rx_clear(tp);
5577 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578}
5579
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580static int rtl8169_init_ring(struct net_device *dev)
5581{
5582 struct rtl8169_private *tp = netdev_priv(dev);
5583
5584 rtl8169_init_ring_indexes(tp);
5585
5586 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005587 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005589 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590}
5591
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005592static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 struct TxDesc *desc)
5594{
5595 unsigned int len = tx_skb->len;
5596
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005597 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5598
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 desc->opts1 = 0x00;
5600 desc->opts2 = 0x00;
5601 desc->addr = 0x00;
5602 tx_skb->len = 0;
5603}
5604
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005605static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5606 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607{
5608 unsigned int i;
5609
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005610 for (i = 0; i < n; i++) {
5611 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 struct ring_info *tx_skb = tp->tx_skb + entry;
5613 unsigned int len = tx_skb->len;
5614
5615 if (len) {
5616 struct sk_buff *skb = tx_skb->skb;
5617
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005618 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 tp->TxDescArray + entry);
5620 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005621 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 dev_kfree_skb(skb);
5623 tx_skb->skb = NULL;
5624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 }
5626 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005627}
5628
5629static void rtl8169_tx_clear(struct rtl8169_private *tp)
5630{
5631 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 tp->cur_tx = tp->dirty_tx = 0;
5633}
5634
Francois Romieu4422bcd2012-01-26 11:23:32 +01005635static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636{
David Howellsc4028952006-11-22 14:57:56 +00005637 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005638 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639
Francois Romieuda78dbf2012-01-26 14:18:23 +01005640 napi_disable(&tp->napi);
5641 netif_stop_queue(dev);
5642 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
françois romieuc7c2c392011-12-04 20:30:52 +00005644 rtl8169_hw_reset(tp);
5645
Francois Romieu56de4142011-03-15 17:29:31 +01005646 for (i = 0; i < NUM_RX_DESC; i++)
5647 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5648
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005650 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Francois Romieuda78dbf2012-01-26 14:18:23 +01005652 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005653 rtl_hw_start(dev);
5654 netif_wake_queue(dev);
5655 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656}
5657
5658static void rtl8169_tx_timeout(struct net_device *dev)
5659{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005660 struct rtl8169_private *tp = netdev_priv(dev);
5661
5662 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663}
5664
5665static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005666 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667{
5668 struct skb_shared_info *info = skb_shinfo(skb);
5669 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005670 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005671 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672
5673 entry = tp->cur_tx;
5674 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005675 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 dma_addr_t mapping;
5677 u32 status, len;
5678 void *addr;
5679
5680 entry = (entry + 1) % NUM_TX_DESC;
5681
5682 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005683 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005684 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005685 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005686 if (unlikely(dma_mapping_error(d, mapping))) {
5687 if (net_ratelimit())
5688 netif_err(tp, drv, tp->dev,
5689 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005690 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
Francois Romieucecb5fd2011-04-01 10:21:07 +02005693 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005694 status = opts[0] | len |
5695 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696
5697 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005698 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 txd->addr = cpu_to_le64(mapping);
5700
5701 tp->tx_skb[entry].len = len;
5702 }
5703
5704 if (cur_frag) {
5705 tp->tx_skb[entry].skb = skb;
5706 txd->opts1 |= cpu_to_le32(LastFrag);
5707 }
5708
5709 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005710
5711err_out:
5712 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5713 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714}
5715
Francois Romieu2b7b4312011-04-18 22:53:24 -07005716static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5717 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005719 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005720 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005721 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Francois Romieu2b7b4312011-04-18 22:53:24 -07005723 if (mss) {
5724 opts[0] |= TD_LSO;
5725 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5726 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005727 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
5729 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005730 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005732 opts[offset] |= info->checksum.udp;
5733 else
5734 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736}
5737
Stephen Hemminger613573252009-08-31 19:50:58 +00005738static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5739 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740{
5741 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005742 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 struct TxDesc *txd = tp->TxDescArray + entry;
5744 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005745 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 dma_addr_t mapping;
5747 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005748 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005749 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005750
Julien Ducourthial477206a2012-05-09 00:00:06 +02005751 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005752 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005753 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754 }
5755
5756 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005757 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005759 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005760 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005761 if (unlikely(dma_mapping_error(d, mapping))) {
5762 if (net_ratelimit())
5763 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005764 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
5767 tp->tx_skb[entry].len = len;
5768 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769
Francois Romieu2b7b4312011-04-18 22:53:24 -07005770 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
5771 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005772
Francois Romieu2b7b4312011-04-18 22:53:24 -07005773 rtl8169_tso_csum(tp, skb, opts);
5774
5775 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005776 if (frags < 0)
5777 goto err_dma_1;
5778 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005779 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005780 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005781 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005782 tp->tx_skb[entry].skb = skb;
5783 }
5784
Francois Romieu2b7b4312011-04-18 22:53:24 -07005785 txd->opts2 = cpu_to_le32(opts[1]);
5786
Richard Cochran5047fb52012-03-10 07:29:42 +00005787 skb_tx_timestamp(skb);
5788
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 wmb();
5790
Francois Romieucecb5fd2011-04-01 10:21:07 +02005791 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005792 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 txd->opts1 = cpu_to_le32(status);
5794
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795 tp->cur_tx += frags + 1;
5796
David Dillow4c020a92010-03-03 16:33:10 +00005797 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
Francois Romieucecb5fd2011-04-01 10:21:07 +02005799 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
Francois Romieuda78dbf2012-01-26 14:18:23 +01005801 mmiowb();
5802
Julien Ducourthial477206a2012-05-09 00:00:06 +02005803 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005804 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5805 * not miss a ring update when it notices a stopped queue.
5806 */
5807 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005809 /* Sync with rtl_tx:
5810 * - publish queue status and cur_tx ring index (write barrier)
5811 * - refresh dirty_tx ring index (read barrier).
5812 * May the current thread have a pessimistic view of the ring
5813 * status and forget to wake up queue, a racing rtl_tx thread
5814 * can't.
5815 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005816 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005817 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818 netif_wake_queue(dev);
5819 }
5820
Stephen Hemminger613573252009-08-31 19:50:58 +00005821 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005823err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005824 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005825err_dma_0:
5826 dev_kfree_skb(skb);
5827 dev->stats.tx_dropped++;
5828 return NETDEV_TX_OK;
5829
5830err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005832 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005833 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834}
5835
5836static void rtl8169_pcierr_interrupt(struct net_device *dev)
5837{
5838 struct rtl8169_private *tp = netdev_priv(dev);
5839 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 u16 pci_status, pci_cmd;
5841
5842 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5843 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5844
Joe Perchesbf82c182010-02-09 11:49:50 +00005845 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5846 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 /*
5849 * The recovery sequence below admits a very elaborated explanation:
5850 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005851 * - I did not see what else could be done;
5852 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 *
5854 * Feel free to adjust to your needs.
5855 */
Francois Romieua27993f2006-12-18 00:04:19 +01005856 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005857 pci_cmd &= ~PCI_COMMAND_PARITY;
5858 else
5859 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5860
5861 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
5863 pci_write_config_word(pdev, PCI_STATUS,
5864 pci_status & (PCI_STATUS_DETECTED_PARITY |
5865 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5866 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5867
5868 /* The infamous DAC f*ckup only happens at boot time */
5869 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005870 void __iomem *ioaddr = tp->mmio_addr;
5871
Joe Perchesbf82c182010-02-09 11:49:50 +00005872 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 tp->cp_cmd &= ~PCIDAC;
5874 RTL_W16(CPlusCmd, tp->cp_cmd);
5875 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 }
5877
françois romieue6de30d2011-01-03 15:08:37 +00005878 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005879
Francois Romieu98ddf982012-01-31 10:47:34 +01005880 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881}
5882
Francois Romieuda78dbf2012-01-26 14:18:23 +01005883static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884{
5885 unsigned int dirty_tx, tx_left;
5886
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 dirty_tx = tp->dirty_tx;
5888 smp_rmb();
5889 tx_left = tp->cur_tx - dirty_tx;
5890
5891 while (tx_left > 0) {
5892 unsigned int entry = dirty_tx % NUM_TX_DESC;
5893 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 u32 status;
5895
5896 rmb();
5897 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5898 if (status & DescOwn)
5899 break;
5900
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005901 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5902 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005904 u64_stats_update_begin(&tp->tx_stats.syncp);
5905 tp->tx_stats.packets++;
5906 tp->tx_stats.bytes += tx_skb->skb->len;
5907 u64_stats_update_end(&tp->tx_stats.syncp);
5908 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 tx_skb->skb = NULL;
5910 }
5911 dirty_tx++;
5912 tx_left--;
5913 }
5914
5915 if (tp->dirty_tx != dirty_tx) {
5916 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005917 /* Sync with rtl8169_start_xmit:
5918 * - publish dirty_tx ring index (write barrier)
5919 * - refresh cur_tx ring index and queue status (read barrier)
5920 * May the current thread miss the stopped queue condition,
5921 * a racing xmit thread can only have a right view of the
5922 * ring status.
5923 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005924 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005926 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 netif_wake_queue(dev);
5928 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005929 /*
5930 * 8168 hack: TxPoll requests are lost when the Tx packets are
5931 * too close. Let's kick an extra TxPoll request when a burst
5932 * of start_xmit activity is detected (if it is not detected,
5933 * it is slow enough). -- FR
5934 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005935 if (tp->cur_tx != dirty_tx) {
5936 void __iomem *ioaddr = tp->mmio_addr;
5937
Francois Romieud78ae2d2007-08-26 20:08:19 +02005938 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 }
5941}
5942
Francois Romieu126fa4b2005-05-12 20:09:17 -04005943static inline int rtl8169_fragmented_frame(u32 status)
5944{
5945 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5946}
5947
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005948static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 u32 status = opts1 & RxProtoMask;
5951
5952 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005953 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 skb->ip_summed = CHECKSUM_UNNECESSARY;
5955 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005956 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957}
5958
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005959static struct sk_buff *rtl8169_try_rx_copy(void *data,
5960 struct rtl8169_private *tp,
5961 int pkt_size,
5962 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02005964 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005965 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005967 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005968 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005969 prefetch(data);
5970 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
5971 if (skb)
5972 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005973 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
5974
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005975 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976}
5977
Francois Romieuda78dbf2012-01-26 14:18:23 +01005978static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979{
5980 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005981 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 cur_rx = tp->cur_rx;
5984 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02005985 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Richard Dawe4dcb7d32005-05-27 21:12:00 +02005987 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04005989 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 u32 status;
5991
5992 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04005993 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
5995 if (status & DescOwn)
5996 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02005997 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005998 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
5999 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006000 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006002 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006004 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006005 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006006 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006007 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006008 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006009 if ((status & (RxRUNT | RxCRC)) &&
6010 !(status & (RxRWT | RxFOVF)) &&
6011 (dev->features & NETIF_F_RXALL))
6012 goto process_pkt;
6013
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006014 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006016 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006017 dma_addr_t addr;
6018 int pkt_size;
6019
6020process_pkt:
6021 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006022 if (likely(!(dev->features & NETIF_F_RXFCS)))
6023 pkt_size = (status & 0x00003fff) - 4;
6024 else
6025 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
Francois Romieu126fa4b2005-05-12 20:09:17 -04006027 /*
6028 * The driver does not support incoming fragmented
6029 * frames. They are seen as a symptom of over-mtu
6030 * sized frames.
6031 */
6032 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006033 dev->stats.rx_dropped++;
6034 dev->stats.rx_length_errors++;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006035 rtl8169_mark_to_asic(desc, rx_buf_sz);
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006036 continue;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006037 }
6038
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006039 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6040 tp, pkt_size, addr);
6041 rtl8169_mark_to_asic(desc, rx_buf_sz);
6042 if (!skb) {
6043 dev->stats.rx_dropped++;
6044 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 }
6046
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006047 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 skb_put(skb, pkt_size);
6049 skb->protocol = eth_type_trans(skb, dev);
6050
Francois Romieu7a8fc772011-03-01 17:18:33 +01006051 rtl8169_rx_vlan_tag(desc, skb);
6052
Francois Romieu56de4142011-03-15 17:29:31 +01006053 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Junchang Wang8027aa22012-03-04 23:30:32 +01006055 u64_stats_update_begin(&tp->rx_stats.syncp);
6056 tp->rx_stats.packets++;
6057 tp->rx_stats.bytes += pkt_size;
6058 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 }
Francois Romieu6dccd162007-02-13 23:38:05 +01006060
6061 /* Work around for AMD plateform. */
Al Viro95e09182007-12-22 18:55:39 +00006062 if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
Francois Romieu6dccd162007-02-13 23:38:05 +01006063 (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
6064 desc->opts2 = 0;
6065 cur_rx++;
6066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 }
6068
6069 count = cur_rx - tp->cur_rx;
6070 tp->cur_rx = cur_rx;
6071
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006072 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073
6074 return count;
6075}
6076
Francois Romieu07d3f512007-02-21 22:40:46 +01006077static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078{
Francois Romieu07d3f512007-02-21 22:40:46 +01006079 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006082 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006084 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006085 if (status && status != 0xffff) {
6086 status &= RTL_EVENT_NAPI | tp->event_slow;
6087 if (status) {
6088 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006089
Francois Romieuda78dbf2012-01-26 14:18:23 +01006090 rtl_irq_disable(tp);
6091 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 return IRQ_RETVAL(handled);
6095}
6096
Francois Romieuda78dbf2012-01-26 14:18:23 +01006097/*
6098 * Workqueue context.
6099 */
6100static void rtl_slow_event_work(struct rtl8169_private *tp)
6101{
6102 struct net_device *dev = tp->dev;
6103 u16 status;
6104
6105 status = rtl_get_events(tp) & tp->event_slow;
6106 rtl_ack_events(tp, status);
6107
6108 if (unlikely(status & RxFIFOOver)) {
6109 switch (tp->mac_version) {
6110 /* Work around for rx fifo overflow */
6111 case RTL_GIGA_MAC_VER_11:
6112 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006113 /* XXX - Hack alert. See rtl_task(). */
6114 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006115 default:
6116 break;
6117 }
6118 }
6119
6120 if (unlikely(status & SYSErr))
6121 rtl8169_pcierr_interrupt(dev);
6122
6123 if (status & LinkChg)
6124 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6125
françois romieu7dbb4912012-06-09 10:53:16 +00006126 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006127}
6128
Francois Romieu4422bcd2012-01-26 11:23:32 +01006129static void rtl_task(struct work_struct *work)
6130{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006131 static const struct {
6132 int bitnr;
6133 void (*action)(struct rtl8169_private *);
6134 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006135 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006136 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6137 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6138 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6139 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006140 struct rtl8169_private *tp =
6141 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006142 struct net_device *dev = tp->dev;
6143 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006144
Francois Romieuda78dbf2012-01-26 14:18:23 +01006145 rtl_lock_work(tp);
6146
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006147 if (!netif_running(dev) ||
6148 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006149 goto out_unlock;
6150
6151 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6152 bool pending;
6153
Francois Romieuda78dbf2012-01-26 14:18:23 +01006154 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006155 if (pending)
6156 rtl_work[i].action(tp);
6157 }
6158
6159out_unlock:
6160 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006161}
6162
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006163static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006165 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6166 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006167 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6168 int work_done= 0;
6169 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170
Francois Romieuda78dbf2012-01-26 14:18:23 +01006171 status = rtl_get_events(tp);
6172 rtl_ack_events(tp, status & ~tp->event_slow);
6173
6174 if (status & RTL_EVENT_NAPI_RX)
6175 work_done = rtl_rx(dev, tp, (u32) budget);
6176
6177 if (status & RTL_EVENT_NAPI_TX)
6178 rtl_tx(dev, tp);
6179
6180 if (status & tp->event_slow) {
6181 enable_mask &= ~tp->event_slow;
6182
6183 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006186 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006187 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006188
Francois Romieuda78dbf2012-01-26 14:18:23 +01006189 rtl_irq_enable(tp, enable_mask);
6190 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 }
6192
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006193 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195
Francois Romieu523a6092008-09-10 22:28:56 +02006196static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6197{
6198 struct rtl8169_private *tp = netdev_priv(dev);
6199
6200 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6201 return;
6202
6203 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6204 RTL_W32(RxMissed, 0);
6205}
6206
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207static void rtl8169_down(struct net_device *dev)
6208{
6209 struct rtl8169_private *tp = netdev_priv(dev);
6210 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Francois Romieu4876cc12011-03-11 21:07:11 +01006212 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006214 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006215 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216
Hayes Wang92fc43b2011-07-06 15:58:03 +08006217 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006218 /*
6219 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006220 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6221 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006222 */
Francois Romieu523a6092008-09-10 22:28:56 +02006223 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006226 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 rtl8169_tx_clear(tp);
6229
6230 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006231
6232 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233}
6234
6235static int rtl8169_close(struct net_device *dev)
6236{
6237 struct rtl8169_private *tp = netdev_priv(dev);
6238 struct pci_dev *pdev = tp->pci_dev;
6239
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006240 pm_runtime_get_sync(&pdev->dev);
6241
Francois Romieucecb5fd2011-04-01 10:21:07 +02006242 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006243 rtl8169_update_counters(dev);
6244
Francois Romieuda78dbf2012-01-26 14:18:23 +01006245 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006246 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006247
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006249 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006251 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006253 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6254 tp->RxPhyAddr);
6255 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6256 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 tp->TxDescArray = NULL;
6258 tp->RxDescArray = NULL;
6259
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006260 pm_runtime_put_sync(&pdev->dev);
6261
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 return 0;
6263}
6264
Francois Romieudc1c00c2012-03-08 10:06:18 +01006265#ifdef CONFIG_NET_POLL_CONTROLLER
6266static void rtl8169_netpoll(struct net_device *dev)
6267{
6268 struct rtl8169_private *tp = netdev_priv(dev);
6269
6270 rtl8169_interrupt(tp->pci_dev->irq, dev);
6271}
6272#endif
6273
Francois Romieudf43ac72012-03-08 09:48:40 +01006274static int rtl_open(struct net_device *dev)
6275{
6276 struct rtl8169_private *tp = netdev_priv(dev);
6277 void __iomem *ioaddr = tp->mmio_addr;
6278 struct pci_dev *pdev = tp->pci_dev;
6279 int retval = -ENOMEM;
6280
6281 pm_runtime_get_sync(&pdev->dev);
6282
6283 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006284 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006285 * dma_alloc_coherent provides more.
6286 */
6287 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6288 &tp->TxPhyAddr, GFP_KERNEL);
6289 if (!tp->TxDescArray)
6290 goto err_pm_runtime_put;
6291
6292 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6293 &tp->RxPhyAddr, GFP_KERNEL);
6294 if (!tp->RxDescArray)
6295 goto err_free_tx_0;
6296
6297 retval = rtl8169_init_ring(dev);
6298 if (retval < 0)
6299 goto err_free_rx_1;
6300
6301 INIT_WORK(&tp->wk.work, rtl_task);
6302
6303 smp_mb();
6304
6305 rtl_request_firmware(tp);
6306
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006307 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006308 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6309 dev->name, dev);
6310 if (retval < 0)
6311 goto err_release_fw_2;
6312
6313 rtl_lock_work(tp);
6314
6315 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6316
6317 napi_enable(&tp->napi);
6318
6319 rtl8169_init_phy(dev, tp);
6320
6321 __rtl8169_set_features(dev, dev->features);
6322
6323 rtl_pll_power_up(tp);
6324
6325 rtl_hw_start(dev);
6326
6327 netif_start_queue(dev);
6328
6329 rtl_unlock_work(tp);
6330
6331 tp->saved_wolopts = 0;
6332 pm_runtime_put_noidle(&pdev->dev);
6333
6334 rtl8169_check_link_status(dev, tp, ioaddr);
6335out:
6336 return retval;
6337
6338err_release_fw_2:
6339 rtl_release_firmware(tp);
6340 rtl8169_rx_clear(tp);
6341err_free_rx_1:
6342 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6343 tp->RxPhyAddr);
6344 tp->RxDescArray = NULL;
6345err_free_tx_0:
6346 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6347 tp->TxPhyAddr);
6348 tp->TxDescArray = NULL;
6349err_pm_runtime_put:
6350 pm_runtime_put_noidle(&pdev->dev);
6351 goto out;
6352}
6353
Junchang Wang8027aa22012-03-04 23:30:32 +01006354static struct rtnl_link_stats64 *
6355rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356{
6357 struct rtl8169_private *tp = netdev_priv(dev);
6358 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006359 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360
Francois Romieuda78dbf2012-01-26 14:18:23 +01006361 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006362 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006363
Junchang Wang8027aa22012-03-04 23:30:32 +01006364 do {
6365 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6366 stats->rx_packets = tp->rx_stats.packets;
6367 stats->rx_bytes = tp->rx_stats.bytes;
6368 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6369
6370
6371 do {
6372 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6373 stats->tx_packets = tp->tx_stats.packets;
6374 stats->tx_bytes = tp->tx_stats.bytes;
6375 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6376
6377 stats->rx_dropped = dev->stats.rx_dropped;
6378 stats->tx_dropped = dev->stats.tx_dropped;
6379 stats->rx_length_errors = dev->stats.rx_length_errors;
6380 stats->rx_errors = dev->stats.rx_errors;
6381 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6382 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6383 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6384
6385 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386}
6387
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006388static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006389{
françois romieu065c27c2011-01-03 15:08:12 +00006390 struct rtl8169_private *tp = netdev_priv(dev);
6391
Francois Romieu5d06a992006-02-23 00:47:58 +01006392 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006393 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006394
6395 netif_device_detach(dev);
6396 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006397
6398 rtl_lock_work(tp);
6399 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006400 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006401 rtl_unlock_work(tp);
6402
6403 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006404}
Francois Romieu5d06a992006-02-23 00:47:58 +01006405
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006406#ifdef CONFIG_PM
6407
6408static int rtl8169_suspend(struct device *device)
6409{
6410 struct pci_dev *pdev = to_pci_dev(device);
6411 struct net_device *dev = pci_get_drvdata(pdev);
6412
6413 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006414
Francois Romieu5d06a992006-02-23 00:47:58 +01006415 return 0;
6416}
6417
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006418static void __rtl8169_resume(struct net_device *dev)
6419{
françois romieu065c27c2011-01-03 15:08:12 +00006420 struct rtl8169_private *tp = netdev_priv(dev);
6421
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006422 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006423
6424 rtl_pll_power_up(tp);
6425
Artem Savkovcff4c162012-04-03 10:29:11 +00006426 rtl_lock_work(tp);
6427 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006428 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006429 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006430
Francois Romieu98ddf982012-01-31 10:47:34 +01006431 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006432}
6433
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006434static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006435{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006436 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006437 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006438 struct rtl8169_private *tp = netdev_priv(dev);
6439
6440 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006441
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006442 if (netif_running(dev))
6443 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006444
Francois Romieu5d06a992006-02-23 00:47:58 +01006445 return 0;
6446}
6447
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006448static int rtl8169_runtime_suspend(struct device *device)
6449{
6450 struct pci_dev *pdev = to_pci_dev(device);
6451 struct net_device *dev = pci_get_drvdata(pdev);
6452 struct rtl8169_private *tp = netdev_priv(dev);
6453
6454 if (!tp->TxDescArray)
6455 return 0;
6456
Francois Romieuda78dbf2012-01-26 14:18:23 +01006457 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006458 tp->saved_wolopts = __rtl8169_get_wol(tp);
6459 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006460 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006461
6462 rtl8169_net_suspend(dev);
6463
6464 return 0;
6465}
6466
6467static int rtl8169_runtime_resume(struct device *device)
6468{
6469 struct pci_dev *pdev = to_pci_dev(device);
6470 struct net_device *dev = pci_get_drvdata(pdev);
6471 struct rtl8169_private *tp = netdev_priv(dev);
6472
6473 if (!tp->TxDescArray)
6474 return 0;
6475
Francois Romieuda78dbf2012-01-26 14:18:23 +01006476 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006477 __rtl8169_set_wol(tp, tp->saved_wolopts);
6478 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006479 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006480
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006481 rtl8169_init_phy(dev, tp);
6482
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006483 __rtl8169_resume(dev);
6484
6485 return 0;
6486}
6487
6488static int rtl8169_runtime_idle(struct device *device)
6489{
6490 struct pci_dev *pdev = to_pci_dev(device);
6491 struct net_device *dev = pci_get_drvdata(pdev);
6492 struct rtl8169_private *tp = netdev_priv(dev);
6493
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006494 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006495}
6496
Alexey Dobriyan47145212009-12-14 18:00:08 -08006497static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006498 .suspend = rtl8169_suspend,
6499 .resume = rtl8169_resume,
6500 .freeze = rtl8169_suspend,
6501 .thaw = rtl8169_resume,
6502 .poweroff = rtl8169_suspend,
6503 .restore = rtl8169_resume,
6504 .runtime_suspend = rtl8169_runtime_suspend,
6505 .runtime_resume = rtl8169_runtime_resume,
6506 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006507};
6508
6509#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6510
6511#else /* !CONFIG_PM */
6512
6513#define RTL8169_PM_OPS NULL
6514
6515#endif /* !CONFIG_PM */
6516
David S. Miller1805b2f2011-10-24 18:18:09 -04006517static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6518{
6519 void __iomem *ioaddr = tp->mmio_addr;
6520
6521 /* WoL fails with 8168b when the receiver is disabled. */
6522 switch (tp->mac_version) {
6523 case RTL_GIGA_MAC_VER_11:
6524 case RTL_GIGA_MAC_VER_12:
6525 case RTL_GIGA_MAC_VER_17:
6526 pci_clear_master(tp->pci_dev);
6527
6528 RTL_W8(ChipCmd, CmdRxEnb);
6529 /* PCI commit */
6530 RTL_R8(ChipCmd);
6531 break;
6532 default:
6533 break;
6534 }
6535}
6536
Francois Romieu1765f952008-09-13 17:21:40 +02006537static void rtl_shutdown(struct pci_dev *pdev)
6538{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006539 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006540 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006541 struct device *d = &pdev->dev;
6542
6543 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006544
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006545 rtl8169_net_suspend(dev);
6546
Francois Romieucecb5fd2011-04-01 10:21:07 +02006547 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006548 rtl_rar_set(tp, dev->perm_addr);
6549
Hayes Wang92fc43b2011-07-06 15:58:03 +08006550 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006551
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006552 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006553 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6554 rtl_wol_suspend_quirk(tp);
6555 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006556 }
6557
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006558 pci_wake_from_d3(pdev, true);
6559 pci_set_power_state(pdev, PCI_D3hot);
6560 }
françois romieu2a15cd22012-03-06 01:14:12 +00006561
6562 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006563}
Francois Romieu5d06a992006-02-23 00:47:58 +01006564
Francois Romieue27566e2012-03-08 09:54:01 +01006565static void __devexit rtl_remove_one(struct pci_dev *pdev)
6566{
6567 struct net_device *dev = pci_get_drvdata(pdev);
6568 struct rtl8169_private *tp = netdev_priv(dev);
6569
6570 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6571 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6572 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6573 rtl8168_driver_stop(tp);
6574 }
6575
6576 cancel_work_sync(&tp->wk.work);
6577
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006578 netif_napi_del(&tp->napi);
6579
Francois Romieue27566e2012-03-08 09:54:01 +01006580 unregister_netdev(dev);
6581
6582 rtl_release_firmware(tp);
6583
6584 if (pci_dev_run_wake(pdev))
6585 pm_runtime_get_noresume(&pdev->dev);
6586
6587 /* restore original MAC address */
6588 rtl_rar_set(tp, dev->perm_addr);
6589
6590 rtl_disable_msi(pdev, tp);
6591 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6592 pci_set_drvdata(pdev, NULL);
6593}
6594
Francois Romieufa9c3852012-03-08 10:01:50 +01006595static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006596 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006597 .ndo_stop = rtl8169_close,
6598 .ndo_get_stats64 = rtl8169_get_stats64,
6599 .ndo_start_xmit = rtl8169_start_xmit,
6600 .ndo_tx_timeout = rtl8169_tx_timeout,
6601 .ndo_validate_addr = eth_validate_addr,
6602 .ndo_change_mtu = rtl8169_change_mtu,
6603 .ndo_fix_features = rtl8169_fix_features,
6604 .ndo_set_features = rtl8169_set_features,
6605 .ndo_set_mac_address = rtl_set_mac_address,
6606 .ndo_do_ioctl = rtl8169_ioctl,
6607 .ndo_set_rx_mode = rtl_set_rx_mode,
6608#ifdef CONFIG_NET_POLL_CONTROLLER
6609 .ndo_poll_controller = rtl8169_netpoll,
6610#endif
6611
6612};
6613
Francois Romieu31fa8b12012-03-08 10:09:40 +01006614static const struct rtl_cfg_info {
6615 void (*hw_start)(struct net_device *);
6616 unsigned int region;
6617 unsigned int align;
6618 u16 event_slow;
6619 unsigned features;
6620 u8 default_ver;
6621} rtl_cfg_infos [] = {
6622 [RTL_CFG_0] = {
6623 .hw_start = rtl_hw_start_8169,
6624 .region = 1,
6625 .align = 0,
6626 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6627 .features = RTL_FEATURE_GMII,
6628 .default_ver = RTL_GIGA_MAC_VER_01,
6629 },
6630 [RTL_CFG_1] = {
6631 .hw_start = rtl_hw_start_8168,
6632 .region = 2,
6633 .align = 8,
6634 .event_slow = SYSErr | LinkChg | RxOverflow,
6635 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6636 .default_ver = RTL_GIGA_MAC_VER_11,
6637 },
6638 [RTL_CFG_2] = {
6639 .hw_start = rtl_hw_start_8101,
6640 .region = 2,
6641 .align = 8,
6642 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6643 PCSTimeout,
6644 .features = RTL_FEATURE_MSI,
6645 .default_ver = RTL_GIGA_MAC_VER_13,
6646 }
6647};
6648
6649/* Cfg9346_Unlock assumed. */
6650static unsigned rtl_try_msi(struct rtl8169_private *tp,
6651 const struct rtl_cfg_info *cfg)
6652{
6653 void __iomem *ioaddr = tp->mmio_addr;
6654 unsigned msi = 0;
6655 u8 cfg2;
6656
6657 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6658 if (cfg->features & RTL_FEATURE_MSI) {
6659 if (pci_enable_msi(tp->pci_dev)) {
6660 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6661 } else {
6662 cfg2 |= MSIEnable;
6663 msi = RTL_FEATURE_MSI;
6664 }
6665 }
6666 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6667 RTL_W8(Config2, cfg2);
6668 return msi;
6669}
6670
Hayes Wangc5583862012-07-02 17:23:22 +08006671DECLARE_RTL_COND(rtl_link_list_ready_cond)
6672{
6673 void __iomem *ioaddr = tp->mmio_addr;
6674
6675 return RTL_R8(MCU) & LINK_LIST_RDY;
6676}
6677
6678DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6679{
6680 void __iomem *ioaddr = tp->mmio_addr;
6681
6682 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6683}
6684
6685static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
6686{
6687 void __iomem *ioaddr = tp->mmio_addr;
6688 u32 data;
6689
6690 tp->ocp_base = OCP_STD_PHY_BASE;
6691
6692 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6693
6694 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6695 return;
6696
6697 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6698 return;
6699
6700 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6701 msleep(1);
6702 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6703
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006704 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006705 data &= ~(1 << 14);
6706 r8168_mac_ocp_write(tp, 0xe8de, data);
6707
6708 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6709 return;
6710
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006711 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006712 data |= (1 << 15);
6713 r8168_mac_ocp_write(tp, 0xe8de, data);
6714
6715 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6716 return;
6717}
6718
6719static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
6720{
6721 switch (tp->mac_version) {
6722 case RTL_GIGA_MAC_VER_40:
6723 case RTL_GIGA_MAC_VER_41:
6724 rtl_hw_init_8168g(tp);
6725 break;
6726
6727 default:
6728 break;
6729 }
6730}
6731
Francois Romieu3b6cf252012-03-08 09:59:04 +01006732static int __devinit
6733rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6734{
6735 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6736 const unsigned int region = cfg->region;
6737 struct rtl8169_private *tp;
6738 struct mii_if_info *mii;
6739 struct net_device *dev;
6740 void __iomem *ioaddr;
6741 int chipset, i;
6742 int rc;
6743
6744 if (netif_msg_drv(&debug)) {
6745 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6746 MODULENAME, RTL8169_VERSION);
6747 }
6748
6749 dev = alloc_etherdev(sizeof (*tp));
6750 if (!dev) {
6751 rc = -ENOMEM;
6752 goto out;
6753 }
6754
6755 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006756 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006757 tp = netdev_priv(dev);
6758 tp->dev = dev;
6759 tp->pci_dev = pdev;
6760 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6761
6762 mii = &tp->mii;
6763 mii->dev = dev;
6764 mii->mdio_read = rtl_mdio_read;
6765 mii->mdio_write = rtl_mdio_write;
6766 mii->phy_id_mask = 0x1f;
6767 mii->reg_num_mask = 0x1f;
6768 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6769
6770 /* disable ASPM completely as that cause random device stop working
6771 * problems as well as full system hangs for some PCIe devices users */
6772 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6773 PCIE_LINK_STATE_CLKPM);
6774
6775 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6776 rc = pci_enable_device(pdev);
6777 if (rc < 0) {
6778 netif_err(tp, probe, dev, "enable failure\n");
6779 goto err_out_free_dev_1;
6780 }
6781
6782 if (pci_set_mwi(pdev) < 0)
6783 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6784
6785 /* make sure PCI base addr 1 is MMIO */
6786 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6787 netif_err(tp, probe, dev,
6788 "region #%d not an MMIO resource, aborting\n",
6789 region);
6790 rc = -ENODEV;
6791 goto err_out_mwi_2;
6792 }
6793
6794 /* check for weird/broken PCI region reporting */
6795 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6796 netif_err(tp, probe, dev,
6797 "Invalid PCI region size(s), aborting\n");
6798 rc = -ENODEV;
6799 goto err_out_mwi_2;
6800 }
6801
6802 rc = pci_request_regions(pdev, MODULENAME);
6803 if (rc < 0) {
6804 netif_err(tp, probe, dev, "could not request regions\n");
6805 goto err_out_mwi_2;
6806 }
6807
6808 tp->cp_cmd = RxChkSum;
6809
6810 if ((sizeof(dma_addr_t) > 4) &&
6811 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6812 tp->cp_cmd |= PCIDAC;
6813 dev->features |= NETIF_F_HIGHDMA;
6814 } else {
6815 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6816 if (rc < 0) {
6817 netif_err(tp, probe, dev, "DMA configuration failed\n");
6818 goto err_out_free_res_3;
6819 }
6820 }
6821
6822 /* ioremap MMIO region */
6823 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6824 if (!ioaddr) {
6825 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6826 rc = -EIO;
6827 goto err_out_free_res_3;
6828 }
6829 tp->mmio_addr = ioaddr;
6830
6831 if (!pci_is_pcie(pdev))
6832 netif_info(tp, probe, dev, "not PCI Express\n");
6833
6834 /* Identify chip attached to board */
6835 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6836
6837 rtl_init_rxcfg(tp);
6838
6839 rtl_irq_disable(tp);
6840
Hayes Wangc5583862012-07-02 17:23:22 +08006841 rtl_hw_initialize(tp);
6842
Francois Romieu3b6cf252012-03-08 09:59:04 +01006843 rtl_hw_reset(tp);
6844
6845 rtl_ack_events(tp, 0xffff);
6846
6847 pci_set_master(pdev);
6848
6849 /*
6850 * Pretend we are using VLANs; This bypasses a nasty bug where
6851 * Interrupts stop flowing on high load on 8110SCd controllers.
6852 */
6853 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6854 tp->cp_cmd |= RxVlan;
6855
6856 rtl_init_mdio_ops(tp);
6857 rtl_init_pll_power_ops(tp);
6858 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006859 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006860
6861 rtl8169_print_mac_version(tp);
6862
6863 chipset = tp->mac_version;
6864 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6865
6866 RTL_W8(Cfg9346, Cfg9346_Unlock);
6867 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6868 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6869 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6870 tp->features |= RTL_FEATURE_WOL;
6871 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6872 tp->features |= RTL_FEATURE_WOL;
6873 tp->features |= rtl_try_msi(tp, cfg);
6874 RTL_W8(Cfg9346, Cfg9346_Lock);
6875
6876 if (rtl_tbi_enabled(tp)) {
6877 tp->set_speed = rtl8169_set_speed_tbi;
6878 tp->get_settings = rtl8169_gset_tbi;
6879 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6880 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6881 tp->link_ok = rtl8169_tbi_link_ok;
6882 tp->do_ioctl = rtl_tbi_ioctl;
6883 } else {
6884 tp->set_speed = rtl8169_set_speed_xmii;
6885 tp->get_settings = rtl8169_gset_xmii;
6886 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6887 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6888 tp->link_ok = rtl8169_xmii_link_ok;
6889 tp->do_ioctl = rtl_xmii_ioctl;
6890 }
6891
6892 mutex_init(&tp->wk.mutex);
6893
6894 /* Get MAC address */
6895 for (i = 0; i < ETH_ALEN; i++)
6896 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6897 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6898
6899 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6900 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006901
6902 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6903
6904 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6905 * properly for all devices */
6906 dev->features |= NETIF_F_RXCSUM |
6907 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6908
6909 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6910 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6911 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6912 NETIF_F_HIGHDMA;
6913
6914 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6915 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6916 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6917
6918 dev->hw_features |= NETIF_F_RXALL;
6919 dev->hw_features |= NETIF_F_RXFCS;
6920
6921 tp->hw_start = cfg->hw_start;
6922 tp->event_slow = cfg->event_slow;
6923
6924 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6925 ~(RxBOVF | RxFOVF) : ~0;
6926
6927 init_timer(&tp->timer);
6928 tp->timer.data = (unsigned long) dev;
6929 tp->timer.function = rtl8169_phy_timer;
6930
6931 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6932
6933 rc = register_netdev(dev);
6934 if (rc < 0)
6935 goto err_out_msi_4;
6936
6937 pci_set_drvdata(pdev, dev);
6938
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006939 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6940 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6941 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006942 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6943 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6944 "tx checksumming: %s]\n",
6945 rtl_chip_infos[chipset].jumbo_max,
6946 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6947 }
6948
6949 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6950 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6951 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6952 rtl8168_driver_start(tp);
6953 }
6954
6955 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6956
6957 if (pci_dev_run_wake(pdev))
6958 pm_runtime_put_noidle(&pdev->dev);
6959
6960 netif_carrier_off(dev);
6961
6962out:
6963 return rc;
6964
6965err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006966 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006967 rtl_disable_msi(pdev, tp);
6968 iounmap(ioaddr);
6969err_out_free_res_3:
6970 pci_release_regions(pdev);
6971err_out_mwi_2:
6972 pci_clear_mwi(pdev);
6973 pci_disable_device(pdev);
6974err_out_free_dev_1:
6975 free_netdev(dev);
6976 goto out;
6977}
6978
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979static struct pci_driver rtl8169_pci_driver = {
6980 .name = MODULENAME,
6981 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01006982 .probe = rtl_init_one,
Francois Romieue27566e2012-03-08 09:54:01 +01006983 .remove = __devexit_p(rtl_remove_one),
Francois Romieu1765f952008-09-13 17:21:40 +02006984 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006985 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986};
6987
Francois Romieu07d3f512007-02-21 22:40:46 +01006988static int __init rtl8169_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989{
Jeff Garzik29917622006-08-19 17:48:59 -04006990 return pci_register_driver(&rtl8169_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006991}
6992
Francois Romieu07d3f512007-02-21 22:40:46 +01006993static void __exit rtl8169_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994{
6995 pci_unregister_driver(&rtl8169_pci_driver);
6996}
6997
6998module_init(rtl8169_init_module);
6999module_exit(rtl8169_cleanup_module);