blob: b47d5b35024ed4c3398f6589228b9be813248c66 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Francois Romieu07d3f512007-02-21 22:40:46 +01002 * r8169.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/delay.h>
17#include <linux/ethtool.h>
18#include <linux/mii.h>
19#include <linux/if_vlan.h>
20#include <linux/crc32.h>
21#include <linux/in.h>
22#include <linux/ip.h>
23#include <linux/tcp.h>
24#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000025#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/dma-mapping.h>
Rafael J. Wysockie1759442010-03-14 14:33:51 +000027#include <linux/pm_runtime.h>
françois romieubca03d52011-01-03 15:07:31 +000028#include <linux/firmware.h>
Stanislaw Gruszkaba04c7c2011-02-22 02:00:11 +000029#include <linux/pci-aspm.h>
Paul Gortmaker70c71602011-05-22 16:47:17 -040030#include <linux/prefetch.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <asm/io.h>
33#include <asm/irq.h>
34
Francois Romieu865c6522008-05-11 14:51:00 +020035#define RTL8169_VERSION "2.3LK-NAPI"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MODULENAME "r8169"
37#define PFX MODULENAME ": "
38
françois romieubca03d52011-01-03 15:07:31 +000039#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
40#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
hayeswang01dc7fe2011-03-21 01:50:28 +000041#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
42#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
Hayes Wang70090422011-07-06 15:58:06 +080043#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
Hayes Wangc2218922011-09-06 16:55:18 +080044#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
45#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
Hayes Wang5a5e4442011-02-22 17:26:21 +080046#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
Hayes Wang7e18dca2012-03-30 14:33:02 +080047#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
Hayes Wangb3d7b2f2012-03-30 14:48:06 +080048#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
Hayes Wang5598bfe2012-07-02 17:23:21 +080049#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
Hayes Wangc5583862012-07-02 17:23:22 +080050#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
françois romieubca03d52011-01-03 15:07:31 +000051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#ifdef RTL8169_DEBUG
53#define assert(expr) \
Francois Romieu5b0384f2006-08-16 16:00:01 +020054 if (!(expr)) { \
55 printk( "Assertion failed! %s,%s,%s,line=%d\n", \
Harvey Harrisonb39d66a2008-08-20 16:52:04 -070056 #expr,__FILE__,__func__,__LINE__); \
Francois Romieu5b0384f2006-08-16 16:00:01 +020057 }
Joe Perches06fa7352007-10-18 21:15:00 +020058#define dprintk(fmt, args...) \
59 do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#else
61#define assert(expr) do {} while (0)
62#define dprintk(fmt, args...) do {} while (0)
63#endif /* RTL8169_DEBUG */
64
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020065#define R8169_MSG_DEFAULT \
Francois Romieuf0e837d92005-09-30 16:54:02 -070066 (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020067
Julien Ducourthial477206a2012-05-09 00:00:06 +020068#define TX_SLOTS_AVAIL(tp) \
69 (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
70
71/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
72#define TX_FRAGS_READY_FOR(tp,nr_frags) \
73 (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
76 The RTL chips use a 64 element hash table based on the Ethernet CRC. */
Arjan van de Venf71e1302006-03-03 21:33:57 -050077static const int multicast_filter_limit = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Francois Romieu9c14cea2008-07-05 00:21:15 +020079#define MAX_READ_REQUEST_SHIFT 12
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
82#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
83
84#define R8169_REGS_SIZE 256
85#define R8169_NAPI_WEIGHT 64
86#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
87#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
88#define RX_BUF_SIZE 1536 /* Rx Buffer size */
89#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
90#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
91
92#define RTL8169_TX_TIMEOUT (6*HZ)
93#define RTL8169_PHY_TIMEOUT (10*HZ)
94
françois romieuea8dbdd2009-03-15 01:10:50 +000095#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
96#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
Francois Romieue1564ec2008-10-16 22:46:13 +020097#define RTL_EEPROM_SIG_ADDR 0x0000
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099/* write/read MMIO register */
100#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
101#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
102#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
103#define RTL_R8(reg) readb (ioaddr + (reg))
104#define RTL_R16(reg) readw (ioaddr + (reg))
Junchang Wang06f555f2010-05-30 02:26:07 +0000105#define RTL_R32(reg) readl (ioaddr + (reg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107enum mac_version {
Francois Romieu85bffe62011-04-27 08:22:39 +0200108 RTL_GIGA_MAC_VER_01 = 0,
109 RTL_GIGA_MAC_VER_02,
110 RTL_GIGA_MAC_VER_03,
111 RTL_GIGA_MAC_VER_04,
112 RTL_GIGA_MAC_VER_05,
113 RTL_GIGA_MAC_VER_06,
114 RTL_GIGA_MAC_VER_07,
115 RTL_GIGA_MAC_VER_08,
116 RTL_GIGA_MAC_VER_09,
117 RTL_GIGA_MAC_VER_10,
118 RTL_GIGA_MAC_VER_11,
119 RTL_GIGA_MAC_VER_12,
120 RTL_GIGA_MAC_VER_13,
121 RTL_GIGA_MAC_VER_14,
122 RTL_GIGA_MAC_VER_15,
123 RTL_GIGA_MAC_VER_16,
124 RTL_GIGA_MAC_VER_17,
125 RTL_GIGA_MAC_VER_18,
126 RTL_GIGA_MAC_VER_19,
127 RTL_GIGA_MAC_VER_20,
128 RTL_GIGA_MAC_VER_21,
129 RTL_GIGA_MAC_VER_22,
130 RTL_GIGA_MAC_VER_23,
131 RTL_GIGA_MAC_VER_24,
132 RTL_GIGA_MAC_VER_25,
133 RTL_GIGA_MAC_VER_26,
134 RTL_GIGA_MAC_VER_27,
135 RTL_GIGA_MAC_VER_28,
136 RTL_GIGA_MAC_VER_29,
137 RTL_GIGA_MAC_VER_30,
138 RTL_GIGA_MAC_VER_31,
139 RTL_GIGA_MAC_VER_32,
140 RTL_GIGA_MAC_VER_33,
Hayes Wang70090422011-07-06 15:58:06 +0800141 RTL_GIGA_MAC_VER_34,
Hayes Wangc2218922011-09-06 16:55:18 +0800142 RTL_GIGA_MAC_VER_35,
143 RTL_GIGA_MAC_VER_36,
Hayes Wang7e18dca2012-03-30 14:33:02 +0800144 RTL_GIGA_MAC_VER_37,
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800145 RTL_GIGA_MAC_VER_38,
Hayes Wang5598bfe2012-07-02 17:23:21 +0800146 RTL_GIGA_MAC_VER_39,
Hayes Wangc5583862012-07-02 17:23:22 +0800147 RTL_GIGA_MAC_VER_40,
148 RTL_GIGA_MAC_VER_41,
Francois Romieu85bffe62011-04-27 08:22:39 +0200149 RTL_GIGA_MAC_NONE = 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150};
151
Francois Romieu2b7b4312011-04-18 22:53:24 -0700152enum rtl_tx_desc_version {
153 RTL_TD_0 = 0,
154 RTL_TD_1 = 1,
155};
156
Francois Romieud58d46b2011-05-03 16:38:29 +0200157#define JUMBO_1K ETH_DATA_LEN
158#define JUMBO_4K (4*1024 - ETH_HLEN - 2)
159#define JUMBO_6K (6*1024 - ETH_HLEN - 2)
160#define JUMBO_7K (7*1024 - ETH_HLEN - 2)
161#define JUMBO_9K (9*1024 - ETH_HLEN - 2)
162
163#define _R(NAME,TD,FW,SZ,B) { \
164 .name = NAME, \
165 .txd_version = TD, \
166 .fw_name = FW, \
167 .jumbo_max = SZ, \
168 .jumbo_tx_csum = B \
169}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Jesper Juhl3c6bee12006-01-09 20:54:01 -0800171static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 const char *name;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700173 enum rtl_tx_desc_version txd_version;
Francois Romieu85bffe62011-04-27 08:22:39 +0200174 const char *fw_name;
Francois Romieud58d46b2011-05-03 16:38:29 +0200175 u16 jumbo_max;
176 bool jumbo_tx_csum;
Francois Romieu85bffe62011-04-27 08:22:39 +0200177} rtl_chip_infos[] = {
178 /* PCI devices. */
179 [RTL_GIGA_MAC_VER_01] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200180 _R("RTL8169", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200181 [RTL_GIGA_MAC_VER_02] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200182 _R("RTL8169s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200183 [RTL_GIGA_MAC_VER_03] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200184 _R("RTL8110s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200185 [RTL_GIGA_MAC_VER_04] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200186 _R("RTL8169sb/8110sb", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200187 [RTL_GIGA_MAC_VER_05] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200188 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200189 [RTL_GIGA_MAC_VER_06] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200190 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200191 /* PCI-E devices. */
192 [RTL_GIGA_MAC_VER_07] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200193 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200194 [RTL_GIGA_MAC_VER_08] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200195 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200196 [RTL_GIGA_MAC_VER_09] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200197 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200198 [RTL_GIGA_MAC_VER_10] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200199 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200200 [RTL_GIGA_MAC_VER_11] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200201 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200202 [RTL_GIGA_MAC_VER_12] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200203 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200204 [RTL_GIGA_MAC_VER_13] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200205 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200206 [RTL_GIGA_MAC_VER_14] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200207 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200208 [RTL_GIGA_MAC_VER_15] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200209 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200210 [RTL_GIGA_MAC_VER_16] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200211 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200212 [RTL_GIGA_MAC_VER_17] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200213 _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200214 [RTL_GIGA_MAC_VER_18] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200215 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200216 [RTL_GIGA_MAC_VER_19] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200217 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200218 [RTL_GIGA_MAC_VER_20] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200219 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200220 [RTL_GIGA_MAC_VER_21] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200221 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200222 [RTL_GIGA_MAC_VER_22] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200223 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200224 [RTL_GIGA_MAC_VER_23] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200225 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200226 [RTL_GIGA_MAC_VER_24] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200227 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200228 [RTL_GIGA_MAC_VER_25] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200229 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1,
230 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200231 [RTL_GIGA_MAC_VER_26] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200232 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2,
233 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200234 [RTL_GIGA_MAC_VER_27] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200235 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200236 [RTL_GIGA_MAC_VER_28] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200237 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200238 [RTL_GIGA_MAC_VER_29] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200239 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
240 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200241 [RTL_GIGA_MAC_VER_30] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200242 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
243 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200244 [RTL_GIGA_MAC_VER_31] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200245 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200246 [RTL_GIGA_MAC_VER_32] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200247 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1,
248 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200249 [RTL_GIGA_MAC_VER_33] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200250 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2,
251 JUMBO_9K, false),
Hayes Wang70090422011-07-06 15:58:06 +0800252 [RTL_GIGA_MAC_VER_34] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200253 _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
254 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800255 [RTL_GIGA_MAC_VER_35] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200256 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_1,
257 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800258 [RTL_GIGA_MAC_VER_36] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200259 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2,
260 JUMBO_9K, false),
Hayes Wang7e18dca2012-03-30 14:33:02 +0800261 [RTL_GIGA_MAC_VER_37] =
262 _R("RTL8402", RTL_TD_1, FIRMWARE_8402_1,
263 JUMBO_1K, true),
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800264 [RTL_GIGA_MAC_VER_38] =
265 _R("RTL8411", RTL_TD_1, FIRMWARE_8411_1,
266 JUMBO_9K, false),
Hayes Wang5598bfe2012-07-02 17:23:21 +0800267 [RTL_GIGA_MAC_VER_39] =
268 _R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_1,
269 JUMBO_1K, true),
Hayes Wangc5583862012-07-02 17:23:22 +0800270 [RTL_GIGA_MAC_VER_40] =
271 _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_1,
272 JUMBO_9K, false),
273 [RTL_GIGA_MAC_VER_41] =
274 _R("RTL8168g/8111g", RTL_TD_1, NULL, JUMBO_9K, false),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275};
276#undef _R
277
Francois Romieubcf0bf92006-07-26 23:14:13 +0200278enum cfg_version {
279 RTL_CFG_0 = 0x00,
280 RTL_CFG_1,
281 RTL_CFG_2
282};
283
Alexey Dobriyana3aa1882010-01-07 11:58:11 +0000284static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
Francois Romieubcf0bf92006-07-26 23:14:13 +0200285 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
Francois Romieud2eed8c2006-08-31 22:01:07 +0200286 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
Francois Romieud81bf552006-09-20 21:31:20 +0200287 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
Francois Romieu07ce4062007-02-23 23:36:39 +0100288 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200289 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
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{
836 int cap = pci_pcie_cap(pdev);
837
838 if (cap) {
839 u16 ctl;
840
841 pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
842 ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
843 pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
844 }
845}
846
Francois Romieuffc46952012-07-06 14:19:23 +0200847struct rtl_cond {
848 bool (*check)(struct rtl8169_private *);
849 const char *msg;
850};
851
852static void rtl_udelay(unsigned int d)
853{
854 udelay(d);
855}
856
857static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
858 void (*delay)(unsigned int), unsigned int d, int n,
859 bool high)
860{
861 int i;
862
863 for (i = 0; i < n; i++) {
864 delay(d);
865 if (c->check(tp) == high)
866 return true;
867 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200868 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
869 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200870 return false;
871}
872
873static bool rtl_udelay_loop_wait_high(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, true);
878}
879
880static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
881 const struct rtl_cond *c,
882 unsigned int d, int n)
883{
884 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
885}
886
887static bool rtl_msleep_loop_wait_high(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, true);
892}
893
894static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
895 const struct rtl_cond *c,
896 unsigned int d, int n)
897{
898 return rtl_loop_wait(tp, c, msleep, d, n, false);
899}
900
901#define DECLARE_RTL_COND(name) \
902static bool name ## _check(struct rtl8169_private *); \
903 \
904static const struct rtl_cond name = { \
905 .check = name ## _check, \
906 .msg = #name \
907}; \
908 \
909static bool name ## _check(struct rtl8169_private *tp)
910
911DECLARE_RTL_COND(rtl_ocpar_cond)
912{
913 void __iomem *ioaddr = tp->mmio_addr;
914
915 return RTL_R32(OCPAR) & OCPAR_FLAG;
916}
917
françois romieub646d902011-01-03 15:08:21 +0000918static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
919{
920 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000921
922 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200923
924 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
925 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000926}
927
928static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
929{
930 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000931
932 RTL_W32(OCPDR, data);
933 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200934
935 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
936}
937
938DECLARE_RTL_COND(rtl_eriar_cond)
939{
940 void __iomem *ioaddr = tp->mmio_addr;
941
942 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000943}
944
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800945static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000946{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800947 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000948
949 RTL_W8(ERIDR, cmd);
950 RTL_W32(ERIAR, 0x800010e8);
951 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200952
953 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
954 return;
françois romieub646d902011-01-03 15:08:21 +0000955
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800956 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000957}
958
959#define OOB_CMD_RESET 0x00
960#define OOB_CMD_DRIVER_START 0x05
961#define OOB_CMD_DRIVER_STOP 0x06
962
Francois Romieucecb5fd2011-04-01 10:21:07 +0200963static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
964{
965 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
966}
967
Francois Romieuffc46952012-07-06 14:19:23 +0200968DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000969{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200970 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000971
Francois Romieucecb5fd2011-04-01 10:21:07 +0200972 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000973
Francois Romieuffc46952012-07-06 14:19:23 +0200974 return ocp_read(tp, 0x0f, reg) & 0x00000800;
975}
976
977static void rtl8168_driver_start(struct rtl8169_private *tp)
978{
979 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
980
981 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000982}
983
984static void rtl8168_driver_stop(struct rtl8169_private *tp)
985{
françois romieub646d902011-01-03 15:08:21 +0000986 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
987
Francois Romieuffc46952012-07-06 14:19:23 +0200988 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000989}
990
hayeswang4804b3b2011-03-21 01:50:29 +0000991static int r8168dp_check_dash(struct rtl8169_private *tp)
992{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200993 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000994
Francois Romieucecb5fd2011-04-01 10:21:07 +0200995 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000996}
françois romieub646d902011-01-03 15:08:21 +0000997
Hayes Wangc5583862012-07-02 17:23:22 +0800998static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
999{
1000 if (reg & 0xffff0001) {
1001 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
1002 return true;
1003 }
1004 return false;
1005}
1006
1007DECLARE_RTL_COND(rtl_ocp_gphy_cond)
1008{
1009 void __iomem *ioaddr = tp->mmio_addr;
1010
1011 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1012}
1013
1014static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1015{
1016 void __iomem *ioaddr = tp->mmio_addr;
1017
1018 if (rtl_ocp_reg_failure(tp, reg))
1019 return;
1020
1021 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1022
1023 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1024}
1025
1026static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1027{
1028 void __iomem *ioaddr = tp->mmio_addr;
1029
1030 if (rtl_ocp_reg_failure(tp, reg))
1031 return 0;
1032
1033 RTL_W32(GPHY_OCP, reg << 15);
1034
1035 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1036 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1037}
1038
1039static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1040{
1041 int val;
1042
1043 val = r8168_phy_ocp_read(tp, reg);
1044 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1045}
1046
Hayes Wangc5583862012-07-02 17:23:22 +08001047static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1048{
1049 void __iomem *ioaddr = tp->mmio_addr;
1050
1051 if (rtl_ocp_reg_failure(tp, reg))
1052 return;
1053
1054 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001055}
1056
1057static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1058{
1059 void __iomem *ioaddr = tp->mmio_addr;
1060
1061 if (rtl_ocp_reg_failure(tp, reg))
1062 return 0;
1063
1064 RTL_W32(OCPDR, reg << 15);
1065
Hayes Wang3a83ad12012-07-11 20:31:56 +08001066 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001067}
1068
1069#define OCP_STD_PHY_BASE 0xa400
1070
1071static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1072{
1073 if (reg == 0x1f) {
1074 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1075 return;
1076 }
1077
1078 if (tp->ocp_base != OCP_STD_PHY_BASE)
1079 reg -= 0x10;
1080
1081 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1082}
1083
1084static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1085{
1086 if (tp->ocp_base != OCP_STD_PHY_BASE)
1087 reg -= 0x10;
1088
1089 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1090}
1091
Francois Romieuffc46952012-07-06 14:19:23 +02001092DECLARE_RTL_COND(rtl_phyar_cond)
1093{
1094 void __iomem *ioaddr = tp->mmio_addr;
1095
1096 return RTL_R32(PHYAR) & 0x80000000;
1097}
1098
Francois Romieu24192212012-07-06 20:19:42 +02001099static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Francois Romieu24192212012-07-06 20:19:42 +02001101 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Francois Romieu24192212012-07-06 20:19:42 +02001103 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Francois Romieuffc46952012-07-06 14:19:23 +02001105 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001106 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001107 * According to hardware specs a 20us delay is required after write
1108 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001109 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001110 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111}
1112
Francois Romieu24192212012-07-06 20:19:42 +02001113static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114{
Francois Romieu24192212012-07-06 20:19:42 +02001115 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001116 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Francois Romieu24192212012-07-06 20:19:42 +02001118 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
Francois Romieuffc46952012-07-06 14:19:23 +02001120 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1121 RTL_R32(PHYAR) & 0xffff : ~0;
1122
Timo Teräs81a95f02010-06-09 17:31:48 -07001123 /*
1124 * According to hardware specs a 20us delay is required after read
1125 * complete indication, but before sending next command.
1126 */
1127 udelay(20);
1128
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 return value;
1130}
1131
Francois Romieu24192212012-07-06 20:19:42 +02001132static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001133{
Francois Romieu24192212012-07-06 20:19:42 +02001134 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001135
Francois Romieu24192212012-07-06 20:19:42 +02001136 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001137 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1138 RTL_W32(EPHY_RXER_NUM, 0);
1139
Francois Romieuffc46952012-07-06 14:19:23 +02001140 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001141}
1142
Francois Romieu24192212012-07-06 20:19:42 +02001143static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001144{
Francois Romieu24192212012-07-06 20:19:42 +02001145 r8168dp_1_mdio_access(tp, reg,
1146 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001147}
1148
Francois Romieu24192212012-07-06 20:19:42 +02001149static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001150{
Francois Romieu24192212012-07-06 20:19:42 +02001151 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001152
Francois Romieu24192212012-07-06 20:19:42 +02001153 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001154
1155 mdelay(1);
1156 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1157 RTL_W32(EPHY_RXER_NUM, 0);
1158
Francois Romieuffc46952012-07-06 14:19:23 +02001159 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1160 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001161}
1162
françois romieue6de30d2011-01-03 15:08:37 +00001163#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1164
1165static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1166{
1167 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1168}
1169
1170static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1171{
1172 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1173}
1174
Francois Romieu24192212012-07-06 20:19:42 +02001175static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001176{
Francois Romieu24192212012-07-06 20:19:42 +02001177 void __iomem *ioaddr = tp->mmio_addr;
1178
françois romieue6de30d2011-01-03 15:08:37 +00001179 r8168dp_2_mdio_start(ioaddr);
1180
Francois Romieu24192212012-07-06 20:19:42 +02001181 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001182
1183 r8168dp_2_mdio_stop(ioaddr);
1184}
1185
Francois Romieu24192212012-07-06 20:19:42 +02001186static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001187{
Francois Romieu24192212012-07-06 20:19:42 +02001188 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001189 int value;
1190
1191 r8168dp_2_mdio_start(ioaddr);
1192
Francois Romieu24192212012-07-06 20:19:42 +02001193 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001194
1195 r8168dp_2_mdio_stop(ioaddr);
1196
1197 return value;
1198}
1199
françois romieu4da19632011-01-03 15:07:55 +00001200static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001201{
Francois Romieu24192212012-07-06 20:19:42 +02001202 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001203}
1204
françois romieu4da19632011-01-03 15:07:55 +00001205static int rtl_readphy(struct rtl8169_private *tp, int location)
1206{
Francois Romieu24192212012-07-06 20:19:42 +02001207 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001208}
1209
1210static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1211{
1212 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1213}
1214
1215static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001216{
1217 int val;
1218
françois romieu4da19632011-01-03 15:07:55 +00001219 val = rtl_readphy(tp, reg_addr);
1220 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001221}
1222
Francois Romieuccdffb92008-07-26 14:26:06 +02001223static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1224 int val)
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 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001229}
1230
1231static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1232{
1233 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001234
françois romieu4da19632011-01-03 15:07:55 +00001235 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001236}
1237
Francois Romieuffc46952012-07-06 14:19:23 +02001238DECLARE_RTL_COND(rtl_ephyar_cond)
1239{
1240 void __iomem *ioaddr = tp->mmio_addr;
1241
1242 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1243}
1244
Francois Romieufdf6fc02012-07-06 22:40:38 +02001245static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001246{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001247 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001248
1249 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1250 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1251
Francois Romieuffc46952012-07-06 14:19:23 +02001252 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1253
1254 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001255}
1256
Francois Romieufdf6fc02012-07-06 22:40:38 +02001257static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001258{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001259 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001260
1261 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1262
Francois Romieuffc46952012-07-06 14:19:23 +02001263 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1264 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001265}
1266
Francois Romieufdf6fc02012-07-06 22:40:38 +02001267static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1268 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001269{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001270 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001271
1272 BUG_ON((addr & 3) || (mask == 0));
1273 RTL_W32(ERIDR, val);
1274 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1275
Francois Romieuffc46952012-07-06 14:19:23 +02001276 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001277}
1278
Francois Romieufdf6fc02012-07-06 22:40:38 +02001279static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001280{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001281 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001282
1283 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1284
Francois Romieuffc46952012-07-06 14:19:23 +02001285 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1286 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001287}
1288
Francois Romieufdf6fc02012-07-06 22:40:38 +02001289static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1290 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001291{
1292 u32 val;
1293
Francois Romieufdf6fc02012-07-06 22:40:38 +02001294 val = rtl_eri_read(tp, addr, type);
1295 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001296}
1297
françois romieuc28aa382011-08-02 03:53:43 +00001298struct exgmac_reg {
1299 u16 addr;
1300 u16 mask;
1301 u32 val;
1302};
1303
Francois Romieufdf6fc02012-07-06 22:40:38 +02001304static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001305 const struct exgmac_reg *r, int len)
1306{
1307 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001308 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001309 r++;
1310 }
1311}
1312
Francois Romieuffc46952012-07-06 14:19:23 +02001313DECLARE_RTL_COND(rtl_efusear_cond)
1314{
1315 void __iomem *ioaddr = tp->mmio_addr;
1316
1317 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1318}
1319
Francois Romieufdf6fc02012-07-06 22:40:38 +02001320static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001321{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001322 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001323
1324 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1325
Francois Romieuffc46952012-07-06 14:19:23 +02001326 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1327 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001328}
1329
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001330static u16 rtl_get_events(struct rtl8169_private *tp)
1331{
1332 void __iomem *ioaddr = tp->mmio_addr;
1333
1334 return RTL_R16(IntrStatus);
1335}
1336
1337static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1338{
1339 void __iomem *ioaddr = tp->mmio_addr;
1340
1341 RTL_W16(IntrStatus, bits);
1342 mmiowb();
1343}
1344
1345static void rtl_irq_disable(struct rtl8169_private *tp)
1346{
1347 void __iomem *ioaddr = tp->mmio_addr;
1348
1349 RTL_W16(IntrMask, 0);
1350 mmiowb();
1351}
1352
Francois Romieu3e990ff2012-01-26 12:50:01 +01001353static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1354{
1355 void __iomem *ioaddr = tp->mmio_addr;
1356
1357 RTL_W16(IntrMask, bits);
1358}
1359
Francois Romieuda78dbf2012-01-26 14:18:23 +01001360#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1361#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1362#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1363
1364static void rtl_irq_enable_all(struct rtl8169_private *tp)
1365{
1366 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1367}
1368
françois romieu811fd302011-12-04 20:30:45 +00001369static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370{
françois romieu811fd302011-12-04 20:30:45 +00001371 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001373 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001374 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001375 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
1377
françois romieu4da19632011-01-03 15:07:55 +00001378static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379{
françois romieu4da19632011-01-03 15:07:55 +00001380 void __iomem *ioaddr = tp->mmio_addr;
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return RTL_R32(TBICSR) & TBIReset;
1383}
1384
françois romieu4da19632011-01-03 15:07:55 +00001385static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386{
françois romieu4da19632011-01-03 15:07:55 +00001387 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388}
1389
1390static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1391{
1392 return RTL_R32(TBICSR) & TBILinkOk;
1393}
1394
1395static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1396{
1397 return RTL_R8(PHYstatus) & LinkStatus;
1398}
1399
françois romieu4da19632011-01-03 15:07:55 +00001400static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
françois romieu4da19632011-01-03 15:07:55 +00001402 void __iomem *ioaddr = tp->mmio_addr;
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1405}
1406
françois romieu4da19632011-01-03 15:07:55 +00001407static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
1409 unsigned int val;
1410
françois romieu4da19632011-01-03 15:07:55 +00001411 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1412 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413}
1414
Hayes Wang70090422011-07-06 15:58:06 +08001415static void rtl_link_chg_patch(struct rtl8169_private *tp)
1416{
1417 void __iomem *ioaddr = tp->mmio_addr;
1418 struct net_device *dev = tp->dev;
1419
1420 if (!netif_running(dev))
1421 return;
1422
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001423 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1424 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001425 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001426 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1427 ERIAR_EXGMAC);
1428 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1429 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001430 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001431 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1432 ERIAR_EXGMAC);
1433 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1434 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001435 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001436 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1437 ERIAR_EXGMAC);
1438 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1439 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001440 }
1441 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001442 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001443 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001444 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001445 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001446 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1447 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1448 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001449 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1450 ERIAR_EXGMAC);
1451 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1452 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001453 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001454 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1455 ERIAR_EXGMAC);
1456 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1457 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001458 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001459 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1460 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001461 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1462 ERIAR_EXGMAC);
1463 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1464 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001465 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001466 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1467 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001468 }
Hayes Wang70090422011-07-06 15:58:06 +08001469 }
1470}
1471
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001472static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001473 struct rtl8169_private *tp,
1474 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001477 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001478 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001479 if (pm)
1480 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001482 if (net_ratelimit())
1483 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001484 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001486 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001487 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001488 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490}
1491
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001492static void rtl8169_check_link_status(struct net_device *dev,
1493 struct rtl8169_private *tp,
1494 void __iomem *ioaddr)
1495{
1496 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1497}
1498
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001499#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1500
1501static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1502{
1503 void __iomem *ioaddr = tp->mmio_addr;
1504 u8 options;
1505 u32 wolopts = 0;
1506
1507 options = RTL_R8(Config1);
1508 if (!(options & PMEnable))
1509 return 0;
1510
1511 options = RTL_R8(Config3);
1512 if (options & LinkUp)
1513 wolopts |= WAKE_PHY;
1514 if (options & MagicPacket)
1515 wolopts |= WAKE_MAGIC;
1516
1517 options = RTL_R8(Config5);
1518 if (options & UWF)
1519 wolopts |= WAKE_UCAST;
1520 if (options & BWF)
1521 wolopts |= WAKE_BCAST;
1522 if (options & MWF)
1523 wolopts |= WAKE_MCAST;
1524
1525 return wolopts;
1526}
1527
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001528static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1529{
1530 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001531
Francois Romieuda78dbf2012-01-26 14:18:23 +01001532 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001533
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001534 wol->supported = WAKE_ANY;
1535 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001536
Francois Romieuda78dbf2012-01-26 14:18:23 +01001537 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001538}
1539
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001540static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001541{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001542 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001543 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001544 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001545 u32 opt;
1546 u16 reg;
1547 u8 mask;
1548 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001549 { WAKE_PHY, Config3, LinkUp },
1550 { WAKE_MAGIC, Config3, MagicPacket },
1551 { WAKE_UCAST, Config5, UWF },
1552 { WAKE_BCAST, Config5, BWF },
1553 { WAKE_MCAST, Config5, MWF },
1554 { WAKE_ANY, Config5, LanWake }
1555 };
Francois Romieu851e6022012-04-17 11:10:11 +02001556 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001557
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001558 RTL_W8(Cfg9346, Cfg9346_Unlock);
1559
1560 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001561 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001562 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001563 options |= cfg[i].mask;
1564 RTL_W8(cfg[i].reg, options);
1565 }
1566
Francois Romieu851e6022012-04-17 11:10:11 +02001567 switch (tp->mac_version) {
1568 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1569 options = RTL_R8(Config1) & ~PMEnable;
1570 if (wolopts)
1571 options |= PMEnable;
1572 RTL_W8(Config1, options);
1573 break;
1574 default:
Francois Romieud387b422012-04-17 11:12:01 +02001575 options = RTL_R8(Config2) & ~PME_SIGNAL;
1576 if (wolopts)
1577 options |= PME_SIGNAL;
1578 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001579 break;
1580 }
1581
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001582 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001583}
1584
1585static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1586{
1587 struct rtl8169_private *tp = netdev_priv(dev);
1588
Francois Romieuda78dbf2012-01-26 14:18:23 +01001589 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001590
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001591 if (wol->wolopts)
1592 tp->features |= RTL_FEATURE_WOL;
1593 else
1594 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001595 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001596
1597 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001598
françois romieuea809072010-11-08 13:23:58 +00001599 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1600
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001601 return 0;
1602}
1603
Francois Romieu31bd2042011-04-26 18:58:59 +02001604static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1605{
Francois Romieu85bffe62011-04-27 08:22:39 +02001606 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001607}
1608
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609static void rtl8169_get_drvinfo(struct net_device *dev,
1610 struct ethtool_drvinfo *info)
1611{
1612 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001613 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Rick Jones68aad782011-11-07 13:29:27 +00001615 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1616 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1617 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001618 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001619 if (!IS_ERR_OR_NULL(rtl_fw))
1620 strlcpy(info->fw_version, rtl_fw->version,
1621 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622}
1623
1624static int rtl8169_get_regs_len(struct net_device *dev)
1625{
1626 return R8169_REGS_SIZE;
1627}
1628
1629static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001630 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631{
1632 struct rtl8169_private *tp = netdev_priv(dev);
1633 void __iomem *ioaddr = tp->mmio_addr;
1634 int ret = 0;
1635 u32 reg;
1636
1637 reg = RTL_R32(TBICSR);
1638 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1639 (duplex == DUPLEX_FULL)) {
1640 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1641 } else if (autoneg == AUTONEG_ENABLE)
1642 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1643 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001644 netif_warn(tp, link, dev,
1645 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 ret = -EOPNOTSUPP;
1647 }
1648
1649 return ret;
1650}
1651
1652static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001653 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654{
1655 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001656 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001657 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Hayes Wang716b50a2011-02-22 17:26:18 +08001659 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
1661 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001662 int auto_nego;
1663
françois romieu4da19632011-01-03 15:07:55 +00001664 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001665 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1666 ADVERTISE_100HALF | ADVERTISE_100FULL);
1667
1668 if (adv & ADVERTISED_10baseT_Half)
1669 auto_nego |= ADVERTISE_10HALF;
1670 if (adv & ADVERTISED_10baseT_Full)
1671 auto_nego |= ADVERTISE_10FULL;
1672 if (adv & ADVERTISED_100baseT_Half)
1673 auto_nego |= ADVERTISE_100HALF;
1674 if (adv & ADVERTISED_100baseT_Full)
1675 auto_nego |= ADVERTISE_100FULL;
1676
françois romieu3577aa12009-05-19 10:46:48 +00001677 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1678
françois romieu4da19632011-01-03 15:07:55 +00001679 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001680 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1681
1682 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001683 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001684 if (adv & ADVERTISED_1000baseT_Half)
1685 giga_ctrl |= ADVERTISE_1000HALF;
1686 if (adv & ADVERTISED_1000baseT_Full)
1687 giga_ctrl |= ADVERTISE_1000FULL;
1688 } else if (adv & (ADVERTISED_1000baseT_Half |
1689 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001690 netif_info(tp, link, dev,
1691 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001692 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
françois romieu3577aa12009-05-19 10:46:48 +00001695 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001696
françois romieu4da19632011-01-03 15:07:55 +00001697 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1698 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001699 } else {
1700 giga_ctrl = 0;
1701
1702 if (speed == SPEED_10)
1703 bmcr = 0;
1704 else if (speed == SPEED_100)
1705 bmcr = BMCR_SPEED100;
1706 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001707 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001708
1709 if (duplex == DUPLEX_FULL)
1710 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001711 }
1712
françois romieu4da19632011-01-03 15:07:55 +00001713 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001714
Francois Romieucecb5fd2011-04-01 10:21:07 +02001715 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1716 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001717 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001718 rtl_writephy(tp, 0x17, 0x2138);
1719 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001720 } else {
françois romieu4da19632011-01-03 15:07:55 +00001721 rtl_writephy(tp, 0x17, 0x2108);
1722 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001723 }
1724 }
1725
Oliver Neukum54405cd2011-01-06 21:55:13 +01001726 rc = 0;
1727out:
1728 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729}
1730
1731static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001732 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733{
1734 struct rtl8169_private *tp = netdev_priv(dev);
1735 int ret;
1736
Oliver Neukum54405cd2011-01-06 21:55:13 +01001737 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001738 if (ret < 0)
1739 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Francois Romieu4876cc12011-03-11 21:07:11 +01001741 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1742 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001744 }
1745out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 return ret;
1747}
1748
1749static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1750{
1751 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 int ret;
1753
Francois Romieu4876cc12011-03-11 21:07:11 +01001754 del_timer_sync(&tp->timer);
1755
Francois Romieuda78dbf2012-01-26 14:18:23 +01001756 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001757 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001758 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001759 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 return ret;
1762}
1763
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001764static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1765 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766{
Francois Romieud58d46b2011-05-03 16:38:29 +02001767 struct rtl8169_private *tp = netdev_priv(dev);
1768
Francois Romieu2b7b4312011-04-18 22:53:24 -07001769 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001770 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
Francois Romieud58d46b2011-05-03 16:38:29 +02001772 if (dev->mtu > JUMBO_1K &&
1773 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1774 features &= ~NETIF_F_IP_CSUM;
1775
Michał Mirosław350fb322011-04-08 06:35:56 +00001776 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777}
1778
Francois Romieuda78dbf2012-01-26 14:18:23 +01001779static void __rtl8169_set_features(struct net_device *dev,
1780 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
1782 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001783 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001784 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
Ben Greear6bbe0212012-02-10 15:04:33 +00001786 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1787 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
Ben Greear6bbe0212012-02-10 15:04:33 +00001789 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1790 if (features & NETIF_F_RXCSUM)
1791 tp->cp_cmd |= RxChkSum;
1792 else
1793 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001794
Ben Greear6bbe0212012-02-10 15:04:33 +00001795 if (dev->features & NETIF_F_HW_VLAN_RX)
1796 tp->cp_cmd |= RxVlan;
1797 else
1798 tp->cp_cmd &= ~RxVlan;
1799
1800 RTL_W16(CPlusCmd, tp->cp_cmd);
1801 RTL_R16(CPlusCmd);
1802 }
1803 if (changed & NETIF_F_RXALL) {
1804 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1805 if (features & NETIF_F_RXALL)
1806 tmp |= (AcceptErr | AcceptRunt);
1807 RTL_W32(RxConfig, tmp);
1808 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001809}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810
Francois Romieuda78dbf2012-01-26 14:18:23 +01001811static int rtl8169_set_features(struct net_device *dev,
1812 netdev_features_t features)
1813{
1814 struct rtl8169_private *tp = netdev_priv(dev);
1815
1816 rtl_lock_work(tp);
1817 __rtl8169_set_features(dev, features);
1818 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820 return 0;
1821}
1822
Francois Romieuda78dbf2012-01-26 14:18:23 +01001823
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1825 struct sk_buff *skb)
1826{
Jesse Grosseab6d182010-10-20 13:56:03 +00001827 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1829}
1830
Francois Romieu7a8fc772011-03-01 17:18:33 +01001831static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832{
1833 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Francois Romieu7a8fc772011-03-01 17:18:33 +01001835 if (opts2 & RxVlanTag)
1836 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Eric Dumazet2edae082010-09-06 18:46:39 +00001837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 desc->opts2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839}
1840
Francois Romieuccdffb92008-07-26 14:26:06 +02001841static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842{
1843 struct rtl8169_private *tp = netdev_priv(dev);
1844 void __iomem *ioaddr = tp->mmio_addr;
1845 u32 status;
1846
1847 cmd->supported =
1848 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1849 cmd->port = PORT_FIBRE;
1850 cmd->transceiver = XCVR_INTERNAL;
1851
1852 status = RTL_R32(TBICSR);
1853 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1854 cmd->autoneg = !!(status & TBINwEnable);
1855
David Decotigny70739492011-04-27 18:32:40 +00001856 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001858
1859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860}
1861
Francois Romieuccdffb92008-07-26 14:26:06 +02001862static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
1864 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
Francois Romieuccdffb92008-07-26 14:26:06 +02001866 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867}
1868
1869static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1870{
1871 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001872 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Francois Romieuda78dbf2012-01-26 14:18:23 +01001874 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001875 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001876 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
Francois Romieuccdffb92008-07-26 14:26:06 +02001878 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879}
1880
1881static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1882 void *p)
1883{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001884 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885
Francois Romieu5b0384f2006-08-16 16:00:01 +02001886 if (regs->len > R8169_REGS_SIZE)
1887 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
Francois Romieuda78dbf2012-01-26 14:18:23 +01001889 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001890 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001891 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892}
1893
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001894static u32 rtl8169_get_msglevel(struct net_device *dev)
1895{
1896 struct rtl8169_private *tp = netdev_priv(dev);
1897
1898 return tp->msg_enable;
1899}
1900
1901static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1902{
1903 struct rtl8169_private *tp = netdev_priv(dev);
1904
1905 tp->msg_enable = value;
1906}
1907
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001908static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1909 "tx_packets",
1910 "rx_packets",
1911 "tx_errors",
1912 "rx_errors",
1913 "rx_missed",
1914 "align_errors",
1915 "tx_single_collisions",
1916 "tx_multi_collisions",
1917 "unicast",
1918 "broadcast",
1919 "multicast",
1920 "tx_aborted",
1921 "tx_underrun",
1922};
1923
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001924static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001925{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001926 switch (sset) {
1927 case ETH_SS_STATS:
1928 return ARRAY_SIZE(rtl8169_gstrings);
1929 default:
1930 return -EOPNOTSUPP;
1931 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001932}
1933
Francois Romieuffc46952012-07-06 14:19:23 +02001934DECLARE_RTL_COND(rtl_counters_cond)
1935{
1936 void __iomem *ioaddr = tp->mmio_addr;
1937
1938 return RTL_R32(CounterAddrLow) & CounterDump;
1939}
1940
Ivan Vecera355423d2009-02-06 21:49:57 -08001941static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001942{
1943 struct rtl8169_private *tp = netdev_priv(dev);
1944 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001945 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001946 struct rtl8169_counters *counters;
1947 dma_addr_t paddr;
1948 u32 cmd;
1949
Ivan Vecera355423d2009-02-06 21:49:57 -08001950 /*
1951 * Some chips are unable to dump tally counters when the receiver
1952 * is disabled.
1953 */
1954 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1955 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001956
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001957 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001958 if (!counters)
1959 return;
1960
1961 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001962 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001963 RTL_W32(CounterAddrLow, cmd);
1964 RTL_W32(CounterAddrLow, cmd | CounterDump);
1965
Francois Romieuffc46952012-07-06 14:19:23 +02001966 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1967 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001968
1969 RTL_W32(CounterAddrLow, 0);
1970 RTL_W32(CounterAddrHigh, 0);
1971
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001972 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001973}
1974
Ivan Vecera355423d2009-02-06 21:49:57 -08001975static void rtl8169_get_ethtool_stats(struct net_device *dev,
1976 struct ethtool_stats *stats, u64 *data)
1977{
1978 struct rtl8169_private *tp = netdev_priv(dev);
1979
1980 ASSERT_RTNL();
1981
1982 rtl8169_update_counters(dev);
1983
1984 data[0] = le64_to_cpu(tp->counters.tx_packets);
1985 data[1] = le64_to_cpu(tp->counters.rx_packets);
1986 data[2] = le64_to_cpu(tp->counters.tx_errors);
1987 data[3] = le32_to_cpu(tp->counters.rx_errors);
1988 data[4] = le16_to_cpu(tp->counters.rx_missed);
1989 data[5] = le16_to_cpu(tp->counters.align_errors);
1990 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1991 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1992 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1993 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1994 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1995 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1996 data[12] = le16_to_cpu(tp->counters.tx_underun);
1997}
1998
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001999static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
2000{
2001 switch(stringset) {
2002 case ETH_SS_STATS:
2003 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
2004 break;
2005 }
2006}
2007
Jeff Garzik7282d492006-09-13 14:30:00 -04002008static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 .get_drvinfo = rtl8169_get_drvinfo,
2010 .get_regs_len = rtl8169_get_regs_len,
2011 .get_link = ethtool_op_get_link,
2012 .get_settings = rtl8169_get_settings,
2013 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002014 .get_msglevel = rtl8169_get_msglevel,
2015 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002017 .get_wol = rtl8169_get_wol,
2018 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002019 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002020 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002021 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002022 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023};
2024
Francois Romieu07d3f512007-02-21 22:40:46 +01002025static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002026 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027{
Francois Romieu5d320a22011-05-08 17:47:36 +02002028 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002029 /*
2030 * The driver currently handles the 8168Bf and the 8168Be identically
2031 * but they can be identified more specifically through the test below
2032 * if needed:
2033 *
2034 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002035 *
2036 * Same thing for the 8101Eb and the 8101Ec:
2037 *
2038 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002039 */
Francois Romieu37441002011-06-17 22:58:54 +02002040 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002042 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 int mac_version;
2044 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002045 /* 8168G family. */
2046 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2047 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2048
Hayes Wangc2218922011-09-06 16:55:18 +08002049 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002050 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002051 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2052 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2053
hayeswang01dc7fe2011-03-21 01:50:28 +00002054 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002055 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002056 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2057 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2058 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2059
Francois Romieu5b538df2008-07-20 16:22:45 +02002060 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002061 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2062 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002063 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002064
françois romieue6de30d2011-01-03 15:08:37 +00002065 /* 8168DP family. */
2066 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2067 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002068 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002069
Francois Romieuef808d52008-06-29 13:10:54 +02002070 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002071 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002072 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002073 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002074 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002075 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2076 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002077 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002078 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002079 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002080
2081 /* 8168B family. */
2082 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2083 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2084 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2085 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2086
2087 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002088 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2089 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002090 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002091 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002092 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2093 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2094 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002095 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2096 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2097 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2098 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2099 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2100 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002101 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002102 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002103 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002104 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2105 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002106 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2107 /* FIXME: where did these entries come from ? -- FR */
2108 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2109 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2110
2111 /* 8110 family. */
2112 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2113 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2114 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2115 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2116 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2117 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2118
Jean Delvaref21b75e2009-05-26 20:54:48 -07002119 /* Catch-all */
2120 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002121 };
2122 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 u32 reg;
2124
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002125 reg = RTL_R32(TxConfig);
2126 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 p++;
2128 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002129
2130 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2131 netif_notice(tp, probe, dev,
2132 "unknown MAC, using family default\n");
2133 tp->mac_version = default_version;
2134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135}
2136
2137static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2138{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002139 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140}
2141
Francois Romieu867763c2007-08-17 18:21:58 +02002142struct phy_reg {
2143 u16 reg;
2144 u16 val;
2145};
2146
françois romieu4da19632011-01-03 15:07:55 +00002147static void rtl_writephy_batch(struct rtl8169_private *tp,
2148 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002149{
2150 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002151 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002152 regs++;
2153 }
2154}
2155
françois romieubca03d52011-01-03 15:07:31 +00002156#define PHY_READ 0x00000000
2157#define PHY_DATA_OR 0x10000000
2158#define PHY_DATA_AND 0x20000000
2159#define PHY_BJMPN 0x30000000
2160#define PHY_READ_EFUSE 0x40000000
2161#define PHY_READ_MAC_BYTE 0x50000000
2162#define PHY_WRITE_MAC_BYTE 0x60000000
2163#define PHY_CLEAR_READCOUNT 0x70000000
2164#define PHY_WRITE 0x80000000
2165#define PHY_READCOUNT_EQ_SKIP 0x90000000
2166#define PHY_COMP_EQ_SKIPN 0xa0000000
2167#define PHY_COMP_NEQ_SKIPN 0xb0000000
2168#define PHY_WRITE_PREVIOUS 0xc0000000
2169#define PHY_SKIPN 0xd0000000
2170#define PHY_DELAY_MS 0xe0000000
2171#define PHY_WRITE_ERI_WORD 0xf0000000
2172
Hayes Wang960aee62011-06-18 11:37:48 +02002173struct fw_info {
2174 u32 magic;
2175 char version[RTL_VER_SIZE];
2176 __le32 fw_start;
2177 __le32 fw_len;
2178 u8 chksum;
2179} __packed;
2180
Francois Romieu1c361ef2011-06-17 17:16:24 +02002181#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2182
2183static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002184{
Francois Romieub6ffd972011-06-17 17:00:05 +02002185 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002186 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002187 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2188 char *version = rtl_fw->version;
2189 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002190
Francois Romieu1c361ef2011-06-17 17:16:24 +02002191 if (fw->size < FW_OPCODE_SIZE)
2192 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002193
2194 if (!fw_info->magic) {
2195 size_t i, size, start;
2196 u8 checksum = 0;
2197
2198 if (fw->size < sizeof(*fw_info))
2199 goto out;
2200
2201 for (i = 0; i < fw->size; i++)
2202 checksum += fw->data[i];
2203 if (checksum != 0)
2204 goto out;
2205
2206 start = le32_to_cpu(fw_info->fw_start);
2207 if (start > fw->size)
2208 goto out;
2209
2210 size = le32_to_cpu(fw_info->fw_len);
2211 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2212 goto out;
2213
2214 memcpy(version, fw_info->version, RTL_VER_SIZE);
2215
2216 pa->code = (__le32 *)(fw->data + start);
2217 pa->size = size;
2218 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002219 if (fw->size % FW_OPCODE_SIZE)
2220 goto out;
2221
2222 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2223
2224 pa->code = (__le32 *)fw->data;
2225 pa->size = fw->size / FW_OPCODE_SIZE;
2226 }
2227 version[RTL_VER_SIZE - 1] = 0;
2228
2229 rc = true;
2230out:
2231 return rc;
2232}
2233
Francois Romieufd112f22011-06-18 00:10:29 +02002234static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2235 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002236{
Francois Romieufd112f22011-06-18 00:10:29 +02002237 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002238 size_t index;
2239
Francois Romieu1c361ef2011-06-17 17:16:24 +02002240 for (index = 0; index < pa->size; index++) {
2241 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002242 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002243
hayeswang42b82dc2011-01-10 02:07:25 +00002244 switch(action & 0xf0000000) {
2245 case PHY_READ:
2246 case PHY_DATA_OR:
2247 case PHY_DATA_AND:
2248 case PHY_READ_EFUSE:
2249 case PHY_CLEAR_READCOUNT:
2250 case PHY_WRITE:
2251 case PHY_WRITE_PREVIOUS:
2252 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002253 break;
2254
hayeswang42b82dc2011-01-10 02:07:25 +00002255 case PHY_BJMPN:
2256 if (regno > index) {
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_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002263 if (index + 2 >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002264 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002265 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002266 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002267 }
2268 break;
2269 case PHY_COMP_EQ_SKIPN:
2270 case PHY_COMP_NEQ_SKIPN:
2271 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002272 if (index + 1 + regno >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002273 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002274 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002275 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002276 }
2277 break;
2278
2279 case PHY_READ_MAC_BYTE:
2280 case PHY_WRITE_MAC_BYTE:
2281 case PHY_WRITE_ERI_WORD:
2282 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002283 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002284 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002285 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002286 }
2287 }
Francois Romieufd112f22011-06-18 00:10:29 +02002288 rc = true;
2289out:
2290 return rc;
2291}
françois romieubca03d52011-01-03 15:07:31 +00002292
Francois Romieufd112f22011-06-18 00:10:29 +02002293static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2294{
2295 struct net_device *dev = tp->dev;
2296 int rc = -EINVAL;
2297
2298 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2299 netif_err(tp, ifup, dev, "invalid firwmare\n");
2300 goto out;
2301 }
2302
2303 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2304 rc = 0;
2305out:
2306 return rc;
2307}
2308
2309static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2310{
2311 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2312 u32 predata, count;
2313 size_t index;
2314
2315 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002316
Francois Romieu1c361ef2011-06-17 17:16:24 +02002317 for (index = 0; index < pa->size; ) {
2318 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002319 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002320 u32 regno = (action & 0x0fff0000) >> 16;
2321
2322 if (!action)
2323 break;
françois romieubca03d52011-01-03 15:07:31 +00002324
2325 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002326 case PHY_READ:
2327 predata = rtl_readphy(tp, regno);
2328 count++;
2329 index++;
françois romieubca03d52011-01-03 15:07:31 +00002330 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002331 case PHY_DATA_OR:
2332 predata |= data;
2333 index++;
2334 break;
2335 case PHY_DATA_AND:
2336 predata &= data;
2337 index++;
2338 break;
2339 case PHY_BJMPN:
2340 index -= regno;
2341 break;
2342 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002343 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002344 index++;
2345 break;
2346 case PHY_CLEAR_READCOUNT:
2347 count = 0;
2348 index++;
2349 break;
2350 case PHY_WRITE:
2351 rtl_writephy(tp, regno, data);
2352 index++;
2353 break;
2354 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002355 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002356 break;
2357 case PHY_COMP_EQ_SKIPN:
2358 if (predata == data)
2359 index += regno;
2360 index++;
2361 break;
2362 case PHY_COMP_NEQ_SKIPN:
2363 if (predata != data)
2364 index += regno;
2365 index++;
2366 break;
2367 case PHY_WRITE_PREVIOUS:
2368 rtl_writephy(tp, regno, predata);
2369 index++;
2370 break;
2371 case PHY_SKIPN:
2372 index += regno + 1;
2373 break;
2374 case PHY_DELAY_MS:
2375 mdelay(data);
2376 index++;
2377 break;
2378
2379 case PHY_READ_MAC_BYTE:
2380 case PHY_WRITE_MAC_BYTE:
2381 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002382 default:
2383 BUG();
2384 }
2385 }
2386}
2387
françois romieuf1e02ed2011-01-13 13:07:53 +00002388static void rtl_release_firmware(struct rtl8169_private *tp)
2389{
Francois Romieub6ffd972011-06-17 17:00:05 +02002390 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2391 release_firmware(tp->rtl_fw->fw);
2392 kfree(tp->rtl_fw);
2393 }
2394 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002395}
2396
François Romieu953a12c2011-04-24 17:38:48 +02002397static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002398{
Francois Romieub6ffd972011-06-17 17:00:05 +02002399 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002400
2401 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
Francois Romieub6ffd972011-06-17 17:00:05 +02002402 if (!IS_ERR_OR_NULL(rtl_fw))
2403 rtl_phy_write_fw(tp, rtl_fw);
François Romieu953a12c2011-04-24 17:38:48 +02002404}
2405
2406static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2407{
2408 if (rtl_readphy(tp, reg) != val)
2409 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2410 else
2411 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002412}
2413
françois romieu4da19632011-01-03 15:07:55 +00002414static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002416 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002417 { 0x1f, 0x0001 },
2418 { 0x06, 0x006e },
2419 { 0x08, 0x0708 },
2420 { 0x15, 0x4000 },
2421 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
françois romieu0b9b5712009-08-10 19:44:56 +00002423 { 0x1f, 0x0001 },
2424 { 0x03, 0x00a1 },
2425 { 0x02, 0x0008 },
2426 { 0x01, 0x0120 },
2427 { 0x00, 0x1000 },
2428 { 0x04, 0x0800 },
2429 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
françois romieu0b9b5712009-08-10 19:44:56 +00002431 { 0x03, 0xff41 },
2432 { 0x02, 0xdf60 },
2433 { 0x01, 0x0140 },
2434 { 0x00, 0x0077 },
2435 { 0x04, 0x7800 },
2436 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
françois romieu0b9b5712009-08-10 19:44:56 +00002438 { 0x03, 0x802f },
2439 { 0x02, 0x4f02 },
2440 { 0x01, 0x0409 },
2441 { 0x00, 0xf0f9 },
2442 { 0x04, 0x9800 },
2443 { 0x04, 0x9000 },
2444
2445 { 0x03, 0xdf01 },
2446 { 0x02, 0xdf20 },
2447 { 0x01, 0xff95 },
2448 { 0x00, 0xba00 },
2449 { 0x04, 0xa800 },
2450 { 0x04, 0xa000 },
2451
2452 { 0x03, 0xff41 },
2453 { 0x02, 0xdf20 },
2454 { 0x01, 0x0140 },
2455 { 0x00, 0x00bb },
2456 { 0x04, 0xb800 },
2457 { 0x04, 0xb000 },
2458
2459 { 0x03, 0xdf41 },
2460 { 0x02, 0xdc60 },
2461 { 0x01, 0x6340 },
2462 { 0x00, 0x007d },
2463 { 0x04, 0xd800 },
2464 { 0x04, 0xd000 },
2465
2466 { 0x03, 0xdf01 },
2467 { 0x02, 0xdf20 },
2468 { 0x01, 0x100a },
2469 { 0x00, 0xa0ff },
2470 { 0x04, 0xf800 },
2471 { 0x04, 0xf000 },
2472
2473 { 0x1f, 0x0000 },
2474 { 0x0b, 0x0000 },
2475 { 0x00, 0x9200 }
2476 };
2477
françois romieu4da19632011-01-03 15:07:55 +00002478 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479}
2480
françois romieu4da19632011-01-03 15:07:55 +00002481static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002482{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002483 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002484 { 0x1f, 0x0002 },
2485 { 0x01, 0x90d0 },
2486 { 0x1f, 0x0000 }
2487 };
2488
françois romieu4da19632011-01-03 15:07:55 +00002489 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002490}
2491
françois romieu4da19632011-01-03 15:07:55 +00002492static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002493{
2494 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002495
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002496 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2497 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002498 return;
2499
françois romieu4da19632011-01-03 15:07:55 +00002500 rtl_writephy(tp, 0x1f, 0x0001);
2501 rtl_writephy(tp, 0x10, 0xf01b);
2502 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002503}
2504
françois romieu4da19632011-01-03 15:07:55 +00002505static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002506{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002507 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002508 { 0x1f, 0x0001 },
2509 { 0x04, 0x0000 },
2510 { 0x03, 0x00a1 },
2511 { 0x02, 0x0008 },
2512 { 0x01, 0x0120 },
2513 { 0x00, 0x1000 },
2514 { 0x04, 0x0800 },
2515 { 0x04, 0x9000 },
2516 { 0x03, 0x802f },
2517 { 0x02, 0x4f02 },
2518 { 0x01, 0x0409 },
2519 { 0x00, 0xf099 },
2520 { 0x04, 0x9800 },
2521 { 0x04, 0xa000 },
2522 { 0x03, 0xdf01 },
2523 { 0x02, 0xdf20 },
2524 { 0x01, 0xff95 },
2525 { 0x00, 0xba00 },
2526 { 0x04, 0xa800 },
2527 { 0x04, 0xf000 },
2528 { 0x03, 0xdf01 },
2529 { 0x02, 0xdf20 },
2530 { 0x01, 0x101a },
2531 { 0x00, 0xa0ff },
2532 { 0x04, 0xf800 },
2533 { 0x04, 0x0000 },
2534 { 0x1f, 0x0000 },
2535
2536 { 0x1f, 0x0001 },
2537 { 0x10, 0xf41b },
2538 { 0x14, 0xfb54 },
2539 { 0x18, 0xf5c7 },
2540 { 0x1f, 0x0000 },
2541
2542 { 0x1f, 0x0001 },
2543 { 0x17, 0x0cc0 },
2544 { 0x1f, 0x0000 }
2545 };
2546
françois romieu4da19632011-01-03 15:07:55 +00002547 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002548
françois romieu4da19632011-01-03 15:07:55 +00002549 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002550}
2551
françois romieu4da19632011-01-03 15:07:55 +00002552static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002553{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002554 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002555 { 0x1f, 0x0001 },
2556 { 0x04, 0x0000 },
2557 { 0x03, 0x00a1 },
2558 { 0x02, 0x0008 },
2559 { 0x01, 0x0120 },
2560 { 0x00, 0x1000 },
2561 { 0x04, 0x0800 },
2562 { 0x04, 0x9000 },
2563 { 0x03, 0x802f },
2564 { 0x02, 0x4f02 },
2565 { 0x01, 0x0409 },
2566 { 0x00, 0xf099 },
2567 { 0x04, 0x9800 },
2568 { 0x04, 0xa000 },
2569 { 0x03, 0xdf01 },
2570 { 0x02, 0xdf20 },
2571 { 0x01, 0xff95 },
2572 { 0x00, 0xba00 },
2573 { 0x04, 0xa800 },
2574 { 0x04, 0xf000 },
2575 { 0x03, 0xdf01 },
2576 { 0x02, 0xdf20 },
2577 { 0x01, 0x101a },
2578 { 0x00, 0xa0ff },
2579 { 0x04, 0xf800 },
2580 { 0x04, 0x0000 },
2581 { 0x1f, 0x0000 },
2582
2583 { 0x1f, 0x0001 },
2584 { 0x0b, 0x8480 },
2585 { 0x1f, 0x0000 },
2586
2587 { 0x1f, 0x0001 },
2588 { 0x18, 0x67c7 },
2589 { 0x04, 0x2000 },
2590 { 0x03, 0x002f },
2591 { 0x02, 0x4360 },
2592 { 0x01, 0x0109 },
2593 { 0x00, 0x3022 },
2594 { 0x04, 0x2800 },
2595 { 0x1f, 0x0000 },
2596
2597 { 0x1f, 0x0001 },
2598 { 0x17, 0x0cc0 },
2599 { 0x1f, 0x0000 }
2600 };
2601
françois romieu4da19632011-01-03 15:07:55 +00002602 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002603}
2604
françois romieu4da19632011-01-03 15:07:55 +00002605static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002606{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002607 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002608 { 0x10, 0xf41b },
2609 { 0x1f, 0x0000 }
2610 };
2611
françois romieu4da19632011-01-03 15:07:55 +00002612 rtl_writephy(tp, 0x1f, 0x0001);
2613 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002614
françois romieu4da19632011-01-03 15:07:55 +00002615 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002616}
2617
françois romieu4da19632011-01-03 15:07:55 +00002618static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002619{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002620 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002621 { 0x1f, 0x0001 },
2622 { 0x10, 0xf41b },
2623 { 0x1f, 0x0000 }
2624 };
2625
françois romieu4da19632011-01-03 15:07:55 +00002626 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002627}
2628
françois romieu4da19632011-01-03 15:07:55 +00002629static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002630{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002631 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002632 { 0x1f, 0x0000 },
2633 { 0x1d, 0x0f00 },
2634 { 0x1f, 0x0002 },
2635 { 0x0c, 0x1ec8 },
2636 { 0x1f, 0x0000 }
2637 };
2638
françois romieu4da19632011-01-03 15:07:55 +00002639 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002640}
2641
françois romieu4da19632011-01-03 15:07:55 +00002642static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002643{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002644 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002645 { 0x1f, 0x0001 },
2646 { 0x1d, 0x3d98 },
2647 { 0x1f, 0x0000 }
2648 };
2649
françois romieu4da19632011-01-03 15:07:55 +00002650 rtl_writephy(tp, 0x1f, 0x0000);
2651 rtl_patchphy(tp, 0x14, 1 << 5);
2652 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002653
françois romieu4da19632011-01-03 15:07:55 +00002654 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002655}
2656
françois romieu4da19632011-01-03 15:07:55 +00002657static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002658{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002659 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002660 { 0x1f, 0x0001 },
2661 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002662 { 0x1f, 0x0002 },
2663 { 0x00, 0x88d4 },
2664 { 0x01, 0x82b1 },
2665 { 0x03, 0x7002 },
2666 { 0x08, 0x9e30 },
2667 { 0x09, 0x01f0 },
2668 { 0x0a, 0x5500 },
2669 { 0x0c, 0x00c8 },
2670 { 0x1f, 0x0003 },
2671 { 0x12, 0xc096 },
2672 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002673 { 0x1f, 0x0000 },
2674 { 0x1f, 0x0000 },
2675 { 0x09, 0x2000 },
2676 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002677 };
2678
françois romieu4da19632011-01-03 15:07:55 +00002679 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002680
françois romieu4da19632011-01-03 15:07:55 +00002681 rtl_patchphy(tp, 0x14, 1 << 5);
2682 rtl_patchphy(tp, 0x0d, 1 << 5);
2683 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002684}
2685
françois romieu4da19632011-01-03 15:07:55 +00002686static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002687{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002688 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002689 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002690 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002691 { 0x03, 0x802f },
2692 { 0x02, 0x4f02 },
2693 { 0x01, 0x0409 },
2694 { 0x00, 0xf099 },
2695 { 0x04, 0x9800 },
2696 { 0x04, 0x9000 },
2697 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002698 { 0x1f, 0x0002 },
2699 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002700 { 0x06, 0x0761 },
2701 { 0x1f, 0x0003 },
2702 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002703 { 0x1f, 0x0000 }
2704 };
2705
françois romieu4da19632011-01-03 15:07:55 +00002706 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002707
françois romieu4da19632011-01-03 15:07:55 +00002708 rtl_patchphy(tp, 0x16, 1 << 0);
2709 rtl_patchphy(tp, 0x14, 1 << 5);
2710 rtl_patchphy(tp, 0x0d, 1 << 5);
2711 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002712}
2713
françois romieu4da19632011-01-03 15:07:55 +00002714static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002715{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002716 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002717 { 0x1f, 0x0001 },
2718 { 0x12, 0x2300 },
2719 { 0x1d, 0x3d98 },
2720 { 0x1f, 0x0002 },
2721 { 0x0c, 0x7eb8 },
2722 { 0x06, 0x5461 },
2723 { 0x1f, 0x0003 },
2724 { 0x16, 0x0f0a },
2725 { 0x1f, 0x0000 }
2726 };
2727
françois romieu4da19632011-01-03 15:07:55 +00002728 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002729
françois romieu4da19632011-01-03 15:07:55 +00002730 rtl_patchphy(tp, 0x16, 1 << 0);
2731 rtl_patchphy(tp, 0x14, 1 << 5);
2732 rtl_patchphy(tp, 0x0d, 1 << 5);
2733 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002734}
2735
françois romieu4da19632011-01-03 15:07:55 +00002736static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002737{
françois romieu4da19632011-01-03 15:07:55 +00002738 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002739}
2740
françois romieubca03d52011-01-03 15:07:31 +00002741static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002742{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002743 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002744 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002745 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002746 { 0x06, 0x4064 },
2747 { 0x07, 0x2863 },
2748 { 0x08, 0x059c },
2749 { 0x09, 0x26b4 },
2750 { 0x0a, 0x6a19 },
2751 { 0x0b, 0xdcc8 },
2752 { 0x10, 0xf06d },
2753 { 0x14, 0x7f68 },
2754 { 0x18, 0x7fd9 },
2755 { 0x1c, 0xf0ff },
2756 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002757 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002758 { 0x12, 0xf49f },
2759 { 0x13, 0x070b },
2760 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002761 { 0x14, 0x94c0 },
2762
2763 /*
2764 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002765 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002766 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002767 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002768 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002769 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002770 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002771 { 0x06, 0x5561 },
2772
2773 /*
2774 * Can not link to 1Gbps with bad cable
2775 * Decrease SNR threshold form 21.07dB to 19.04dB
2776 */
2777 { 0x1f, 0x0001 },
2778 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002779
2780 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002781 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002782 };
2783
françois romieu4da19632011-01-03 15:07:55 +00002784 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002785
françois romieubca03d52011-01-03 15:07:31 +00002786 /*
2787 * Rx Error Issue
2788 * Fine Tune Switching regulator parameter
2789 */
françois romieu4da19632011-01-03 15:07:55 +00002790 rtl_writephy(tp, 0x1f, 0x0002);
2791 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2792 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002793
Francois Romieufdf6fc02012-07-06 22:40:38 +02002794 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002795 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002796 { 0x1f, 0x0002 },
2797 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002798 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002799 { 0x05, 0x8330 },
2800 { 0x06, 0x669a },
2801 { 0x1f, 0x0002 }
2802 };
2803 int val;
2804
françois romieu4da19632011-01-03 15:07:55 +00002805 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002806
françois romieu4da19632011-01-03 15:07:55 +00002807 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002808
2809 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002810 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002811 0x0065, 0x0066, 0x0067, 0x0068,
2812 0x0069, 0x006a, 0x006b, 0x006c
2813 };
2814 int i;
2815
françois romieu4da19632011-01-03 15:07:55 +00002816 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002817
2818 val &= 0xff00;
2819 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002820 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002821 }
2822 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002823 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002824 { 0x1f, 0x0002 },
2825 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002826 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002827 { 0x05, 0x8330 },
2828 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002829 };
2830
françois romieu4da19632011-01-03 15:07:55 +00002831 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002832 }
2833
françois romieubca03d52011-01-03 15:07:31 +00002834 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002835 rtl_writephy(tp, 0x1f, 0x0002);
2836 rtl_patchphy(tp, 0x0d, 0x0300);
2837 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002838
françois romieubca03d52011-01-03 15:07:31 +00002839 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002840 rtl_writephy(tp, 0x1f, 0x0002);
2841 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2842 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002843
françois romieu4da19632011-01-03 15:07:55 +00002844 rtl_writephy(tp, 0x1f, 0x0005);
2845 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002846
2847 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002848
françois romieu4da19632011-01-03 15:07:55 +00002849 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002850}
2851
françois romieubca03d52011-01-03 15:07:31 +00002852static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002853{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002854 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002855 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002856 { 0x1f, 0x0001 },
2857 { 0x06, 0x4064 },
2858 { 0x07, 0x2863 },
2859 { 0x08, 0x059c },
2860 { 0x09, 0x26b4 },
2861 { 0x0a, 0x6a19 },
2862 { 0x0b, 0xdcc8 },
2863 { 0x10, 0xf06d },
2864 { 0x14, 0x7f68 },
2865 { 0x18, 0x7fd9 },
2866 { 0x1c, 0xf0ff },
2867 { 0x1d, 0x3d9c },
2868 { 0x1f, 0x0003 },
2869 { 0x12, 0xf49f },
2870 { 0x13, 0x070b },
2871 { 0x1a, 0x05ad },
2872 { 0x14, 0x94c0 },
2873
françois romieubca03d52011-01-03 15:07:31 +00002874 /*
2875 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002876 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002877 */
françois romieudaf9df62009-10-07 12:44:20 +00002878 { 0x1f, 0x0002 },
2879 { 0x06, 0x5561 },
2880 { 0x1f, 0x0005 },
2881 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002882 { 0x06, 0x5561 },
2883
2884 /*
2885 * Can not link to 1Gbps with bad cable
2886 * Decrease SNR threshold form 21.07dB to 19.04dB
2887 */
2888 { 0x1f, 0x0001 },
2889 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002890
2891 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002892 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002893 };
2894
françois romieu4da19632011-01-03 15:07:55 +00002895 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002896
Francois Romieufdf6fc02012-07-06 22:40:38 +02002897 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002898 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002899 { 0x1f, 0x0002 },
2900 { 0x05, 0x669a },
2901 { 0x1f, 0x0005 },
2902 { 0x05, 0x8330 },
2903 { 0x06, 0x669a },
2904
2905 { 0x1f, 0x0002 }
2906 };
2907 int val;
2908
françois romieu4da19632011-01-03 15:07:55 +00002909 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002910
françois romieu4da19632011-01-03 15:07:55 +00002911 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002912 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002913 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002914 0x0065, 0x0066, 0x0067, 0x0068,
2915 0x0069, 0x006a, 0x006b, 0x006c
2916 };
2917 int i;
2918
françois romieu4da19632011-01-03 15:07:55 +00002919 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002920
2921 val &= 0xff00;
2922 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002923 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002924 }
2925 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002926 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002927 { 0x1f, 0x0002 },
2928 { 0x05, 0x2642 },
2929 { 0x1f, 0x0005 },
2930 { 0x05, 0x8330 },
2931 { 0x06, 0x2642 }
2932 };
2933
françois romieu4da19632011-01-03 15:07:55 +00002934 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002935 }
2936
françois romieubca03d52011-01-03 15:07:31 +00002937 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002938 rtl_writephy(tp, 0x1f, 0x0002);
2939 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2940 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002941
françois romieubca03d52011-01-03 15:07:31 +00002942 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002943 rtl_writephy(tp, 0x1f, 0x0002);
2944 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002945
françois romieu4da19632011-01-03 15:07:55 +00002946 rtl_writephy(tp, 0x1f, 0x0005);
2947 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002948
2949 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002950
françois romieu4da19632011-01-03 15:07:55 +00002951 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002952}
2953
françois romieu4da19632011-01-03 15:07:55 +00002954static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002955{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002956 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002957 { 0x1f, 0x0002 },
2958 { 0x10, 0x0008 },
2959 { 0x0d, 0x006c },
2960
2961 { 0x1f, 0x0000 },
2962 { 0x0d, 0xf880 },
2963
2964 { 0x1f, 0x0001 },
2965 { 0x17, 0x0cc0 },
2966
2967 { 0x1f, 0x0001 },
2968 { 0x0b, 0xa4d8 },
2969 { 0x09, 0x281c },
2970 { 0x07, 0x2883 },
2971 { 0x0a, 0x6b35 },
2972 { 0x1d, 0x3da4 },
2973 { 0x1c, 0xeffd },
2974 { 0x14, 0x7f52 },
2975 { 0x18, 0x7fc6 },
2976 { 0x08, 0x0601 },
2977 { 0x06, 0x4063 },
2978 { 0x10, 0xf074 },
2979 { 0x1f, 0x0003 },
2980 { 0x13, 0x0789 },
2981 { 0x12, 0xf4bd },
2982 { 0x1a, 0x04fd },
2983 { 0x14, 0x84b0 },
2984 { 0x1f, 0x0000 },
2985 { 0x00, 0x9200 },
2986
2987 { 0x1f, 0x0005 },
2988 { 0x01, 0x0340 },
2989 { 0x1f, 0x0001 },
2990 { 0x04, 0x4000 },
2991 { 0x03, 0x1d21 },
2992 { 0x02, 0x0c32 },
2993 { 0x01, 0x0200 },
2994 { 0x00, 0x5554 },
2995 { 0x04, 0x4800 },
2996 { 0x04, 0x4000 },
2997 { 0x04, 0xf000 },
2998 { 0x03, 0xdf01 },
2999 { 0x02, 0xdf20 },
3000 { 0x01, 0x101a },
3001 { 0x00, 0xa0ff },
3002 { 0x04, 0xf800 },
3003 { 0x04, 0xf000 },
3004 { 0x1f, 0x0000 },
3005
3006 { 0x1f, 0x0007 },
3007 { 0x1e, 0x0023 },
3008 { 0x16, 0x0000 },
3009 { 0x1f, 0x0000 }
3010 };
3011
françois romieu4da19632011-01-03 15:07:55 +00003012 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02003013}
3014
françois romieue6de30d2011-01-03 15:08:37 +00003015static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3016{
3017 static const struct phy_reg phy_reg_init[] = {
3018 { 0x1f, 0x0001 },
3019 { 0x17, 0x0cc0 },
3020
3021 { 0x1f, 0x0007 },
3022 { 0x1e, 0x002d },
3023 { 0x18, 0x0040 },
3024 { 0x1f, 0x0000 }
3025 };
3026
3027 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3028 rtl_patchphy(tp, 0x0d, 1 << 5);
3029}
3030
Hayes Wang70090422011-07-06 15:58:06 +08003031static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003032{
3033 static const struct phy_reg phy_reg_init[] = {
3034 /* Enable Delay cap */
3035 { 0x1f, 0x0005 },
3036 { 0x05, 0x8b80 },
3037 { 0x06, 0xc896 },
3038 { 0x1f, 0x0000 },
3039
3040 /* Channel estimation fine tune */
3041 { 0x1f, 0x0001 },
3042 { 0x0b, 0x6c20 },
3043 { 0x07, 0x2872 },
3044 { 0x1c, 0xefff },
3045 { 0x1f, 0x0003 },
3046 { 0x14, 0x6420 },
3047 { 0x1f, 0x0000 },
3048
3049 /* Update PFM & 10M TX idle timer */
3050 { 0x1f, 0x0007 },
3051 { 0x1e, 0x002f },
3052 { 0x15, 0x1919 },
3053 { 0x1f, 0x0000 },
3054
3055 { 0x1f, 0x0007 },
3056 { 0x1e, 0x00ac },
3057 { 0x18, 0x0006 },
3058 { 0x1f, 0x0000 }
3059 };
3060
Francois Romieu15ecd032011-04-27 13:52:22 -07003061 rtl_apply_firmware(tp);
3062
hayeswang01dc7fe2011-03-21 01:50:28 +00003063 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3064
3065 /* DCO enable for 10M IDLE Power */
3066 rtl_writephy(tp, 0x1f, 0x0007);
3067 rtl_writephy(tp, 0x1e, 0x0023);
3068 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3069 rtl_writephy(tp, 0x1f, 0x0000);
3070
3071 /* For impedance matching */
3072 rtl_writephy(tp, 0x1f, 0x0002);
3073 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003074 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003075
3076 /* PHY auto speed down */
3077 rtl_writephy(tp, 0x1f, 0x0007);
3078 rtl_writephy(tp, 0x1e, 0x002d);
3079 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3080 rtl_writephy(tp, 0x1f, 0x0000);
3081 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3082
3083 rtl_writephy(tp, 0x1f, 0x0005);
3084 rtl_writephy(tp, 0x05, 0x8b86);
3085 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3086 rtl_writephy(tp, 0x1f, 0x0000);
3087
3088 rtl_writephy(tp, 0x1f, 0x0005);
3089 rtl_writephy(tp, 0x05, 0x8b85);
3090 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3091 rtl_writephy(tp, 0x1f, 0x0007);
3092 rtl_writephy(tp, 0x1e, 0x0020);
3093 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3094 rtl_writephy(tp, 0x1f, 0x0006);
3095 rtl_writephy(tp, 0x00, 0x5a00);
3096 rtl_writephy(tp, 0x1f, 0x0000);
3097 rtl_writephy(tp, 0x0d, 0x0007);
3098 rtl_writephy(tp, 0x0e, 0x003c);
3099 rtl_writephy(tp, 0x0d, 0x4007);
3100 rtl_writephy(tp, 0x0e, 0x0000);
3101 rtl_writephy(tp, 0x0d, 0x0000);
3102}
3103
Hayes Wang70090422011-07-06 15:58:06 +08003104static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3105{
3106 static const struct phy_reg phy_reg_init[] = {
3107 /* Enable Delay cap */
3108 { 0x1f, 0x0004 },
3109 { 0x1f, 0x0007 },
3110 { 0x1e, 0x00ac },
3111 { 0x18, 0x0006 },
3112 { 0x1f, 0x0002 },
3113 { 0x1f, 0x0000 },
3114 { 0x1f, 0x0000 },
3115
3116 /* Channel estimation fine tune */
3117 { 0x1f, 0x0003 },
3118 { 0x09, 0xa20f },
3119 { 0x1f, 0x0000 },
3120 { 0x1f, 0x0000 },
3121
3122 /* Green Setting */
3123 { 0x1f, 0x0005 },
3124 { 0x05, 0x8b5b },
3125 { 0x06, 0x9222 },
3126 { 0x05, 0x8b6d },
3127 { 0x06, 0x8000 },
3128 { 0x05, 0x8b76 },
3129 { 0x06, 0x8000 },
3130 { 0x1f, 0x0000 }
3131 };
3132
3133 rtl_apply_firmware(tp);
3134
3135 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3136
3137 /* For 4-corner performance improve */
3138 rtl_writephy(tp, 0x1f, 0x0005);
3139 rtl_writephy(tp, 0x05, 0x8b80);
3140 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3141 rtl_writephy(tp, 0x1f, 0x0000);
3142
3143 /* PHY auto speed down */
3144 rtl_writephy(tp, 0x1f, 0x0004);
3145 rtl_writephy(tp, 0x1f, 0x0007);
3146 rtl_writephy(tp, 0x1e, 0x002d);
3147 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3148 rtl_writephy(tp, 0x1f, 0x0002);
3149 rtl_writephy(tp, 0x1f, 0x0000);
3150 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3151
3152 /* improve 10M EEE waveform */
3153 rtl_writephy(tp, 0x1f, 0x0005);
3154 rtl_writephy(tp, 0x05, 0x8b86);
3155 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3156 rtl_writephy(tp, 0x1f, 0x0000);
3157
3158 /* Improve 2-pair detection performance */
3159 rtl_writephy(tp, 0x1f, 0x0005);
3160 rtl_writephy(tp, 0x05, 0x8b85);
3161 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3162 rtl_writephy(tp, 0x1f, 0x0000);
3163
3164 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003165 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003166 rtl_writephy(tp, 0x1f, 0x0005);
3167 rtl_writephy(tp, 0x05, 0x8b85);
3168 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3169 rtl_writephy(tp, 0x1f, 0x0004);
3170 rtl_writephy(tp, 0x1f, 0x0007);
3171 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003172 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003173 rtl_writephy(tp, 0x1f, 0x0002);
3174 rtl_writephy(tp, 0x1f, 0x0000);
3175 rtl_writephy(tp, 0x0d, 0x0007);
3176 rtl_writephy(tp, 0x0e, 0x003c);
3177 rtl_writephy(tp, 0x0d, 0x4007);
3178 rtl_writephy(tp, 0x0e, 0x0000);
3179 rtl_writephy(tp, 0x0d, 0x0000);
3180
3181 /* Green feature */
3182 rtl_writephy(tp, 0x1f, 0x0003);
3183 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3184 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3185 rtl_writephy(tp, 0x1f, 0x0000);
3186}
3187
Hayes Wang5f886e02012-03-30 14:33:03 +08003188static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3189{
3190 /* For 4-corner performance improve */
3191 rtl_writephy(tp, 0x1f, 0x0005);
3192 rtl_writephy(tp, 0x05, 0x8b80);
3193 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3194 rtl_writephy(tp, 0x1f, 0x0000);
3195
3196 /* PHY auto speed down */
3197 rtl_writephy(tp, 0x1f, 0x0007);
3198 rtl_writephy(tp, 0x1e, 0x002d);
3199 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3200 rtl_writephy(tp, 0x1f, 0x0000);
3201 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3202
3203 /* Improve 10M EEE waveform */
3204 rtl_writephy(tp, 0x1f, 0x0005);
3205 rtl_writephy(tp, 0x05, 0x8b86);
3206 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3207 rtl_writephy(tp, 0x1f, 0x0000);
3208}
3209
Hayes Wangc2218922011-09-06 16:55:18 +08003210static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3211{
3212 static const struct phy_reg phy_reg_init[] = {
3213 /* Channel estimation fine tune */
3214 { 0x1f, 0x0003 },
3215 { 0x09, 0xa20f },
3216 { 0x1f, 0x0000 },
3217
3218 /* Modify green table for giga & fnet */
3219 { 0x1f, 0x0005 },
3220 { 0x05, 0x8b55 },
3221 { 0x06, 0x0000 },
3222 { 0x05, 0x8b5e },
3223 { 0x06, 0x0000 },
3224 { 0x05, 0x8b67 },
3225 { 0x06, 0x0000 },
3226 { 0x05, 0x8b70 },
3227 { 0x06, 0x0000 },
3228 { 0x1f, 0x0000 },
3229 { 0x1f, 0x0007 },
3230 { 0x1e, 0x0078 },
3231 { 0x17, 0x0000 },
3232 { 0x19, 0x00fb },
3233 { 0x1f, 0x0000 },
3234
3235 /* Modify green table for 10M */
3236 { 0x1f, 0x0005 },
3237 { 0x05, 0x8b79 },
3238 { 0x06, 0xaa00 },
3239 { 0x1f, 0x0000 },
3240
3241 /* Disable hiimpedance detection (RTCT) */
3242 { 0x1f, 0x0003 },
3243 { 0x01, 0x328a },
3244 { 0x1f, 0x0000 }
3245 };
3246
3247 rtl_apply_firmware(tp);
3248
3249 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3250
Hayes Wang5f886e02012-03-30 14:33:03 +08003251 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003252
3253 /* Improve 2-pair detection performance */
3254 rtl_writephy(tp, 0x1f, 0x0005);
3255 rtl_writephy(tp, 0x05, 0x8b85);
3256 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3257 rtl_writephy(tp, 0x1f, 0x0000);
3258}
3259
3260static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3261{
3262 rtl_apply_firmware(tp);
3263
Hayes Wang5f886e02012-03-30 14:33:03 +08003264 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003265}
3266
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003267static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3268{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003269 static const struct phy_reg phy_reg_init[] = {
3270 /* Channel estimation fine tune */
3271 { 0x1f, 0x0003 },
3272 { 0x09, 0xa20f },
3273 { 0x1f, 0x0000 },
3274
3275 /* Modify green table for giga & fnet */
3276 { 0x1f, 0x0005 },
3277 { 0x05, 0x8b55 },
3278 { 0x06, 0x0000 },
3279 { 0x05, 0x8b5e },
3280 { 0x06, 0x0000 },
3281 { 0x05, 0x8b67 },
3282 { 0x06, 0x0000 },
3283 { 0x05, 0x8b70 },
3284 { 0x06, 0x0000 },
3285 { 0x1f, 0x0000 },
3286 { 0x1f, 0x0007 },
3287 { 0x1e, 0x0078 },
3288 { 0x17, 0x0000 },
3289 { 0x19, 0x00aa },
3290 { 0x1f, 0x0000 },
3291
3292 /* Modify green table for 10M */
3293 { 0x1f, 0x0005 },
3294 { 0x05, 0x8b79 },
3295 { 0x06, 0xaa00 },
3296 { 0x1f, 0x0000 },
3297
3298 /* Disable hiimpedance detection (RTCT) */
3299 { 0x1f, 0x0003 },
3300 { 0x01, 0x328a },
3301 { 0x1f, 0x0000 }
3302 };
3303
3304
3305 rtl_apply_firmware(tp);
3306
3307 rtl8168f_hw_phy_config(tp);
3308
3309 /* Improve 2-pair detection performance */
3310 rtl_writephy(tp, 0x1f, 0x0005);
3311 rtl_writephy(tp, 0x05, 0x8b85);
3312 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3313 rtl_writephy(tp, 0x1f, 0x0000);
3314
3315 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3316
3317 /* Modify green table for giga */
3318 rtl_writephy(tp, 0x1f, 0x0005);
3319 rtl_writephy(tp, 0x05, 0x8b54);
3320 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3321 rtl_writephy(tp, 0x05, 0x8b5d);
3322 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3323 rtl_writephy(tp, 0x05, 0x8a7c);
3324 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3325 rtl_writephy(tp, 0x05, 0x8a7f);
3326 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3327 rtl_writephy(tp, 0x05, 0x8a82);
3328 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3329 rtl_writephy(tp, 0x05, 0x8a85);
3330 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3331 rtl_writephy(tp, 0x05, 0x8a88);
3332 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3333 rtl_writephy(tp, 0x1f, 0x0000);
3334
3335 /* uc same-seed solution */
3336 rtl_writephy(tp, 0x1f, 0x0005);
3337 rtl_writephy(tp, 0x05, 0x8b85);
3338 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3339 rtl_writephy(tp, 0x1f, 0x0000);
3340
3341 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003342 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003343 rtl_writephy(tp, 0x1f, 0x0005);
3344 rtl_writephy(tp, 0x05, 0x8b85);
3345 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3346 rtl_writephy(tp, 0x1f, 0x0004);
3347 rtl_writephy(tp, 0x1f, 0x0007);
3348 rtl_writephy(tp, 0x1e, 0x0020);
3349 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3350 rtl_writephy(tp, 0x1f, 0x0000);
3351 rtl_writephy(tp, 0x0d, 0x0007);
3352 rtl_writephy(tp, 0x0e, 0x003c);
3353 rtl_writephy(tp, 0x0d, 0x4007);
3354 rtl_writephy(tp, 0x0e, 0x0000);
3355 rtl_writephy(tp, 0x0d, 0x0000);
3356
3357 /* Green feature */
3358 rtl_writephy(tp, 0x1f, 0x0003);
3359 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3360 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3361 rtl_writephy(tp, 0x1f, 0x0000);
3362}
3363
Hayes Wangc5583862012-07-02 17:23:22 +08003364static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3365{
3366 static const u16 mac_ocp_patch[] = {
3367 0xe008, 0xe01b, 0xe01d, 0xe01f,
3368 0xe021, 0xe023, 0xe025, 0xe027,
3369 0x49d2, 0xf10d, 0x766c, 0x49e2,
3370 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3371
3372 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3373 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3374 0xbe00, 0xb416, 0x0076, 0xe86c,
3375 0xc602, 0xbe00, 0x0000, 0xc602,
3376
3377 0xbe00, 0x0000, 0xc602, 0xbe00,
3378 0x0000, 0xc602, 0xbe00, 0x0000,
3379 0xc602, 0xbe00, 0x0000, 0xc602,
3380 0xbe00, 0x0000, 0xc602, 0xbe00,
3381
3382 0x0000, 0x0000, 0x0000, 0x0000
3383 };
3384 u32 i;
3385
3386 /* Patch code for GPHY reset */
3387 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3388 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3389 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3390 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3391
3392 rtl_apply_firmware(tp);
3393
3394 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3395 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3396 else
3397 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3398
3399 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3400 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3401 else
3402 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3403
3404 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3405 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3406
3407 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3408 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3409
3410 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3411}
3412
françois romieu4da19632011-01-03 15:07:55 +00003413static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003414{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003415 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003416 { 0x1f, 0x0003 },
3417 { 0x08, 0x441d },
3418 { 0x01, 0x9100 },
3419 { 0x1f, 0x0000 }
3420 };
3421
françois romieu4da19632011-01-03 15:07:55 +00003422 rtl_writephy(tp, 0x1f, 0x0000);
3423 rtl_patchphy(tp, 0x11, 1 << 12);
3424 rtl_patchphy(tp, 0x19, 1 << 13);
3425 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003426
françois romieu4da19632011-01-03 15:07:55 +00003427 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003428}
3429
Hayes Wang5a5e4442011-02-22 17:26:21 +08003430static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3431{
3432 static const struct phy_reg phy_reg_init[] = {
3433 { 0x1f, 0x0005 },
3434 { 0x1a, 0x0000 },
3435 { 0x1f, 0x0000 },
3436
3437 { 0x1f, 0x0004 },
3438 { 0x1c, 0x0000 },
3439 { 0x1f, 0x0000 },
3440
3441 { 0x1f, 0x0001 },
3442 { 0x15, 0x7701 },
3443 { 0x1f, 0x0000 }
3444 };
3445
3446 /* Disable ALDPS before ram code */
3447 rtl_writephy(tp, 0x1f, 0x0000);
3448 rtl_writephy(tp, 0x18, 0x0310);
3449 msleep(100);
3450
François Romieu953a12c2011-04-24 17:38:48 +02003451 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003452
3453 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3454}
3455
Hayes Wang7e18dca2012-03-30 14:33:02 +08003456static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3457{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003458 /* Disable ALDPS before setting firmware */
3459 rtl_writephy(tp, 0x1f, 0x0000);
3460 rtl_writephy(tp, 0x18, 0x0310);
3461 msleep(20);
3462
3463 rtl_apply_firmware(tp);
3464
3465 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003466 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003467 rtl_writephy(tp, 0x1f, 0x0004);
3468 rtl_writephy(tp, 0x10, 0x401f);
3469 rtl_writephy(tp, 0x19, 0x7030);
3470 rtl_writephy(tp, 0x1f, 0x0000);
3471}
3472
Hayes Wang5598bfe2012-07-02 17:23:21 +08003473static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3474{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003475 static const struct phy_reg phy_reg_init[] = {
3476 { 0x1f, 0x0004 },
3477 { 0x10, 0xc07f },
3478 { 0x19, 0x7030 },
3479 { 0x1f, 0x0000 }
3480 };
3481
3482 /* Disable ALDPS before ram code */
3483 rtl_writephy(tp, 0x1f, 0x0000);
3484 rtl_writephy(tp, 0x18, 0x0310);
3485 msleep(100);
3486
3487 rtl_apply_firmware(tp);
3488
Francois Romieufdf6fc02012-07-06 22:40:38 +02003489 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003490 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3491
Francois Romieufdf6fc02012-07-06 22:40:38 +02003492 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003493}
3494
Francois Romieu5615d9f2007-08-17 17:50:46 +02003495static void rtl_hw_phy_config(struct net_device *dev)
3496{
3497 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003498
3499 rtl8169_print_mac_version(tp);
3500
3501 switch (tp->mac_version) {
3502 case RTL_GIGA_MAC_VER_01:
3503 break;
3504 case RTL_GIGA_MAC_VER_02:
3505 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003506 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003507 break;
3508 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003509 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003510 break;
françois romieu2e9558562009-08-10 19:44:19 +00003511 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003512 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003513 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003514 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003515 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003516 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003517 case RTL_GIGA_MAC_VER_07:
3518 case RTL_GIGA_MAC_VER_08:
3519 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003520 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003521 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003522 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003523 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003524 break;
3525 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003526 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003527 break;
3528 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003529 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003530 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003531 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003532 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003533 break;
3534 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003535 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003536 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003537 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003538 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003539 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003540 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003541 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003542 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003543 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003544 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003545 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003546 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003547 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003548 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003549 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003550 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003551 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003552 break;
3553 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003554 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003555 break;
3556 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003557 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003558 break;
françois romieue6de30d2011-01-03 15:08:37 +00003559 case RTL_GIGA_MAC_VER_28:
3560 rtl8168d_4_hw_phy_config(tp);
3561 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003562 case RTL_GIGA_MAC_VER_29:
3563 case RTL_GIGA_MAC_VER_30:
3564 rtl8105e_hw_phy_config(tp);
3565 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003566 case RTL_GIGA_MAC_VER_31:
3567 /* None. */
3568 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003569 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003570 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003571 rtl8168e_1_hw_phy_config(tp);
3572 break;
3573 case RTL_GIGA_MAC_VER_34:
3574 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003575 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003576 case RTL_GIGA_MAC_VER_35:
3577 rtl8168f_1_hw_phy_config(tp);
3578 break;
3579 case RTL_GIGA_MAC_VER_36:
3580 rtl8168f_2_hw_phy_config(tp);
3581 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003582
Hayes Wang7e18dca2012-03-30 14:33:02 +08003583 case RTL_GIGA_MAC_VER_37:
3584 rtl8402_hw_phy_config(tp);
3585 break;
3586
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003587 case RTL_GIGA_MAC_VER_38:
3588 rtl8411_hw_phy_config(tp);
3589 break;
3590
Hayes Wang5598bfe2012-07-02 17:23:21 +08003591 case RTL_GIGA_MAC_VER_39:
3592 rtl8106e_hw_phy_config(tp);
3593 break;
3594
Hayes Wangc5583862012-07-02 17:23:22 +08003595 case RTL_GIGA_MAC_VER_40:
3596 rtl8168g_1_hw_phy_config(tp);
3597 break;
3598
3599 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003600 default:
3601 break;
3602 }
3603}
3604
Francois Romieuda78dbf2012-01-26 14:18:23 +01003605static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 struct timer_list *timer = &tp->timer;
3608 void __iomem *ioaddr = tp->mmio_addr;
3609 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3610
Francois Romieubcf0bf92006-07-26 23:14:13 +02003611 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
françois romieu4da19632011-01-03 15:07:55 +00003613 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003614 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 * A busy loop could burn quite a few cycles on nowadays CPU.
3616 * Let's delay the execution of the timer for a few ticks.
3617 */
3618 timeout = HZ/10;
3619 goto out_mod_timer;
3620 }
3621
3622 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003623 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624
Francois Romieuda78dbf2012-01-26 14:18:23 +01003625 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626
françois romieu4da19632011-01-03 15:07:55 +00003627 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
3629out_mod_timer:
3630 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003631}
3632
3633static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3634{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003635 if (!test_and_set_bit(flag, tp->wk.flags))
3636 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003637}
3638
3639static void rtl8169_phy_timer(unsigned long __opaque)
3640{
3641 struct net_device *dev = (struct net_device *)__opaque;
3642 struct rtl8169_private *tp = netdev_priv(dev);
3643
Francois Romieu98ddf982012-01-31 10:47:34 +01003644 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645}
3646
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3648 void __iomem *ioaddr)
3649{
3650 iounmap(ioaddr);
3651 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003652 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 pci_disable_device(pdev);
3654 free_netdev(dev);
3655}
3656
Francois Romieuffc46952012-07-06 14:19:23 +02003657DECLARE_RTL_COND(rtl_phy_reset_cond)
3658{
3659 return tp->phy_reset_pending(tp);
3660}
3661
Francois Romieubf793292006-11-01 00:53:05 +01003662static void rtl8169_phy_reset(struct net_device *dev,
3663 struct rtl8169_private *tp)
3664{
françois romieu4da19632011-01-03 15:07:55 +00003665 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003666 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003667}
3668
David S. Miller8decf862011-09-22 03:23:13 -04003669static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3670{
3671 void __iomem *ioaddr = tp->mmio_addr;
3672
3673 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3674 (RTL_R8(PHYstatus) & TBI_Enable);
3675}
3676
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003677static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003679 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003680
Francois Romieu5615d9f2007-08-17 17:50:46 +02003681 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003682
Marcus Sundberg773328942008-07-10 21:28:08 +02003683 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3684 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3685 RTL_W8(0x82, 0x01);
3686 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003687
Francois Romieu6dccd162007-02-13 23:38:05 +01003688 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3689
3690 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3691 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003692
Francois Romieubcf0bf92006-07-26 23:14:13 +02003693 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003694 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3695 RTL_W8(0x82, 0x01);
3696 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003697 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003698 }
3699
Francois Romieubf793292006-11-01 00:53:05 +01003700 rtl8169_phy_reset(dev, tp);
3701
Oliver Neukum54405cd2011-01-06 21:55:13 +01003702 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003703 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3704 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3705 (tp->mii.supports_gmii ?
3706 ADVERTISED_1000baseT_Half |
3707 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003708
David S. Miller8decf862011-09-22 03:23:13 -04003709 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003710 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003711}
3712
Francois Romieu773d2022007-01-31 23:47:43 +01003713static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3714{
3715 void __iomem *ioaddr = tp->mmio_addr;
3716 u32 high;
3717 u32 low;
3718
3719 low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
3720 high = addr[4] | (addr[5] << 8);
3721
Francois Romieuda78dbf2012-01-26 14:18:23 +01003722 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003723
3724 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2bf2010-04-26 11:42:58 +00003725
Francois Romieu773d2022007-01-31 23:47:43 +01003726 RTL_W32(MAC4, high);
françois romieu908ba2bf2010-04-26 11:42:58 +00003727 RTL_R32(MAC4);
3728
Francois Romieu78f1cd02010-03-27 19:35:46 -07003729 RTL_W32(MAC0, low);
françois romieu908ba2bf2010-04-26 11:42:58 +00003730 RTL_R32(MAC0);
3731
françois romieuc28aa382011-08-02 03:53:43 +00003732 if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
3733 const struct exgmac_reg e[] = {
3734 { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
3735 { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
3736 { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
3737 { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
3738 low >> 16 },
3739 };
3740
Francois Romieufdf6fc02012-07-06 22:40:38 +02003741 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
françois romieuc28aa382011-08-02 03:53:43 +00003742 }
3743
Francois Romieu773d2022007-01-31 23:47:43 +01003744 RTL_W8(Cfg9346, Cfg9346_Lock);
3745
Francois Romieuda78dbf2012-01-26 14:18:23 +01003746 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003747}
3748
3749static int rtl_set_mac_address(struct net_device *dev, void *p)
3750{
3751 struct rtl8169_private *tp = netdev_priv(dev);
3752 struct sockaddr *addr = p;
3753
3754 if (!is_valid_ether_addr(addr->sa_data))
3755 return -EADDRNOTAVAIL;
3756
3757 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3758
3759 rtl_rar_set(tp, dev->dev_addr);
3760
3761 return 0;
3762}
3763
Francois Romieu5f787a12006-08-17 13:02:36 +02003764static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3765{
3766 struct rtl8169_private *tp = netdev_priv(dev);
3767 struct mii_ioctl_data *data = if_mii(ifr);
3768
Francois Romieu8b4ab282008-11-19 22:05:25 -08003769 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3770}
Francois Romieu5f787a12006-08-17 13:02:36 +02003771
Francois Romieucecb5fd2011-04-01 10:21:07 +02003772static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3773 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003774{
Francois Romieu5f787a12006-08-17 13:02:36 +02003775 switch (cmd) {
3776 case SIOCGMIIPHY:
3777 data->phy_id = 32; /* Internal PHY */
3778 return 0;
3779
3780 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003781 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003782 return 0;
3783
3784 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003785 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003786 return 0;
3787 }
3788 return -EOPNOTSUPP;
3789}
3790
Francois Romieu8b4ab282008-11-19 22:05:25 -08003791static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3792{
3793 return -EOPNOTSUPP;
3794}
3795
Francois Romieufbac58f2007-10-04 22:51:38 +02003796static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3797{
3798 if (tp->features & RTL_FEATURE_MSI) {
3799 pci_disable_msi(pdev);
3800 tp->features &= ~RTL_FEATURE_MSI;
3801 }
3802}
3803
françois romieuc0e45c12011-01-03 15:08:04 +00003804static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
3805{
3806 struct mdio_ops *ops = &tp->mdio_ops;
3807
3808 switch (tp->mac_version) {
3809 case RTL_GIGA_MAC_VER_27:
3810 ops->write = r8168dp_1_mdio_write;
3811 ops->read = r8168dp_1_mdio_read;
3812 break;
françois romieue6de30d2011-01-03 15:08:37 +00003813 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003814 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003815 ops->write = r8168dp_2_mdio_write;
3816 ops->read = r8168dp_2_mdio_read;
3817 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003818 case RTL_GIGA_MAC_VER_40:
3819 case RTL_GIGA_MAC_VER_41:
3820 ops->write = r8168g_mdio_write;
3821 ops->read = r8168g_mdio_read;
3822 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003823 default:
3824 ops->write = r8169_mdio_write;
3825 ops->read = r8169_mdio_read;
3826 break;
3827 }
3828}
3829
David S. Miller1805b2f2011-10-24 18:18:09 -04003830static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3831{
3832 void __iomem *ioaddr = tp->mmio_addr;
3833
3834 switch (tp->mac_version) {
3835 case RTL_GIGA_MAC_VER_29:
3836 case RTL_GIGA_MAC_VER_30:
3837 case RTL_GIGA_MAC_VER_32:
3838 case RTL_GIGA_MAC_VER_33:
3839 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003840 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003841 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003842 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003843 case RTL_GIGA_MAC_VER_40:
3844 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003845 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3846 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3847 break;
3848 default:
3849 break;
3850 }
3851}
3852
3853static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3854{
3855 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3856 return false;
3857
3858 rtl_writephy(tp, 0x1f, 0x0000);
3859 rtl_writephy(tp, MII_BMCR, 0x0000);
3860
3861 rtl_wol_suspend_quirk(tp);
3862
3863 return true;
3864}
3865
françois romieu065c27c2011-01-03 15:08:12 +00003866static void r810x_phy_power_down(struct rtl8169_private *tp)
3867{
3868 rtl_writephy(tp, 0x1f, 0x0000);
3869 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3870}
3871
3872static void r810x_phy_power_up(struct rtl8169_private *tp)
3873{
3874 rtl_writephy(tp, 0x1f, 0x0000);
3875 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3876}
3877
3878static void r810x_pll_power_down(struct rtl8169_private *tp)
3879{
Hayes Wang00042992012-03-30 14:33:00 +08003880 void __iomem *ioaddr = tp->mmio_addr;
3881
David S. Miller1805b2f2011-10-24 18:18:09 -04003882 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003883 return;
françois romieu065c27c2011-01-03 15:08:12 +00003884
3885 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003886
3887 switch (tp->mac_version) {
3888 case RTL_GIGA_MAC_VER_07:
3889 case RTL_GIGA_MAC_VER_08:
3890 case RTL_GIGA_MAC_VER_09:
3891 case RTL_GIGA_MAC_VER_10:
3892 case RTL_GIGA_MAC_VER_13:
3893 case RTL_GIGA_MAC_VER_16:
3894 break;
3895 default:
3896 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3897 break;
3898 }
françois romieu065c27c2011-01-03 15:08:12 +00003899}
3900
3901static void r810x_pll_power_up(struct rtl8169_private *tp)
3902{
Hayes Wang00042992012-03-30 14:33:00 +08003903 void __iomem *ioaddr = tp->mmio_addr;
3904
françois romieu065c27c2011-01-03 15:08:12 +00003905 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003906
3907 switch (tp->mac_version) {
3908 case RTL_GIGA_MAC_VER_07:
3909 case RTL_GIGA_MAC_VER_08:
3910 case RTL_GIGA_MAC_VER_09:
3911 case RTL_GIGA_MAC_VER_10:
3912 case RTL_GIGA_MAC_VER_13:
3913 case RTL_GIGA_MAC_VER_16:
3914 break;
3915 default:
3916 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3917 break;
3918 }
françois romieu065c27c2011-01-03 15:08:12 +00003919}
3920
3921static void r8168_phy_power_up(struct rtl8169_private *tp)
3922{
3923 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003924 switch (tp->mac_version) {
3925 case RTL_GIGA_MAC_VER_11:
3926 case RTL_GIGA_MAC_VER_12:
3927 case RTL_GIGA_MAC_VER_17:
3928 case RTL_GIGA_MAC_VER_18:
3929 case RTL_GIGA_MAC_VER_19:
3930 case RTL_GIGA_MAC_VER_20:
3931 case RTL_GIGA_MAC_VER_21:
3932 case RTL_GIGA_MAC_VER_22:
3933 case RTL_GIGA_MAC_VER_23:
3934 case RTL_GIGA_MAC_VER_24:
3935 case RTL_GIGA_MAC_VER_25:
3936 case RTL_GIGA_MAC_VER_26:
3937 case RTL_GIGA_MAC_VER_27:
3938 case RTL_GIGA_MAC_VER_28:
3939 case RTL_GIGA_MAC_VER_31:
3940 rtl_writephy(tp, 0x0e, 0x0000);
3941 break;
3942 default:
3943 break;
3944 }
françois romieu065c27c2011-01-03 15:08:12 +00003945 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3946}
3947
3948static void r8168_phy_power_down(struct rtl8169_private *tp)
3949{
3950 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003951 switch (tp->mac_version) {
3952 case RTL_GIGA_MAC_VER_32:
3953 case RTL_GIGA_MAC_VER_33:
3954 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3955 break;
3956
3957 case RTL_GIGA_MAC_VER_11:
3958 case RTL_GIGA_MAC_VER_12:
3959 case RTL_GIGA_MAC_VER_17:
3960 case RTL_GIGA_MAC_VER_18:
3961 case RTL_GIGA_MAC_VER_19:
3962 case RTL_GIGA_MAC_VER_20:
3963 case RTL_GIGA_MAC_VER_21:
3964 case RTL_GIGA_MAC_VER_22:
3965 case RTL_GIGA_MAC_VER_23:
3966 case RTL_GIGA_MAC_VER_24:
3967 case RTL_GIGA_MAC_VER_25:
3968 case RTL_GIGA_MAC_VER_26:
3969 case RTL_GIGA_MAC_VER_27:
3970 case RTL_GIGA_MAC_VER_28:
3971 case RTL_GIGA_MAC_VER_31:
3972 rtl_writephy(tp, 0x0e, 0x0200);
3973 default:
3974 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3975 break;
3976 }
françois romieu065c27c2011-01-03 15:08:12 +00003977}
3978
3979static void r8168_pll_power_down(struct rtl8169_private *tp)
3980{
3981 void __iomem *ioaddr = tp->mmio_addr;
3982
Francois Romieucecb5fd2011-04-01 10:21:07 +02003983 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
3984 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
3985 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00003986 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00003987 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08003988 }
françois romieu065c27c2011-01-03 15:08:12 +00003989
Francois Romieucecb5fd2011-04-01 10:21:07 +02003990 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
3991 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00003992 (RTL_R16(CPlusCmd) & ASF)) {
3993 return;
3994 }
3995
hayeswang01dc7fe2011-03-21 01:50:28 +00003996 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
3997 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02003998 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00003999
David S. Miller1805b2f2011-10-24 18:18:09 -04004000 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00004001 return;
françois romieu065c27c2011-01-03 15:08:12 +00004002
4003 r8168_phy_power_down(tp);
4004
4005 switch (tp->mac_version) {
4006 case RTL_GIGA_MAC_VER_25:
4007 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004008 case RTL_GIGA_MAC_VER_27:
4009 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004010 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004011 case RTL_GIGA_MAC_VER_32:
4012 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004013 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4014 break;
4015 }
4016}
4017
4018static void r8168_pll_power_up(struct rtl8169_private *tp)
4019{
4020 void __iomem *ioaddr = tp->mmio_addr;
4021
françois romieu065c27c2011-01-03 15:08:12 +00004022 switch (tp->mac_version) {
4023 case RTL_GIGA_MAC_VER_25:
4024 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004025 case RTL_GIGA_MAC_VER_27:
4026 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004027 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004028 case RTL_GIGA_MAC_VER_32:
4029 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004030 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4031 break;
4032 }
4033
4034 r8168_phy_power_up(tp);
4035}
4036
Francois Romieud58d46b2011-05-03 16:38:29 +02004037static void rtl_generic_op(struct rtl8169_private *tp,
4038 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004039{
4040 if (op)
4041 op(tp);
4042}
4043
4044static void rtl_pll_power_down(struct rtl8169_private *tp)
4045{
Francois Romieud58d46b2011-05-03 16:38:29 +02004046 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004047}
4048
4049static void rtl_pll_power_up(struct rtl8169_private *tp)
4050{
Francois Romieud58d46b2011-05-03 16:38:29 +02004051 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004052}
4053
4054static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
4055{
4056 struct pll_power_ops *ops = &tp->pll_power_ops;
4057
4058 switch (tp->mac_version) {
4059 case RTL_GIGA_MAC_VER_07:
4060 case RTL_GIGA_MAC_VER_08:
4061 case RTL_GIGA_MAC_VER_09:
4062 case RTL_GIGA_MAC_VER_10:
4063 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004064 case RTL_GIGA_MAC_VER_29:
4065 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004066 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004067 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004068 ops->down = r810x_pll_power_down;
4069 ops->up = r810x_pll_power_up;
4070 break;
4071
4072 case RTL_GIGA_MAC_VER_11:
4073 case RTL_GIGA_MAC_VER_12:
4074 case RTL_GIGA_MAC_VER_17:
4075 case RTL_GIGA_MAC_VER_18:
4076 case RTL_GIGA_MAC_VER_19:
4077 case RTL_GIGA_MAC_VER_20:
4078 case RTL_GIGA_MAC_VER_21:
4079 case RTL_GIGA_MAC_VER_22:
4080 case RTL_GIGA_MAC_VER_23:
4081 case RTL_GIGA_MAC_VER_24:
4082 case RTL_GIGA_MAC_VER_25:
4083 case RTL_GIGA_MAC_VER_26:
4084 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004085 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004086 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004087 case RTL_GIGA_MAC_VER_32:
4088 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004089 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004090 case RTL_GIGA_MAC_VER_35:
4091 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004092 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004093 case RTL_GIGA_MAC_VER_40:
4094 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004095 ops->down = r8168_pll_power_down;
4096 ops->up = r8168_pll_power_up;
4097 break;
4098
4099 default:
4100 ops->down = NULL;
4101 ops->up = NULL;
4102 break;
4103 }
4104}
4105
Hayes Wange542a222011-07-06 15:58:04 +08004106static void rtl_init_rxcfg(struct rtl8169_private *tp)
4107{
4108 void __iomem *ioaddr = tp->mmio_addr;
4109
4110 switch (tp->mac_version) {
4111 case RTL_GIGA_MAC_VER_01:
4112 case RTL_GIGA_MAC_VER_02:
4113 case RTL_GIGA_MAC_VER_03:
4114 case RTL_GIGA_MAC_VER_04:
4115 case RTL_GIGA_MAC_VER_05:
4116 case RTL_GIGA_MAC_VER_06:
4117 case RTL_GIGA_MAC_VER_10:
4118 case RTL_GIGA_MAC_VER_11:
4119 case RTL_GIGA_MAC_VER_12:
4120 case RTL_GIGA_MAC_VER_13:
4121 case RTL_GIGA_MAC_VER_14:
4122 case RTL_GIGA_MAC_VER_15:
4123 case RTL_GIGA_MAC_VER_16:
4124 case RTL_GIGA_MAC_VER_17:
4125 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4126 break;
4127 case RTL_GIGA_MAC_VER_18:
4128 case RTL_GIGA_MAC_VER_19:
4129 case RTL_GIGA_MAC_VER_20:
4130 case RTL_GIGA_MAC_VER_21:
4131 case RTL_GIGA_MAC_VER_22:
4132 case RTL_GIGA_MAC_VER_23:
4133 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004134 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004135 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4136 break;
4137 default:
4138 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4139 break;
4140 }
4141}
4142
Hayes Wang92fc43b2011-07-06 15:58:03 +08004143static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4144{
4145 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4146}
4147
Francois Romieud58d46b2011-05-03 16:38:29 +02004148static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4149{
françois romieu9c5028e2012-03-02 04:43:14 +00004150 void __iomem *ioaddr = tp->mmio_addr;
4151
4152 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004153 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004154 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004155}
4156
4157static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
4158{
françois romieu9c5028e2012-03-02 04:43:14 +00004159 void __iomem *ioaddr = tp->mmio_addr;
4160
4161 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004162 rtl_generic_op(tp, tp->jumbo_ops.disable);
françois romieu9c5028e2012-03-02 04:43:14 +00004163 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004164}
4165
4166static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4167{
4168 void __iomem *ioaddr = tp->mmio_addr;
4169
4170 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4171 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4172 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4173}
4174
4175static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
4176{
4177 void __iomem *ioaddr = tp->mmio_addr;
4178
4179 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4180 RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
4181 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
4182}
4183
4184static void r8168dp_hw_jumbo_enable(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 r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4192{
4193 void __iomem *ioaddr = tp->mmio_addr;
4194
4195 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4196}
4197
4198static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4199{
4200 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004201
4202 RTL_W8(MaxTxPacketSize, 0x3f);
4203 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4204 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004205 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004206}
4207
4208static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4209{
4210 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004211
4212 RTL_W8(MaxTxPacketSize, 0x0c);
4213 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4214 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004215 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004216}
4217
4218static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4219{
4220 rtl_tx_performance_tweak(tp->pci_dev,
4221 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4222}
4223
4224static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4225{
4226 rtl_tx_performance_tweak(tp->pci_dev,
4227 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4228}
4229
4230static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4231{
4232 void __iomem *ioaddr = tp->mmio_addr;
4233
4234 r8168b_0_hw_jumbo_enable(tp);
4235
4236 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4237}
4238
4239static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4240{
4241 void __iomem *ioaddr = tp->mmio_addr;
4242
4243 r8168b_0_hw_jumbo_disable(tp);
4244
4245 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4246}
4247
4248static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
4249{
4250 struct jumbo_ops *ops = &tp->jumbo_ops;
4251
4252 switch (tp->mac_version) {
4253 case RTL_GIGA_MAC_VER_11:
4254 ops->disable = r8168b_0_hw_jumbo_disable;
4255 ops->enable = r8168b_0_hw_jumbo_enable;
4256 break;
4257 case RTL_GIGA_MAC_VER_12:
4258 case RTL_GIGA_MAC_VER_17:
4259 ops->disable = r8168b_1_hw_jumbo_disable;
4260 ops->enable = r8168b_1_hw_jumbo_enable;
4261 break;
4262 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4263 case RTL_GIGA_MAC_VER_19:
4264 case RTL_GIGA_MAC_VER_20:
4265 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4266 case RTL_GIGA_MAC_VER_22:
4267 case RTL_GIGA_MAC_VER_23:
4268 case RTL_GIGA_MAC_VER_24:
4269 case RTL_GIGA_MAC_VER_25:
4270 case RTL_GIGA_MAC_VER_26:
4271 ops->disable = r8168c_hw_jumbo_disable;
4272 ops->enable = r8168c_hw_jumbo_enable;
4273 break;
4274 case RTL_GIGA_MAC_VER_27:
4275 case RTL_GIGA_MAC_VER_28:
4276 ops->disable = r8168dp_hw_jumbo_disable;
4277 ops->enable = r8168dp_hw_jumbo_enable;
4278 break;
4279 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4280 case RTL_GIGA_MAC_VER_32:
4281 case RTL_GIGA_MAC_VER_33:
4282 case RTL_GIGA_MAC_VER_34:
4283 ops->disable = r8168e_hw_jumbo_disable;
4284 ops->enable = r8168e_hw_jumbo_enable;
4285 break;
4286
4287 /*
4288 * No action needed for jumbo frames with 8169.
4289 * No jumbo for 810x at all.
4290 */
Hayes Wangc5583862012-07-02 17:23:22 +08004291 case RTL_GIGA_MAC_VER_40:
4292 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004293 default:
4294 ops->disable = NULL;
4295 ops->enable = NULL;
4296 break;
4297 }
4298}
4299
Francois Romieuffc46952012-07-06 14:19:23 +02004300DECLARE_RTL_COND(rtl_chipcmd_cond)
4301{
4302 void __iomem *ioaddr = tp->mmio_addr;
4303
4304 return RTL_R8(ChipCmd) & CmdReset;
4305}
4306
Francois Romieu6f43adc2011-04-29 15:05:51 +02004307static void rtl_hw_reset(struct rtl8169_private *tp)
4308{
4309 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004310
Francois Romieu6f43adc2011-04-29 15:05:51 +02004311 RTL_W8(ChipCmd, CmdReset);
4312
Francois Romieuffc46952012-07-06 14:19:23 +02004313 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004314}
4315
Francois Romieub6ffd972011-06-17 17:00:05 +02004316static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4317{
4318 struct rtl_fw *rtl_fw;
4319 const char *name;
4320 int rc = -ENOMEM;
4321
4322 name = rtl_lookup_firmware_name(tp);
4323 if (!name)
4324 goto out_no_firmware;
4325
4326 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4327 if (!rtl_fw)
4328 goto err_warn;
4329
4330 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4331 if (rc < 0)
4332 goto err_free;
4333
Francois Romieufd112f22011-06-18 00:10:29 +02004334 rc = rtl_check_firmware(tp, rtl_fw);
4335 if (rc < 0)
4336 goto err_release_firmware;
4337
Francois Romieub6ffd972011-06-17 17:00:05 +02004338 tp->rtl_fw = rtl_fw;
4339out:
4340 return;
4341
Francois Romieufd112f22011-06-18 00:10:29 +02004342err_release_firmware:
4343 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004344err_free:
4345 kfree(rtl_fw);
4346err_warn:
4347 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4348 name, rc);
4349out_no_firmware:
4350 tp->rtl_fw = NULL;
4351 goto out;
4352}
4353
François Romieu953a12c2011-04-24 17:38:48 +02004354static void rtl_request_firmware(struct rtl8169_private *tp)
4355{
Francois Romieub6ffd972011-06-17 17:00:05 +02004356 if (IS_ERR(tp->rtl_fw))
4357 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004358}
4359
Hayes Wang92fc43b2011-07-06 15:58:03 +08004360static void rtl_rx_close(struct rtl8169_private *tp)
4361{
4362 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004363
Francois Romieu1687b562011-07-19 17:21:29 +02004364 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004365}
4366
Francois Romieuffc46952012-07-06 14:19:23 +02004367DECLARE_RTL_COND(rtl_npq_cond)
4368{
4369 void __iomem *ioaddr = tp->mmio_addr;
4370
4371 return RTL_R8(TxPoll) & NPQ;
4372}
4373
4374DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4375{
4376 void __iomem *ioaddr = tp->mmio_addr;
4377
4378 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4379}
4380
françois romieue6de30d2011-01-03 15:08:37 +00004381static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
françois romieue6de30d2011-01-03 15:08:37 +00004383 void __iomem *ioaddr = tp->mmio_addr;
4384
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004386 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
Hayes Wang92fc43b2011-07-06 15:58:03 +08004388 rtl_rx_close(tp);
4389
Hayes Wang5d2e1952011-02-22 17:26:22 +08004390 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004391 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4392 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004393 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004394 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4395 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004396 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004397 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004398 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4399 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004400 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004401 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004402 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004403 } else {
4404 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4405 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004406 }
4407
Hayes Wang92fc43b2011-07-06 15:58:03 +08004408 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409}
4410
Francois Romieu7f796d832007-06-11 23:04:41 +02004411static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004412{
4413 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004414
4415 /* Set DMA burst size and Interframe Gap Time */
4416 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4417 (InterFrameGap << TxInterFrameGapShift));
4418}
4419
Francois Romieu07ce4062007-02-23 23:36:39 +01004420static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421{
4422 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
Francois Romieu07ce4062007-02-23 23:36:39 +01004424 tp->hw_start(dev);
4425
Francois Romieuda78dbf2012-01-26 14:18:23 +01004426 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004427}
4428
Francois Romieu7f796d832007-06-11 23:04:41 +02004429static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4430 void __iomem *ioaddr)
4431{
4432 /*
4433 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4434 * register to be written before TxDescAddrLow to work.
4435 * Switching from MMIO to I/O access fixes the issue as well.
4436 */
4437 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004438 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004439 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004440 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004441}
4442
4443static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4444{
4445 u16 cmd;
4446
4447 cmd = RTL_R16(CPlusCmd);
4448 RTL_W16(CPlusCmd, cmd);
4449 return cmd;
4450}
4451
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004452static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004453{
4454 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e872009-10-26 10:52:37 +00004455 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004456}
4457
Francois Romieu6dccd162007-02-13 23:38:05 +01004458static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4459{
Francois Romieu37441002011-06-17 22:58:54 +02004460 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004461 u32 mac_version;
4462 u32 clk;
4463 u32 val;
4464 } cfg2_info [] = {
4465 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4466 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4467 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4468 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004469 };
4470 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004471 unsigned int i;
4472 u32 clk;
4473
4474 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004475 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004476 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4477 RTL_W32(0x7c, p->val);
4478 break;
4479 }
4480 }
4481}
4482
Francois Romieue6b763e2012-03-08 09:35:39 +01004483static void rtl_set_rx_mode(struct net_device *dev)
4484{
4485 struct rtl8169_private *tp = netdev_priv(dev);
4486 void __iomem *ioaddr = tp->mmio_addr;
4487 u32 mc_filter[2]; /* Multicast hash filter */
4488 int rx_mode;
4489 u32 tmp = 0;
4490
4491 if (dev->flags & IFF_PROMISC) {
4492 /* Unconditionally log net taps. */
4493 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4494 rx_mode =
4495 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4496 AcceptAllPhys;
4497 mc_filter[1] = mc_filter[0] = 0xffffffff;
4498 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4499 (dev->flags & IFF_ALLMULTI)) {
4500 /* Too many to filter perfectly -- accept all multicasts. */
4501 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4502 mc_filter[1] = mc_filter[0] = 0xffffffff;
4503 } else {
4504 struct netdev_hw_addr *ha;
4505
4506 rx_mode = AcceptBroadcast | AcceptMyPhys;
4507 mc_filter[1] = mc_filter[0] = 0;
4508 netdev_for_each_mc_addr(ha, dev) {
4509 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4510 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4511 rx_mode |= AcceptMulticast;
4512 }
4513 }
4514
4515 if (dev->features & NETIF_F_RXALL)
4516 rx_mode |= (AcceptErr | AcceptRunt);
4517
4518 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4519
4520 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4521 u32 data = mc_filter[0];
4522
4523 mc_filter[0] = swab32(mc_filter[1]);
4524 mc_filter[1] = swab32(data);
4525 }
4526
4527 RTL_W32(MAR0 + 4, mc_filter[1]);
4528 RTL_W32(MAR0 + 0, mc_filter[0]);
4529
4530 RTL_W32(RxConfig, tmp);
4531}
4532
Francois Romieu07ce4062007-02-23 23:36:39 +01004533static void rtl_hw_start_8169(struct net_device *dev)
4534{
4535 struct rtl8169_private *tp = netdev_priv(dev);
4536 void __iomem *ioaddr = tp->mmio_addr;
4537 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004538
Francois Romieu9cb427b2006-11-02 00:10:16 +01004539 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4540 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4541 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4542 }
4543
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004545 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4546 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4547 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4548 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004549 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4550
Hayes Wange542a222011-07-06 15:58:04 +08004551 rtl_init_rxcfg(tp);
4552
françois romieuf0298f82011-01-03 15:07:42 +00004553 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004555 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Francois Romieucecb5fd2011-04-01 10:21:07 +02004557 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4558 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4559 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4560 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004561 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
Francois Romieu7f796d832007-06-11 23:04:41 +02004563 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004564
Francois Romieucecb5fd2011-04-01 10:21:07 +02004565 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4566 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004567 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004569 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571
Francois Romieubcf0bf92006-07-26 23:14:13 +02004572 RTL_W16(CPlusCmd, tp->cp_cmd);
4573
Francois Romieu6dccd162007-02-13 23:38:05 +01004574 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 /*
4577 * Undocumented corner. Supposedly:
4578 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4579 */
4580 RTL_W16(IntrMitigate, 0x0000);
4581
Francois Romieu7f796d832007-06-11 23:04:41 +02004582 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004583
Francois Romieucecb5fd2011-04-01 10:21:07 +02004584 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4585 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4586 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4587 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004588 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4589 rtl_set_rx_tx_config_registers(tp);
4590 }
4591
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004593
4594 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4595 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596
4597 RTL_W32(RxMissed, 0);
4598
Francois Romieu07ce4062007-02-23 23:36:39 +01004599 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601 /* no early-rx interrupts */
4602 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004603}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004605static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4606{
4607 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004608 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004609}
4610
4611static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4612{
Francois Romieu52989f02012-07-06 13:37:00 +02004613 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004614}
4615
4616static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004617{
4618 u32 csi;
4619
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004620 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4621 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004622}
4623
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004624static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004625{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004626 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004627}
4628
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004629static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004630{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004631 rtl_csi_access_enable(tp, 0x27000000);
4632}
4633
Francois Romieuffc46952012-07-06 14:19:23 +02004634DECLARE_RTL_COND(rtl_csiar_cond)
4635{
4636 void __iomem *ioaddr = tp->mmio_addr;
4637
4638 return RTL_R32(CSIAR) & CSIAR_FLAG;
4639}
4640
Francois Romieu52989f02012-07-06 13:37:00 +02004641static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004642{
Francois Romieu52989f02012-07-06 13:37:00 +02004643 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004644
4645 RTL_W32(CSIDR, value);
4646 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4647 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4648
Francois Romieuffc46952012-07-06 14:19:23 +02004649 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004650}
4651
Francois Romieu52989f02012-07-06 13:37:00 +02004652static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004653{
Francois Romieu52989f02012-07-06 13:37:00 +02004654 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004655
4656 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4657 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4658
Francois Romieuffc46952012-07-06 14:19:23 +02004659 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4660 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004661}
4662
Francois Romieu52989f02012-07-06 13:37:00 +02004663static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004664{
Francois Romieu52989f02012-07-06 13:37:00 +02004665 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004666
4667 RTL_W32(CSIDR, value);
4668 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4669 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4670 CSIAR_FUNC_NIC);
4671
Francois Romieuffc46952012-07-06 14:19:23 +02004672 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004673}
4674
Francois Romieu52989f02012-07-06 13:37:00 +02004675static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004676{
Francois Romieu52989f02012-07-06 13:37:00 +02004677 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004678
4679 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4680 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4681
Francois Romieuffc46952012-07-06 14:19:23 +02004682 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4683 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004684}
4685
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004686static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
4687{
4688 struct csi_ops *ops = &tp->csi_ops;
4689
4690 switch (tp->mac_version) {
4691 case RTL_GIGA_MAC_VER_01:
4692 case RTL_GIGA_MAC_VER_02:
4693 case RTL_GIGA_MAC_VER_03:
4694 case RTL_GIGA_MAC_VER_04:
4695 case RTL_GIGA_MAC_VER_05:
4696 case RTL_GIGA_MAC_VER_06:
4697 case RTL_GIGA_MAC_VER_10:
4698 case RTL_GIGA_MAC_VER_11:
4699 case RTL_GIGA_MAC_VER_12:
4700 case RTL_GIGA_MAC_VER_13:
4701 case RTL_GIGA_MAC_VER_14:
4702 case RTL_GIGA_MAC_VER_15:
4703 case RTL_GIGA_MAC_VER_16:
4704 case RTL_GIGA_MAC_VER_17:
4705 ops->write = NULL;
4706 ops->read = NULL;
4707 break;
4708
Hayes Wang7e18dca2012-03-30 14:33:02 +08004709 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004710 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004711 ops->write = r8402_csi_write;
4712 ops->read = r8402_csi_read;
4713 break;
4714
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004715 default:
4716 ops->write = r8169_csi_write;
4717 ops->read = r8169_csi_read;
4718 break;
4719 }
Francois Romieudacf8152008-08-02 20:44:13 +02004720}
4721
4722struct ephy_info {
4723 unsigned int offset;
4724 u16 mask;
4725 u16 bits;
4726};
4727
Francois Romieufdf6fc02012-07-06 22:40:38 +02004728static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4729 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004730{
4731 u16 w;
4732
4733 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004734 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4735 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004736 e++;
4737 }
4738}
4739
Francois Romieub726e492008-06-28 12:22:59 +02004740static void rtl_disable_clock_request(struct pci_dev *pdev)
4741{
Jon Masone44daad2011-06-27 07:46:31 +00004742 int cap = pci_pcie_cap(pdev);
Francois Romieub726e492008-06-28 12:22:59 +02004743
4744 if (cap) {
4745 u16 ctl;
4746
4747 pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
4748 ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
4749 pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
4750 }
4751}
4752
françois romieue6de30d2011-01-03 15:08:37 +00004753static void rtl_enable_clock_request(struct pci_dev *pdev)
4754{
Jon Masone44daad2011-06-27 07:46:31 +00004755 int cap = pci_pcie_cap(pdev);
françois romieue6de30d2011-01-03 15:08:37 +00004756
4757 if (cap) {
4758 u16 ctl;
4759
4760 pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
4761 ctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
4762 pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
4763 }
4764}
4765
Francois Romieub726e492008-06-28 12:22:59 +02004766#define R8168_CPCMD_QUIRK_MASK (\
4767 EnableBist | \
4768 Mac_dbgo_oe | \
4769 Force_half_dup | \
4770 Force_rxflow_en | \
4771 Force_txflow_en | \
4772 Cxpl_dbg_sel | \
4773 ASF | \
4774 PktCntrDisable | \
4775 Mac_dbgo_sel)
4776
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004777static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004778{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004779 void __iomem *ioaddr = tp->mmio_addr;
4780 struct pci_dev *pdev = tp->pci_dev;
4781
Francois Romieub726e492008-06-28 12:22:59 +02004782 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4783
4784 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4785
Francois Romieu2e68ae42008-06-28 12:00:55 +02004786 rtl_tx_performance_tweak(pdev,
4787 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004788}
4789
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004790static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004791{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004792 void __iomem *ioaddr = tp->mmio_addr;
4793
4794 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004795
françois romieuf0298f82011-01-03 15:07:42 +00004796 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004797
4798 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004799}
4800
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004801static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004802{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004803 void __iomem *ioaddr = tp->mmio_addr;
4804 struct pci_dev *pdev = tp->pci_dev;
4805
Francois Romieub726e492008-06-28 12:22:59 +02004806 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4807
4808 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4809
Francois Romieu219a1e92008-06-28 11:58:39 +02004810 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004811
4812 rtl_disable_clock_request(pdev);
4813
4814 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004815}
4816
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004817static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004818{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004819 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004820 { 0x01, 0, 0x0001 },
4821 { 0x02, 0x0800, 0x1000 },
4822 { 0x03, 0, 0x0042 },
4823 { 0x06, 0x0080, 0x0000 },
4824 { 0x07, 0, 0x2000 }
4825 };
4826
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004827 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004828
Francois Romieufdf6fc02012-07-06 22:40:38 +02004829 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004830
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004831 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004832}
4833
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004834static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004835{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004836 void __iomem *ioaddr = tp->mmio_addr;
4837 struct pci_dev *pdev = tp->pci_dev;
4838
4839 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004840
4841 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4842
4843 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4844
4845 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4846}
4847
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004848static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004849{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004850 void __iomem *ioaddr = tp->mmio_addr;
4851 struct pci_dev *pdev = tp->pci_dev;
4852
4853 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004854
4855 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4856
4857 /* Magic. */
4858 RTL_W8(DBG_REG, 0x20);
4859
françois romieuf0298f82011-01-03 15:07:42 +00004860 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004861
4862 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4863
4864 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4865}
4866
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004867static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004868{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004869 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004870 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004871 { 0x02, 0x0800, 0x1000 },
4872 { 0x03, 0, 0x0002 },
4873 { 0x06, 0x0080, 0x0000 }
4874 };
4875
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004876 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004877
4878 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4879
Francois Romieufdf6fc02012-07-06 22:40:38 +02004880 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004881
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004882 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004883}
4884
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004885static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004886{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004887 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004888 { 0x01, 0, 0x0001 },
4889 { 0x03, 0x0400, 0x0220 }
4890 };
4891
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004892 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004893
Francois Romieufdf6fc02012-07-06 22:40:38 +02004894 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004895
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004896 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004897}
4898
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004899static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004900{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004901 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004902}
4903
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004904static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004905{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004906 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004907
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004908 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004909}
4910
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004911static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004912{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004913 void __iomem *ioaddr = tp->mmio_addr;
4914 struct pci_dev *pdev = tp->pci_dev;
4915
4916 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004917
4918 rtl_disable_clock_request(pdev);
4919
françois romieuf0298f82011-01-03 15:07:42 +00004920 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004921
4922 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4923
4924 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4925}
4926
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004927static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004928{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004929 void __iomem *ioaddr = tp->mmio_addr;
4930 struct pci_dev *pdev = tp->pci_dev;
4931
4932 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004933
4934 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4935
4936 RTL_W8(MaxTxPacketSize, TxPacketMax);
4937
4938 rtl_disable_clock_request(pdev);
4939}
4940
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004941static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004942{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004943 void __iomem *ioaddr = tp->mmio_addr;
4944 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004945 static const struct ephy_info e_info_8168d_4[] = {
4946 { 0x0b, ~0, 0x48 },
4947 { 0x19, 0x20, 0x50 },
4948 { 0x0c, ~0, 0x20 }
4949 };
4950 int i;
4951
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004952 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004953
4954 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4955
4956 RTL_W8(MaxTxPacketSize, TxPacketMax);
4957
4958 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4959 const struct ephy_info *e = e_info_8168d_4 + i;
4960 u16 w;
4961
Francois Romieufdf6fc02012-07-06 22:40:38 +02004962 w = rtl_ephy_read(tp, e->offset);
4963 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004964 }
4965
4966 rtl_enable_clock_request(pdev);
4967}
4968
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004969static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004970{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004971 void __iomem *ioaddr = tp->mmio_addr;
4972 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004973 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004974 { 0x00, 0x0200, 0x0100 },
4975 { 0x00, 0x0000, 0x0004 },
4976 { 0x06, 0x0002, 0x0001 },
4977 { 0x06, 0x0000, 0x0030 },
4978 { 0x07, 0x0000, 0x2000 },
4979 { 0x00, 0x0000, 0x0020 },
4980 { 0x03, 0x5800, 0x2000 },
4981 { 0x03, 0x0000, 0x0001 },
4982 { 0x01, 0x0800, 0x1000 },
4983 { 0x07, 0x0000, 0x4000 },
4984 { 0x1e, 0x0000, 0x2000 },
4985 { 0x19, 0xffff, 0xfe6c },
4986 { 0x0a, 0x0000, 0x0040 }
4987 };
4988
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004989 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00004990
Francois Romieufdf6fc02012-07-06 22:40:38 +02004991 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00004992
4993 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4994
4995 RTL_W8(MaxTxPacketSize, TxPacketMax);
4996
4997 rtl_disable_clock_request(pdev);
4998
4999 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02005000 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
5001 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00005002
Francois Romieucecb5fd2011-04-01 10:21:07 +02005003 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00005004}
5005
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005006static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08005007{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005008 void __iomem *ioaddr = tp->mmio_addr;
5009 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08005010 static const struct ephy_info e_info_8168e_2[] = {
5011 { 0x09, 0x0000, 0x0080 },
5012 { 0x19, 0x0000, 0x0224 }
5013 };
5014
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005015 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005016
Francois Romieufdf6fc02012-07-06 22:40:38 +02005017 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08005018
5019 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5020
Francois Romieufdf6fc02012-07-06 22:40:38 +02005021 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5022 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5023 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5024 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5025 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5026 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5027 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5028 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005029
Hayes Wang3090bd92011-09-06 16:55:15 +08005030 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005031
5032 rtl_disable_clock_request(pdev);
5033
5034 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5035 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5036
5037 /* Adjust EEE LED frequency */
5038 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5039
5040 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5041 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5042 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5043}
5044
Hayes Wang5f886e02012-03-30 14:33:03 +08005045static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005046{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005047 void __iomem *ioaddr = tp->mmio_addr;
5048 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005049
Hayes Wang5f886e02012-03-30 14:33:03 +08005050 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005051
5052 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5053
Francois Romieufdf6fc02012-07-06 22:40:38 +02005054 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5055 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5056 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5057 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5058 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5059 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5060 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5061 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5062 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5063 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005064
5065 RTL_W8(MaxTxPacketSize, EarlySize);
5066
5067 rtl_disable_clock_request(pdev);
5068
5069 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5070 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005071 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5072 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5073 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5074}
5075
Hayes Wang5f886e02012-03-30 14:33:03 +08005076static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5077{
5078 void __iomem *ioaddr = tp->mmio_addr;
5079 static const struct ephy_info e_info_8168f_1[] = {
5080 { 0x06, 0x00c0, 0x0020 },
5081 { 0x08, 0x0001, 0x0002 },
5082 { 0x09, 0x0000, 0x0080 },
5083 { 0x19, 0x0000, 0x0224 }
5084 };
5085
5086 rtl_hw_start_8168f(tp);
5087
Francois Romieufdf6fc02012-07-06 22:40:38 +02005088 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005089
Francois Romieufdf6fc02012-07-06 22:40:38 +02005090 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005091
5092 /* Adjust EEE LED frequency */
5093 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5094}
5095
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005096static void rtl_hw_start_8411(struct rtl8169_private *tp)
5097{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005098 static const struct ephy_info e_info_8168f_1[] = {
5099 { 0x06, 0x00c0, 0x0020 },
5100 { 0x0f, 0xffff, 0x5200 },
5101 { 0x1e, 0x0000, 0x4000 },
5102 { 0x19, 0x0000, 0x0224 }
5103 };
5104
5105 rtl_hw_start_8168f(tp);
5106
Francois Romieufdf6fc02012-07-06 22:40:38 +02005107 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005108
Francois Romieufdf6fc02012-07-06 22:40:38 +02005109 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005110}
5111
Hayes Wangc5583862012-07-02 17:23:22 +08005112static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5113{
5114 void __iomem *ioaddr = tp->mmio_addr;
5115 struct pci_dev *pdev = tp->pci_dev;
5116
5117 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5118 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5119 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5120 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5121
5122 rtl_csi_access_enable_1(tp);
5123
5124 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5125
5126 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5127 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5128
5129 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5130 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
5131 RTL_W8(MaxTxPacketSize, EarlySize);
5132
5133 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5134 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5135
5136 /* Adjust EEE LED frequency */
5137 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5138
5139 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5140}
5141
Francois Romieu07ce4062007-02-23 23:36:39 +01005142static void rtl_hw_start_8168(struct net_device *dev)
5143{
Francois Romieu2dd99532007-06-11 23:22:52 +02005144 struct rtl8169_private *tp = netdev_priv(dev);
5145 void __iomem *ioaddr = tp->mmio_addr;
5146
5147 RTL_W8(Cfg9346, Cfg9346_Unlock);
5148
françois romieuf0298f82011-01-03 15:07:42 +00005149 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005150
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005151 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005152
Francois Romieu0e485152007-02-20 00:00:26 +01005153 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005154
5155 RTL_W16(CPlusCmd, tp->cp_cmd);
5156
Francois Romieu0e485152007-02-20 00:00:26 +01005157 RTL_W16(IntrMitigate, 0x5151);
5158
5159 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005160 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005161 tp->event_slow |= RxFIFOOver | PCSTimeout;
5162 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005163 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005164
5165 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5166
Francois Romieub8363902008-06-01 12:31:57 +02005167 rtl_set_rx_mode(dev);
5168
5169 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5170 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005171
5172 RTL_R8(IntrMask);
5173
Francois Romieu219a1e92008-06-28 11:58:39 +02005174 switch (tp->mac_version) {
5175 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005176 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005177 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005178
5179 case RTL_GIGA_MAC_VER_12:
5180 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005181 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005182 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005183
5184 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005185 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005186 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005187
5188 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005189 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005190 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005191
5192 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005193 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005194 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005195
Francois Romieu197ff762008-06-28 13:16:02 +02005196 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005197 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005198 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005199
Francois Romieu6fb07052008-06-29 11:54:28 +02005200 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005201 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005202 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005203
Francois Romieuef3386f2008-06-29 12:24:30 +02005204 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005205 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005206 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005207
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005208 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005209 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005210 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005211
Francois Romieu5b538df2008-07-20 16:22:45 +02005212 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005213 case RTL_GIGA_MAC_VER_26:
5214 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005215 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005216 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005217
françois romieue6de30d2011-01-03 15:08:37 +00005218 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005219 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005220 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005221
hayeswang4804b3b2011-03-21 01:50:29 +00005222 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005223 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005224 break;
5225
hayeswang01dc7fe2011-03-21 01:50:28 +00005226 case RTL_GIGA_MAC_VER_32:
5227 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005228 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005229 break;
5230 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005231 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005232 break;
françois romieue6de30d2011-01-03 15:08:37 +00005233
Hayes Wangc2218922011-09-06 16:55:18 +08005234 case RTL_GIGA_MAC_VER_35:
5235 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005236 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005237 break;
5238
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005239 case RTL_GIGA_MAC_VER_38:
5240 rtl_hw_start_8411(tp);
5241 break;
5242
Hayes Wangc5583862012-07-02 17:23:22 +08005243 case RTL_GIGA_MAC_VER_40:
5244 case RTL_GIGA_MAC_VER_41:
5245 rtl_hw_start_8168g_1(tp);
5246 break;
5247
Francois Romieu219a1e92008-06-28 11:58:39 +02005248 default:
5249 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5250 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005251 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005252 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005253
Francois Romieu0e485152007-02-20 00:00:26 +01005254 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5255
Francois Romieub8363902008-06-01 12:31:57 +02005256 RTL_W8(Cfg9346, Cfg9346_Lock);
5257
Francois Romieu2dd99532007-06-11 23:22:52 +02005258 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005259}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Francois Romieu2857ffb2008-08-02 21:08:49 +02005261#define R810X_CPCMD_QUIRK_MASK (\
5262 EnableBist | \
5263 Mac_dbgo_oe | \
5264 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005265 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005266 Force_txflow_en | \
5267 Cxpl_dbg_sel | \
5268 ASF | \
5269 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005270 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005271
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005272static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005273{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005274 void __iomem *ioaddr = tp->mmio_addr;
5275 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005276 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005277 { 0x01, 0, 0x6e65 },
5278 { 0x02, 0, 0x091f },
5279 { 0x03, 0, 0xc2f9 },
5280 { 0x06, 0, 0xafb5 },
5281 { 0x07, 0, 0x0e00 },
5282 { 0x19, 0, 0xec80 },
5283 { 0x01, 0, 0x2e65 },
5284 { 0x01, 0, 0x6e65 }
5285 };
5286 u8 cfg1;
5287
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005288 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005289
5290 RTL_W8(DBG_REG, FIX_NAK_1);
5291
5292 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5293
5294 RTL_W8(Config1,
5295 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5296 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5297
5298 cfg1 = RTL_R8(Config1);
5299 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5300 RTL_W8(Config1, cfg1 & ~LEDS0);
5301
Francois Romieufdf6fc02012-07-06 22:40:38 +02005302 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005303}
5304
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005305static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005306{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005307 void __iomem *ioaddr = tp->mmio_addr;
5308 struct pci_dev *pdev = tp->pci_dev;
5309
5310 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005311
5312 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5313
5314 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5315 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005316}
5317
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005318static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005319{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005320 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005321
Francois Romieufdf6fc02012-07-06 22:40:38 +02005322 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005323}
5324
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005325static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005326{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005327 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005328 static const struct ephy_info e_info_8105e_1[] = {
5329 { 0x07, 0, 0x4000 },
5330 { 0x19, 0, 0x0200 },
5331 { 0x19, 0, 0x0020 },
5332 { 0x1e, 0, 0x2000 },
5333 { 0x03, 0, 0x0001 },
5334 { 0x19, 0, 0x0100 },
5335 { 0x19, 0, 0x0004 },
5336 { 0x0a, 0, 0x0020 }
5337 };
5338
Francois Romieucecb5fd2011-04-01 10:21:07 +02005339 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005340 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5341
Francois Romieucecb5fd2011-04-01 10:21:07 +02005342 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005343 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5344
5345 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e52011-07-06 15:58:02 +08005346 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005347
Francois Romieufdf6fc02012-07-06 22:40:38 +02005348 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005349}
5350
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005351static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005352{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005353 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005354 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005355}
5356
Hayes Wang7e18dca2012-03-30 14:33:02 +08005357static void rtl_hw_start_8402(struct rtl8169_private *tp)
5358{
5359 void __iomem *ioaddr = tp->mmio_addr;
5360 static const struct ephy_info e_info_8402[] = {
5361 { 0x19, 0xffff, 0xff64 },
5362 { 0x1e, 0, 0x4000 }
5363 };
5364
5365 rtl_csi_access_enable_2(tp);
5366
5367 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5368 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5369
5370 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5371 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5372
Francois Romieufdf6fc02012-07-06 22:40:38 +02005373 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005374
5375 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5376
Francois Romieufdf6fc02012-07-06 22:40:38 +02005377 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5378 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5379 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5380 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5381 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5382 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5383 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005384}
5385
Hayes Wang5598bfe2012-07-02 17:23:21 +08005386static void rtl_hw_start_8106(struct rtl8169_private *tp)
5387{
5388 void __iomem *ioaddr = tp->mmio_addr;
5389
5390 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5391 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5392
5393 RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
5394 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5395 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5396}
5397
Francois Romieu07ce4062007-02-23 23:36:39 +01005398static void rtl_hw_start_8101(struct net_device *dev)
5399{
Francois Romieucdf1a602007-06-11 23:29:50 +02005400 struct rtl8169_private *tp = netdev_priv(dev);
5401 void __iomem *ioaddr = tp->mmio_addr;
5402 struct pci_dev *pdev = tp->pci_dev;
5403
Francois Romieuda78dbf2012-01-26 14:18:23 +01005404 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5405 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005406
Francois Romieucecb5fd2011-04-01 10:21:07 +02005407 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
5408 tp->mac_version == RTL_GIGA_MAC_VER_16) {
Jon Masone44daad2011-06-27 07:46:31 +00005409 int cap = pci_pcie_cap(pdev);
Francois Romieu9c14cea2008-07-05 00:21:15 +02005410
5411 if (cap) {
5412 pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
5413 PCI_EXP_DEVCTL_NOSNOOP_EN);
5414 }
Francois Romieucdf1a602007-06-11 23:29:50 +02005415 }
5416
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005417 RTL_W8(Cfg9346, Cfg9346_Unlock);
5418
Francois Romieu2857ffb2008-08-02 21:08:49 +02005419 switch (tp->mac_version) {
5420 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005421 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005422 break;
5423
5424 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005425 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005426 break;
5427
5428 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005429 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005430 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005431
5432 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005433 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005434 break;
5435 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005436 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005437 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005438
5439 case RTL_GIGA_MAC_VER_37:
5440 rtl_hw_start_8402(tp);
5441 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005442
5443 case RTL_GIGA_MAC_VER_39:
5444 rtl_hw_start_8106(tp);
5445 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005446 }
5447
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005448 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005449
françois romieuf0298f82011-01-03 15:07:42 +00005450 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005451
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005452 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005453
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005454 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005455 RTL_W16(CPlusCmd, tp->cp_cmd);
5456
5457 RTL_W16(IntrMitigate, 0x0000);
5458
5459 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5460
5461 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5462 rtl_set_rx_tx_config_registers(tp);
5463
Francois Romieucdf1a602007-06-11 23:29:50 +02005464 RTL_R8(IntrMask);
5465
Francois Romieucdf1a602007-06-11 23:29:50 +02005466 rtl_set_rx_mode(dev);
5467
5468 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469}
5470
5471static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5472{
Francois Romieud58d46b2011-05-03 16:38:29 +02005473 struct rtl8169_private *tp = netdev_priv(dev);
5474
5475 if (new_mtu < ETH_ZLEN ||
5476 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 return -EINVAL;
5478
Francois Romieud58d46b2011-05-03 16:38:29 +02005479 if (new_mtu > ETH_DATA_LEN)
5480 rtl_hw_jumbo_enable(tp);
5481 else
5482 rtl_hw_jumbo_disable(tp);
5483
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005485 netdev_update_features(dev);
5486
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005487 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488}
5489
5490static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5491{
Al Viro95e09182007-12-22 18:55:39 +00005492 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5494}
5495
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005496static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5497 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005499 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005500 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005501
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005502 kfree(*data_buff);
5503 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 rtl8169_make_unusable_by_asic(desc);
5505}
5506
5507static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5508{
5509 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5510
5511 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5512}
5513
5514static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5515 u32 rx_buf_sz)
5516{
5517 desc->addr = cpu_to_le64(mapping);
5518 wmb();
5519 rtl8169_mark_to_asic(desc, rx_buf_sz);
5520}
5521
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005522static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005524 return (void *)ALIGN((long)data, 16);
5525}
5526
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005527static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5528 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005529{
5530 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005532 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005533 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005534 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005536 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5537 if (!data)
5538 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005539
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005540 if (rtl8169_align(data) != data) {
5541 kfree(data);
5542 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5543 if (!data)
5544 return NULL;
5545 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005546
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005547 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005548 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005549 if (unlikely(dma_mapping_error(d, mapping))) {
5550 if (net_ratelimit())
5551 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005552 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554
5555 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005556 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005557
5558err_out:
5559 kfree(data);
5560 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561}
5562
5563static void rtl8169_rx_clear(struct rtl8169_private *tp)
5564{
Francois Romieu07d3f512007-02-21 22:40:46 +01005565 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
5567 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005568 if (tp->Rx_databuff[i]) {
5569 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 tp->RxDescArray + i);
5571 }
5572 }
5573}
5574
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005575static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005577 desc->opts1 |= cpu_to_le32(RingEnd);
5578}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005579
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005580static int rtl8169_rx_fill(struct rtl8169_private *tp)
5581{
5582 unsigned int i;
5583
5584 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005585 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005586
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005587 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005589
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005590 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005591 if (!data) {
5592 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005593 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005594 }
5595 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005598 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5599 return 0;
5600
5601err_out:
5602 rtl8169_rx_clear(tp);
5603 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604}
5605
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606static int rtl8169_init_ring(struct net_device *dev)
5607{
5608 struct rtl8169_private *tp = netdev_priv(dev);
5609
5610 rtl8169_init_ring_indexes(tp);
5611
5612 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005613 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005615 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616}
5617
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005618static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 struct TxDesc *desc)
5620{
5621 unsigned int len = tx_skb->len;
5622
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005623 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5624
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 desc->opts1 = 0x00;
5626 desc->opts2 = 0x00;
5627 desc->addr = 0x00;
5628 tx_skb->len = 0;
5629}
5630
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005631static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5632 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633{
5634 unsigned int i;
5635
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005636 for (i = 0; i < n; i++) {
5637 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 struct ring_info *tx_skb = tp->tx_skb + entry;
5639 unsigned int len = tx_skb->len;
5640
5641 if (len) {
5642 struct sk_buff *skb = tx_skb->skb;
5643
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005644 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 tp->TxDescArray + entry);
5646 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005647 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 dev_kfree_skb(skb);
5649 tx_skb->skb = NULL;
5650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 }
5652 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005653}
5654
5655static void rtl8169_tx_clear(struct rtl8169_private *tp)
5656{
5657 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 tp->cur_tx = tp->dirty_tx = 0;
5659}
5660
Francois Romieu4422bcd2012-01-26 11:23:32 +01005661static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662{
David Howellsc4028952006-11-22 14:57:56 +00005663 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005664 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665
Francois Romieuda78dbf2012-01-26 14:18:23 +01005666 napi_disable(&tp->napi);
5667 netif_stop_queue(dev);
5668 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
françois romieuc7c2c392011-12-04 20:30:52 +00005670 rtl8169_hw_reset(tp);
5671
Francois Romieu56de4142011-03-15 17:29:31 +01005672 for (i = 0; i < NUM_RX_DESC; i++)
5673 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005676 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677
Francois Romieuda78dbf2012-01-26 14:18:23 +01005678 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005679 rtl_hw_start(dev);
5680 netif_wake_queue(dev);
5681 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682}
5683
5684static void rtl8169_tx_timeout(struct net_device *dev)
5685{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005686 struct rtl8169_private *tp = netdev_priv(dev);
5687
5688 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689}
5690
5691static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005692 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693{
5694 struct skb_shared_info *info = skb_shinfo(skb);
5695 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005696 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005697 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
5699 entry = tp->cur_tx;
5700 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005701 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702 dma_addr_t mapping;
5703 u32 status, len;
5704 void *addr;
5705
5706 entry = (entry + 1) % NUM_TX_DESC;
5707
5708 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005709 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005710 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005711 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005712 if (unlikely(dma_mapping_error(d, mapping))) {
5713 if (net_ratelimit())
5714 netif_err(tp, drv, tp->dev,
5715 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005716 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718
Francois Romieucecb5fd2011-04-01 10:21:07 +02005719 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005720 status = opts[0] | len |
5721 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
5723 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005724 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725 txd->addr = cpu_to_le64(mapping);
5726
5727 tp->tx_skb[entry].len = len;
5728 }
5729
5730 if (cur_frag) {
5731 tp->tx_skb[entry].skb = skb;
5732 txd->opts1 |= cpu_to_le32(LastFrag);
5733 }
5734
5735 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005736
5737err_out:
5738 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5739 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740}
5741
Francois Romieu2b7b4312011-04-18 22:53:24 -07005742static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5743 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005745 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005746 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005747 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
Francois Romieu2b7b4312011-04-18 22:53:24 -07005749 if (mss) {
5750 opts[0] |= TD_LSO;
5751 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5752 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005753 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
5755 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005756 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005758 opts[offset] |= info->checksum.udp;
5759 else
5760 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762}
5763
Stephen Hemminger613573252009-08-31 19:50:58 +00005764static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5765 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766{
5767 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005768 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 struct TxDesc *txd = tp->TxDescArray + entry;
5770 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005771 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772 dma_addr_t mapping;
5773 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005774 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005775 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005776
Julien Ducourthial477206a2012-05-09 00:00:06 +02005777 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005778 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005779 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 }
5781
5782 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005783 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005785 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005786 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005787 if (unlikely(dma_mapping_error(d, mapping))) {
5788 if (net_ratelimit())
5789 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005790 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792
5793 tp->tx_skb[entry].len = len;
5794 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Francois Romieu2b7b4312011-04-18 22:53:24 -07005796 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
5797 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005798
Francois Romieu2b7b4312011-04-18 22:53:24 -07005799 rtl8169_tso_csum(tp, skb, opts);
5800
5801 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005802 if (frags < 0)
5803 goto err_dma_1;
5804 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005805 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005806 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005807 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005808 tp->tx_skb[entry].skb = skb;
5809 }
5810
Francois Romieu2b7b4312011-04-18 22:53:24 -07005811 txd->opts2 = cpu_to_le32(opts[1]);
5812
Richard Cochran5047fb52012-03-10 07:29:42 +00005813 skb_tx_timestamp(skb);
5814
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 wmb();
5816
Francois Romieucecb5fd2011-04-01 10:21:07 +02005817 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005818 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 txd->opts1 = cpu_to_le32(status);
5820
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 tp->cur_tx += frags + 1;
5822
David Dillow4c020a92010-03-03 16:33:10 +00005823 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005824
Francois Romieucecb5fd2011-04-01 10:21:07 +02005825 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
Francois Romieuda78dbf2012-01-26 14:18:23 +01005827 mmiowb();
5828
Julien Ducourthial477206a2012-05-09 00:00:06 +02005829 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005830 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5831 * not miss a ring update when it notices a stopped queue.
5832 */
5833 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005834 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005835 /* Sync with rtl_tx:
5836 * - publish queue status and cur_tx ring index (write barrier)
5837 * - refresh dirty_tx ring index (read barrier).
5838 * May the current thread have a pessimistic view of the ring
5839 * status and forget to wake up queue, a racing rtl_tx thread
5840 * can't.
5841 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005842 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005843 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 netif_wake_queue(dev);
5845 }
5846
Stephen Hemminger613573252009-08-31 19:50:58 +00005847 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005849err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005850 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005851err_dma_0:
5852 dev_kfree_skb(skb);
5853 dev->stats.tx_dropped++;
5854 return NETDEV_TX_OK;
5855
5856err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005858 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005859 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860}
5861
5862static void rtl8169_pcierr_interrupt(struct net_device *dev)
5863{
5864 struct rtl8169_private *tp = netdev_priv(dev);
5865 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 u16 pci_status, pci_cmd;
5867
5868 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5869 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5870
Joe Perchesbf82c182010-02-09 11:49:50 +00005871 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5872 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873
5874 /*
5875 * The recovery sequence below admits a very elaborated explanation:
5876 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005877 * - I did not see what else could be done;
5878 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 *
5880 * Feel free to adjust to your needs.
5881 */
Francois Romieua27993f2006-12-18 00:04:19 +01005882 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005883 pci_cmd &= ~PCI_COMMAND_PARITY;
5884 else
5885 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5886
5887 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888
5889 pci_write_config_word(pdev, PCI_STATUS,
5890 pci_status & (PCI_STATUS_DETECTED_PARITY |
5891 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5892 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5893
5894 /* The infamous DAC f*ckup only happens at boot time */
5895 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005896 void __iomem *ioaddr = tp->mmio_addr;
5897
Joe Perchesbf82c182010-02-09 11:49:50 +00005898 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 tp->cp_cmd &= ~PCIDAC;
5900 RTL_W16(CPlusCmd, tp->cp_cmd);
5901 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 }
5903
françois romieue6de30d2011-01-03 15:08:37 +00005904 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005905
Francois Romieu98ddf982012-01-31 10:47:34 +01005906 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907}
5908
Francois Romieuda78dbf2012-01-26 14:18:23 +01005909static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910{
5911 unsigned int dirty_tx, tx_left;
5912
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 dirty_tx = tp->dirty_tx;
5914 smp_rmb();
5915 tx_left = tp->cur_tx - dirty_tx;
5916
5917 while (tx_left > 0) {
5918 unsigned int entry = dirty_tx % NUM_TX_DESC;
5919 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 u32 status;
5921
5922 rmb();
5923 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5924 if (status & DescOwn)
5925 break;
5926
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005927 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5928 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005930 u64_stats_update_begin(&tp->tx_stats.syncp);
5931 tp->tx_stats.packets++;
5932 tp->tx_stats.bytes += tx_skb->skb->len;
5933 u64_stats_update_end(&tp->tx_stats.syncp);
5934 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 tx_skb->skb = NULL;
5936 }
5937 dirty_tx++;
5938 tx_left--;
5939 }
5940
5941 if (tp->dirty_tx != dirty_tx) {
5942 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005943 /* Sync with rtl8169_start_xmit:
5944 * - publish dirty_tx ring index (write barrier)
5945 * - refresh cur_tx ring index and queue status (read barrier)
5946 * May the current thread miss the stopped queue condition,
5947 * a racing xmit thread can only have a right view of the
5948 * ring status.
5949 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005950 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005952 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 netif_wake_queue(dev);
5954 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005955 /*
5956 * 8168 hack: TxPoll requests are lost when the Tx packets are
5957 * too close. Let's kick an extra TxPoll request when a burst
5958 * of start_xmit activity is detected (if it is not detected,
5959 * it is slow enough). -- FR
5960 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005961 if (tp->cur_tx != dirty_tx) {
5962 void __iomem *ioaddr = tp->mmio_addr;
5963
Francois Romieud78ae2d2007-08-26 20:08:19 +02005964 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 }
5967}
5968
Francois Romieu126fa4b2005-05-12 20:09:17 -04005969static inline int rtl8169_fragmented_frame(u32 status)
5970{
5971 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5972}
5973
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005974static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976 u32 status = opts1 & RxProtoMask;
5977
5978 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005979 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 skb->ip_summed = CHECKSUM_UNNECESSARY;
5981 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005982 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983}
5984
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005985static struct sk_buff *rtl8169_try_rx_copy(void *data,
5986 struct rtl8169_private *tp,
5987 int pkt_size,
5988 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02005990 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005991 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005993 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005994 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005995 prefetch(data);
5996 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
5997 if (skb)
5998 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005999 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
6000
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006001 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002}
6003
Francois Romieuda78dbf2012-01-26 14:18:23 +01006004static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005{
6006 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006007 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009 cur_rx = tp->cur_rx;
6010 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02006011 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006013 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006015 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 u32 status;
6017
6018 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04006019 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020
6021 if (status & DescOwn)
6022 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006023 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00006024 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
6025 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006026 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006028 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006030 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006031 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006032 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006033 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006034 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006035 if ((status & (RxRUNT | RxCRC)) &&
6036 !(status & (RxRWT | RxFOVF)) &&
6037 (dev->features & NETIF_F_RXALL))
6038 goto process_pkt;
6039
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006040 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006042 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006043 dma_addr_t addr;
6044 int pkt_size;
6045
6046process_pkt:
6047 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006048 if (likely(!(dev->features & NETIF_F_RXFCS)))
6049 pkt_size = (status & 0x00003fff) - 4;
6050 else
6051 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052
Francois Romieu126fa4b2005-05-12 20:09:17 -04006053 /*
6054 * The driver does not support incoming fragmented
6055 * frames. They are seen as a symptom of over-mtu
6056 * sized frames.
6057 */
6058 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006059 dev->stats.rx_dropped++;
6060 dev->stats.rx_length_errors++;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006061 rtl8169_mark_to_asic(desc, rx_buf_sz);
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006062 continue;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006063 }
6064
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006065 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6066 tp, pkt_size, addr);
6067 rtl8169_mark_to_asic(desc, rx_buf_sz);
6068 if (!skb) {
6069 dev->stats.rx_dropped++;
6070 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 }
6072
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006073 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 skb_put(skb, pkt_size);
6075 skb->protocol = eth_type_trans(skb, dev);
6076
Francois Romieu7a8fc772011-03-01 17:18:33 +01006077 rtl8169_rx_vlan_tag(desc, skb);
6078
Francois Romieu56de4142011-03-15 17:29:31 +01006079 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
Junchang Wang8027aa22012-03-04 23:30:32 +01006081 u64_stats_update_begin(&tp->rx_stats.syncp);
6082 tp->rx_stats.packets++;
6083 tp->rx_stats.bytes += pkt_size;
6084 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 }
Francois Romieu6dccd162007-02-13 23:38:05 +01006086
6087 /* Work around for AMD plateform. */
Al Viro95e09182007-12-22 18:55:39 +00006088 if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
Francois Romieu6dccd162007-02-13 23:38:05 +01006089 (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
6090 desc->opts2 = 0;
6091 cur_rx++;
6092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 }
6094
6095 count = cur_rx - tp->cur_rx;
6096 tp->cur_rx = cur_rx;
6097
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006098 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099
6100 return count;
6101}
6102
Francois Romieu07d3f512007-02-21 22:40:46 +01006103static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104{
Francois Romieu07d3f512007-02-21 22:40:46 +01006105 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006108 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006110 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006111 if (status && status != 0xffff) {
6112 status &= RTL_EVENT_NAPI | tp->event_slow;
6113 if (status) {
6114 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006115
Francois Romieuda78dbf2012-01-26 14:18:23 +01006116 rtl_irq_disable(tp);
6117 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 return IRQ_RETVAL(handled);
6121}
6122
Francois Romieuda78dbf2012-01-26 14:18:23 +01006123/*
6124 * Workqueue context.
6125 */
6126static void rtl_slow_event_work(struct rtl8169_private *tp)
6127{
6128 struct net_device *dev = tp->dev;
6129 u16 status;
6130
6131 status = rtl_get_events(tp) & tp->event_slow;
6132 rtl_ack_events(tp, status);
6133
6134 if (unlikely(status & RxFIFOOver)) {
6135 switch (tp->mac_version) {
6136 /* Work around for rx fifo overflow */
6137 case RTL_GIGA_MAC_VER_11:
6138 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006139 /* XXX - Hack alert. See rtl_task(). */
6140 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006141 default:
6142 break;
6143 }
6144 }
6145
6146 if (unlikely(status & SYSErr))
6147 rtl8169_pcierr_interrupt(dev);
6148
6149 if (status & LinkChg)
6150 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6151
françois romieu7dbb4912012-06-09 10:53:16 +00006152 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006153}
6154
Francois Romieu4422bcd2012-01-26 11:23:32 +01006155static void rtl_task(struct work_struct *work)
6156{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006157 static const struct {
6158 int bitnr;
6159 void (*action)(struct rtl8169_private *);
6160 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006161 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006162 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6163 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6164 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6165 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006166 struct rtl8169_private *tp =
6167 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006168 struct net_device *dev = tp->dev;
6169 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006170
Francois Romieuda78dbf2012-01-26 14:18:23 +01006171 rtl_lock_work(tp);
6172
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006173 if (!netif_running(dev) ||
6174 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006175 goto out_unlock;
6176
6177 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6178 bool pending;
6179
Francois Romieuda78dbf2012-01-26 14:18:23 +01006180 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006181 if (pending)
6182 rtl_work[i].action(tp);
6183 }
6184
6185out_unlock:
6186 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006187}
6188
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006189static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006191 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6192 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006193 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6194 int work_done= 0;
6195 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196
Francois Romieuda78dbf2012-01-26 14:18:23 +01006197 status = rtl_get_events(tp);
6198 rtl_ack_events(tp, status & ~tp->event_slow);
6199
6200 if (status & RTL_EVENT_NAPI_RX)
6201 work_done = rtl_rx(dev, tp, (u32) budget);
6202
6203 if (status & RTL_EVENT_NAPI_TX)
6204 rtl_tx(dev, tp);
6205
6206 if (status & tp->event_slow) {
6207 enable_mask &= ~tp->event_slow;
6208
6209 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006212 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006213 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006214
Francois Romieuda78dbf2012-01-26 14:18:23 +01006215 rtl_irq_enable(tp, enable_mask);
6216 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006219 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221
Francois Romieu523a6092008-09-10 22:28:56 +02006222static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6223{
6224 struct rtl8169_private *tp = netdev_priv(dev);
6225
6226 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6227 return;
6228
6229 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6230 RTL_W32(RxMissed, 0);
6231}
6232
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233static void rtl8169_down(struct net_device *dev)
6234{
6235 struct rtl8169_private *tp = netdev_priv(dev);
6236 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237
Francois Romieu4876cc12011-03-11 21:07:11 +01006238 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006240 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006241 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242
Hayes Wang92fc43b2011-07-06 15:58:03 +08006243 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006244 /*
6245 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006246 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6247 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006248 */
Francois Romieu523a6092008-09-10 22:28:56 +02006249 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006252 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 rtl8169_tx_clear(tp);
6255
6256 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006257
6258 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259}
6260
6261static int rtl8169_close(struct net_device *dev)
6262{
6263 struct rtl8169_private *tp = netdev_priv(dev);
6264 struct pci_dev *pdev = tp->pci_dev;
6265
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006266 pm_runtime_get_sync(&pdev->dev);
6267
Francois Romieucecb5fd2011-04-01 10:21:07 +02006268 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006269 rtl8169_update_counters(dev);
6270
Francois Romieuda78dbf2012-01-26 14:18:23 +01006271 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006272 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006273
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006275 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006277 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006279 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6280 tp->RxPhyAddr);
6281 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6282 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 tp->TxDescArray = NULL;
6284 tp->RxDescArray = NULL;
6285
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006286 pm_runtime_put_sync(&pdev->dev);
6287
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288 return 0;
6289}
6290
Francois Romieudc1c00c2012-03-08 10:06:18 +01006291#ifdef CONFIG_NET_POLL_CONTROLLER
6292static void rtl8169_netpoll(struct net_device *dev)
6293{
6294 struct rtl8169_private *tp = netdev_priv(dev);
6295
6296 rtl8169_interrupt(tp->pci_dev->irq, dev);
6297}
6298#endif
6299
Francois Romieudf43ac72012-03-08 09:48:40 +01006300static int rtl_open(struct net_device *dev)
6301{
6302 struct rtl8169_private *tp = netdev_priv(dev);
6303 void __iomem *ioaddr = tp->mmio_addr;
6304 struct pci_dev *pdev = tp->pci_dev;
6305 int retval = -ENOMEM;
6306
6307 pm_runtime_get_sync(&pdev->dev);
6308
6309 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006310 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006311 * dma_alloc_coherent provides more.
6312 */
6313 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6314 &tp->TxPhyAddr, GFP_KERNEL);
6315 if (!tp->TxDescArray)
6316 goto err_pm_runtime_put;
6317
6318 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6319 &tp->RxPhyAddr, GFP_KERNEL);
6320 if (!tp->RxDescArray)
6321 goto err_free_tx_0;
6322
6323 retval = rtl8169_init_ring(dev);
6324 if (retval < 0)
6325 goto err_free_rx_1;
6326
6327 INIT_WORK(&tp->wk.work, rtl_task);
6328
6329 smp_mb();
6330
6331 rtl_request_firmware(tp);
6332
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006333 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006334 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6335 dev->name, dev);
6336 if (retval < 0)
6337 goto err_release_fw_2;
6338
6339 rtl_lock_work(tp);
6340
6341 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6342
6343 napi_enable(&tp->napi);
6344
6345 rtl8169_init_phy(dev, tp);
6346
6347 __rtl8169_set_features(dev, dev->features);
6348
6349 rtl_pll_power_up(tp);
6350
6351 rtl_hw_start(dev);
6352
6353 netif_start_queue(dev);
6354
6355 rtl_unlock_work(tp);
6356
6357 tp->saved_wolopts = 0;
6358 pm_runtime_put_noidle(&pdev->dev);
6359
6360 rtl8169_check_link_status(dev, tp, ioaddr);
6361out:
6362 return retval;
6363
6364err_release_fw_2:
6365 rtl_release_firmware(tp);
6366 rtl8169_rx_clear(tp);
6367err_free_rx_1:
6368 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6369 tp->RxPhyAddr);
6370 tp->RxDescArray = NULL;
6371err_free_tx_0:
6372 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6373 tp->TxPhyAddr);
6374 tp->TxDescArray = NULL;
6375err_pm_runtime_put:
6376 pm_runtime_put_noidle(&pdev->dev);
6377 goto out;
6378}
6379
Junchang Wang8027aa22012-03-04 23:30:32 +01006380static struct rtnl_link_stats64 *
6381rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382{
6383 struct rtl8169_private *tp = netdev_priv(dev);
6384 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006385 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386
Francois Romieuda78dbf2012-01-26 14:18:23 +01006387 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006388 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006389
Junchang Wang8027aa22012-03-04 23:30:32 +01006390 do {
6391 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6392 stats->rx_packets = tp->rx_stats.packets;
6393 stats->rx_bytes = tp->rx_stats.bytes;
6394 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6395
6396
6397 do {
6398 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6399 stats->tx_packets = tp->tx_stats.packets;
6400 stats->tx_bytes = tp->tx_stats.bytes;
6401 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6402
6403 stats->rx_dropped = dev->stats.rx_dropped;
6404 stats->tx_dropped = dev->stats.tx_dropped;
6405 stats->rx_length_errors = dev->stats.rx_length_errors;
6406 stats->rx_errors = dev->stats.rx_errors;
6407 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6408 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6409 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6410
6411 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412}
6413
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006414static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006415{
françois romieu065c27c2011-01-03 15:08:12 +00006416 struct rtl8169_private *tp = netdev_priv(dev);
6417
Francois Romieu5d06a992006-02-23 00:47:58 +01006418 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006419 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006420
6421 netif_device_detach(dev);
6422 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006423
6424 rtl_lock_work(tp);
6425 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006426 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006427 rtl_unlock_work(tp);
6428
6429 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006430}
Francois Romieu5d06a992006-02-23 00:47:58 +01006431
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006432#ifdef CONFIG_PM
6433
6434static int rtl8169_suspend(struct device *device)
6435{
6436 struct pci_dev *pdev = to_pci_dev(device);
6437 struct net_device *dev = pci_get_drvdata(pdev);
6438
6439 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006440
Francois Romieu5d06a992006-02-23 00:47:58 +01006441 return 0;
6442}
6443
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006444static void __rtl8169_resume(struct net_device *dev)
6445{
françois romieu065c27c2011-01-03 15:08:12 +00006446 struct rtl8169_private *tp = netdev_priv(dev);
6447
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006448 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006449
6450 rtl_pll_power_up(tp);
6451
Artem Savkovcff4c162012-04-03 10:29:11 +00006452 rtl_lock_work(tp);
6453 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006454 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006455 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006456
Francois Romieu98ddf982012-01-31 10:47:34 +01006457 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006458}
6459
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006460static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006461{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006462 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006463 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006464 struct rtl8169_private *tp = netdev_priv(dev);
6465
6466 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006467
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006468 if (netif_running(dev))
6469 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006470
Francois Romieu5d06a992006-02-23 00:47:58 +01006471 return 0;
6472}
6473
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006474static int rtl8169_runtime_suspend(struct device *device)
6475{
6476 struct pci_dev *pdev = to_pci_dev(device);
6477 struct net_device *dev = pci_get_drvdata(pdev);
6478 struct rtl8169_private *tp = netdev_priv(dev);
6479
6480 if (!tp->TxDescArray)
6481 return 0;
6482
Francois Romieuda78dbf2012-01-26 14:18:23 +01006483 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006484 tp->saved_wolopts = __rtl8169_get_wol(tp);
6485 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006486 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006487
6488 rtl8169_net_suspend(dev);
6489
6490 return 0;
6491}
6492
6493static int rtl8169_runtime_resume(struct device *device)
6494{
6495 struct pci_dev *pdev = to_pci_dev(device);
6496 struct net_device *dev = pci_get_drvdata(pdev);
6497 struct rtl8169_private *tp = netdev_priv(dev);
6498
6499 if (!tp->TxDescArray)
6500 return 0;
6501
Francois Romieuda78dbf2012-01-26 14:18:23 +01006502 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006503 __rtl8169_set_wol(tp, tp->saved_wolopts);
6504 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006505 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006506
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006507 rtl8169_init_phy(dev, tp);
6508
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006509 __rtl8169_resume(dev);
6510
6511 return 0;
6512}
6513
6514static int rtl8169_runtime_idle(struct device *device)
6515{
6516 struct pci_dev *pdev = to_pci_dev(device);
6517 struct net_device *dev = pci_get_drvdata(pdev);
6518 struct rtl8169_private *tp = netdev_priv(dev);
6519
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006520 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006521}
6522
Alexey Dobriyan47145212009-12-14 18:00:08 -08006523static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006524 .suspend = rtl8169_suspend,
6525 .resume = rtl8169_resume,
6526 .freeze = rtl8169_suspend,
6527 .thaw = rtl8169_resume,
6528 .poweroff = rtl8169_suspend,
6529 .restore = rtl8169_resume,
6530 .runtime_suspend = rtl8169_runtime_suspend,
6531 .runtime_resume = rtl8169_runtime_resume,
6532 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006533};
6534
6535#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6536
6537#else /* !CONFIG_PM */
6538
6539#define RTL8169_PM_OPS NULL
6540
6541#endif /* !CONFIG_PM */
6542
David S. Miller1805b2f2011-10-24 18:18:09 -04006543static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6544{
6545 void __iomem *ioaddr = tp->mmio_addr;
6546
6547 /* WoL fails with 8168b when the receiver is disabled. */
6548 switch (tp->mac_version) {
6549 case RTL_GIGA_MAC_VER_11:
6550 case RTL_GIGA_MAC_VER_12:
6551 case RTL_GIGA_MAC_VER_17:
6552 pci_clear_master(tp->pci_dev);
6553
6554 RTL_W8(ChipCmd, CmdRxEnb);
6555 /* PCI commit */
6556 RTL_R8(ChipCmd);
6557 break;
6558 default:
6559 break;
6560 }
6561}
6562
Francois Romieu1765f952008-09-13 17:21:40 +02006563static void rtl_shutdown(struct pci_dev *pdev)
6564{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006565 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006566 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006567 struct device *d = &pdev->dev;
6568
6569 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006570
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006571 rtl8169_net_suspend(dev);
6572
Francois Romieucecb5fd2011-04-01 10:21:07 +02006573 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006574 rtl_rar_set(tp, dev->perm_addr);
6575
Hayes Wang92fc43b2011-07-06 15:58:03 +08006576 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006577
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006578 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006579 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6580 rtl_wol_suspend_quirk(tp);
6581 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006582 }
6583
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006584 pci_wake_from_d3(pdev, true);
6585 pci_set_power_state(pdev, PCI_D3hot);
6586 }
françois romieu2a15cd22012-03-06 01:14:12 +00006587
6588 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006589}
Francois Romieu5d06a992006-02-23 00:47:58 +01006590
Francois Romieue27566e2012-03-08 09:54:01 +01006591static void __devexit rtl_remove_one(struct pci_dev *pdev)
6592{
6593 struct net_device *dev = pci_get_drvdata(pdev);
6594 struct rtl8169_private *tp = netdev_priv(dev);
6595
6596 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6597 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6598 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6599 rtl8168_driver_stop(tp);
6600 }
6601
6602 cancel_work_sync(&tp->wk.work);
6603
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006604 netif_napi_del(&tp->napi);
6605
Francois Romieue27566e2012-03-08 09:54:01 +01006606 unregister_netdev(dev);
6607
6608 rtl_release_firmware(tp);
6609
6610 if (pci_dev_run_wake(pdev))
6611 pm_runtime_get_noresume(&pdev->dev);
6612
6613 /* restore original MAC address */
6614 rtl_rar_set(tp, dev->perm_addr);
6615
6616 rtl_disable_msi(pdev, tp);
6617 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6618 pci_set_drvdata(pdev, NULL);
6619}
6620
Francois Romieufa9c3852012-03-08 10:01:50 +01006621static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006622 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006623 .ndo_stop = rtl8169_close,
6624 .ndo_get_stats64 = rtl8169_get_stats64,
6625 .ndo_start_xmit = rtl8169_start_xmit,
6626 .ndo_tx_timeout = rtl8169_tx_timeout,
6627 .ndo_validate_addr = eth_validate_addr,
6628 .ndo_change_mtu = rtl8169_change_mtu,
6629 .ndo_fix_features = rtl8169_fix_features,
6630 .ndo_set_features = rtl8169_set_features,
6631 .ndo_set_mac_address = rtl_set_mac_address,
6632 .ndo_do_ioctl = rtl8169_ioctl,
6633 .ndo_set_rx_mode = rtl_set_rx_mode,
6634#ifdef CONFIG_NET_POLL_CONTROLLER
6635 .ndo_poll_controller = rtl8169_netpoll,
6636#endif
6637
6638};
6639
Francois Romieu31fa8b12012-03-08 10:09:40 +01006640static const struct rtl_cfg_info {
6641 void (*hw_start)(struct net_device *);
6642 unsigned int region;
6643 unsigned int align;
6644 u16 event_slow;
6645 unsigned features;
6646 u8 default_ver;
6647} rtl_cfg_infos [] = {
6648 [RTL_CFG_0] = {
6649 .hw_start = rtl_hw_start_8169,
6650 .region = 1,
6651 .align = 0,
6652 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6653 .features = RTL_FEATURE_GMII,
6654 .default_ver = RTL_GIGA_MAC_VER_01,
6655 },
6656 [RTL_CFG_1] = {
6657 .hw_start = rtl_hw_start_8168,
6658 .region = 2,
6659 .align = 8,
6660 .event_slow = SYSErr | LinkChg | RxOverflow,
6661 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6662 .default_ver = RTL_GIGA_MAC_VER_11,
6663 },
6664 [RTL_CFG_2] = {
6665 .hw_start = rtl_hw_start_8101,
6666 .region = 2,
6667 .align = 8,
6668 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6669 PCSTimeout,
6670 .features = RTL_FEATURE_MSI,
6671 .default_ver = RTL_GIGA_MAC_VER_13,
6672 }
6673};
6674
6675/* Cfg9346_Unlock assumed. */
6676static unsigned rtl_try_msi(struct rtl8169_private *tp,
6677 const struct rtl_cfg_info *cfg)
6678{
6679 void __iomem *ioaddr = tp->mmio_addr;
6680 unsigned msi = 0;
6681 u8 cfg2;
6682
6683 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6684 if (cfg->features & RTL_FEATURE_MSI) {
6685 if (pci_enable_msi(tp->pci_dev)) {
6686 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6687 } else {
6688 cfg2 |= MSIEnable;
6689 msi = RTL_FEATURE_MSI;
6690 }
6691 }
6692 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6693 RTL_W8(Config2, cfg2);
6694 return msi;
6695}
6696
Hayes Wangc5583862012-07-02 17:23:22 +08006697DECLARE_RTL_COND(rtl_link_list_ready_cond)
6698{
6699 void __iomem *ioaddr = tp->mmio_addr;
6700
6701 return RTL_R8(MCU) & LINK_LIST_RDY;
6702}
6703
6704DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6705{
6706 void __iomem *ioaddr = tp->mmio_addr;
6707
6708 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6709}
6710
6711static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
6712{
6713 void __iomem *ioaddr = tp->mmio_addr;
6714 u32 data;
6715
6716 tp->ocp_base = OCP_STD_PHY_BASE;
6717
6718 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6719
6720 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6721 return;
6722
6723 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6724 return;
6725
6726 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6727 msleep(1);
6728 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6729
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006730 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006731 data &= ~(1 << 14);
6732 r8168_mac_ocp_write(tp, 0xe8de, data);
6733
6734 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6735 return;
6736
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006737 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006738 data |= (1 << 15);
6739 r8168_mac_ocp_write(tp, 0xe8de, data);
6740
6741 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6742 return;
6743}
6744
6745static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
6746{
6747 switch (tp->mac_version) {
6748 case RTL_GIGA_MAC_VER_40:
6749 case RTL_GIGA_MAC_VER_41:
6750 rtl_hw_init_8168g(tp);
6751 break;
6752
6753 default:
6754 break;
6755 }
6756}
6757
Francois Romieu3b6cf252012-03-08 09:59:04 +01006758static int __devinit
6759rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6760{
6761 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6762 const unsigned int region = cfg->region;
6763 struct rtl8169_private *tp;
6764 struct mii_if_info *mii;
6765 struct net_device *dev;
6766 void __iomem *ioaddr;
6767 int chipset, i;
6768 int rc;
6769
6770 if (netif_msg_drv(&debug)) {
6771 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6772 MODULENAME, RTL8169_VERSION);
6773 }
6774
6775 dev = alloc_etherdev(sizeof (*tp));
6776 if (!dev) {
6777 rc = -ENOMEM;
6778 goto out;
6779 }
6780
6781 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006782 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006783 tp = netdev_priv(dev);
6784 tp->dev = dev;
6785 tp->pci_dev = pdev;
6786 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6787
6788 mii = &tp->mii;
6789 mii->dev = dev;
6790 mii->mdio_read = rtl_mdio_read;
6791 mii->mdio_write = rtl_mdio_write;
6792 mii->phy_id_mask = 0x1f;
6793 mii->reg_num_mask = 0x1f;
6794 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6795
6796 /* disable ASPM completely as that cause random device stop working
6797 * problems as well as full system hangs for some PCIe devices users */
6798 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6799 PCIE_LINK_STATE_CLKPM);
6800
6801 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6802 rc = pci_enable_device(pdev);
6803 if (rc < 0) {
6804 netif_err(tp, probe, dev, "enable failure\n");
6805 goto err_out_free_dev_1;
6806 }
6807
6808 if (pci_set_mwi(pdev) < 0)
6809 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6810
6811 /* make sure PCI base addr 1 is MMIO */
6812 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6813 netif_err(tp, probe, dev,
6814 "region #%d not an MMIO resource, aborting\n",
6815 region);
6816 rc = -ENODEV;
6817 goto err_out_mwi_2;
6818 }
6819
6820 /* check for weird/broken PCI region reporting */
6821 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6822 netif_err(tp, probe, dev,
6823 "Invalid PCI region size(s), aborting\n");
6824 rc = -ENODEV;
6825 goto err_out_mwi_2;
6826 }
6827
6828 rc = pci_request_regions(pdev, MODULENAME);
6829 if (rc < 0) {
6830 netif_err(tp, probe, dev, "could not request regions\n");
6831 goto err_out_mwi_2;
6832 }
6833
6834 tp->cp_cmd = RxChkSum;
6835
6836 if ((sizeof(dma_addr_t) > 4) &&
6837 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6838 tp->cp_cmd |= PCIDAC;
6839 dev->features |= NETIF_F_HIGHDMA;
6840 } else {
6841 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6842 if (rc < 0) {
6843 netif_err(tp, probe, dev, "DMA configuration failed\n");
6844 goto err_out_free_res_3;
6845 }
6846 }
6847
6848 /* ioremap MMIO region */
6849 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6850 if (!ioaddr) {
6851 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6852 rc = -EIO;
6853 goto err_out_free_res_3;
6854 }
6855 tp->mmio_addr = ioaddr;
6856
6857 if (!pci_is_pcie(pdev))
6858 netif_info(tp, probe, dev, "not PCI Express\n");
6859
6860 /* Identify chip attached to board */
6861 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6862
6863 rtl_init_rxcfg(tp);
6864
6865 rtl_irq_disable(tp);
6866
Hayes Wangc5583862012-07-02 17:23:22 +08006867 rtl_hw_initialize(tp);
6868
Francois Romieu3b6cf252012-03-08 09:59:04 +01006869 rtl_hw_reset(tp);
6870
6871 rtl_ack_events(tp, 0xffff);
6872
6873 pci_set_master(pdev);
6874
6875 /*
6876 * Pretend we are using VLANs; This bypasses a nasty bug where
6877 * Interrupts stop flowing on high load on 8110SCd controllers.
6878 */
6879 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6880 tp->cp_cmd |= RxVlan;
6881
6882 rtl_init_mdio_ops(tp);
6883 rtl_init_pll_power_ops(tp);
6884 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006885 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006886
6887 rtl8169_print_mac_version(tp);
6888
6889 chipset = tp->mac_version;
6890 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6891
6892 RTL_W8(Cfg9346, Cfg9346_Unlock);
6893 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6894 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6895 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6896 tp->features |= RTL_FEATURE_WOL;
6897 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6898 tp->features |= RTL_FEATURE_WOL;
6899 tp->features |= rtl_try_msi(tp, cfg);
6900 RTL_W8(Cfg9346, Cfg9346_Lock);
6901
6902 if (rtl_tbi_enabled(tp)) {
6903 tp->set_speed = rtl8169_set_speed_tbi;
6904 tp->get_settings = rtl8169_gset_tbi;
6905 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6906 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6907 tp->link_ok = rtl8169_tbi_link_ok;
6908 tp->do_ioctl = rtl_tbi_ioctl;
6909 } else {
6910 tp->set_speed = rtl8169_set_speed_xmii;
6911 tp->get_settings = rtl8169_gset_xmii;
6912 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6913 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6914 tp->link_ok = rtl8169_xmii_link_ok;
6915 tp->do_ioctl = rtl_xmii_ioctl;
6916 }
6917
6918 mutex_init(&tp->wk.mutex);
6919
6920 /* Get MAC address */
6921 for (i = 0; i < ETH_ALEN; i++)
6922 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6923 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6924
6925 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6926 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006927
6928 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6929
6930 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6931 * properly for all devices */
6932 dev->features |= NETIF_F_RXCSUM |
6933 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6934
6935 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6936 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6937 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6938 NETIF_F_HIGHDMA;
6939
6940 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6941 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6942 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6943
6944 dev->hw_features |= NETIF_F_RXALL;
6945 dev->hw_features |= NETIF_F_RXFCS;
6946
6947 tp->hw_start = cfg->hw_start;
6948 tp->event_slow = cfg->event_slow;
6949
6950 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6951 ~(RxBOVF | RxFOVF) : ~0;
6952
6953 init_timer(&tp->timer);
6954 tp->timer.data = (unsigned long) dev;
6955 tp->timer.function = rtl8169_phy_timer;
6956
6957 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6958
6959 rc = register_netdev(dev);
6960 if (rc < 0)
6961 goto err_out_msi_4;
6962
6963 pci_set_drvdata(pdev, dev);
6964
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006965 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6966 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6967 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006968 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6969 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6970 "tx checksumming: %s]\n",
6971 rtl_chip_infos[chipset].jumbo_max,
6972 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6973 }
6974
6975 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6976 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6977 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6978 rtl8168_driver_start(tp);
6979 }
6980
6981 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6982
6983 if (pci_dev_run_wake(pdev))
6984 pm_runtime_put_noidle(&pdev->dev);
6985
6986 netif_carrier_off(dev);
6987
6988out:
6989 return rc;
6990
6991err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006992 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006993 rtl_disable_msi(pdev, tp);
6994 iounmap(ioaddr);
6995err_out_free_res_3:
6996 pci_release_regions(pdev);
6997err_out_mwi_2:
6998 pci_clear_mwi(pdev);
6999 pci_disable_device(pdev);
7000err_out_free_dev_1:
7001 free_netdev(dev);
7002 goto out;
7003}
7004
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005static struct pci_driver rtl8169_pci_driver = {
7006 .name = MODULENAME,
7007 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01007008 .probe = rtl_init_one,
Francois Romieue27566e2012-03-08 09:54:01 +01007009 .remove = __devexit_p(rtl_remove_one),
Francois Romieu1765f952008-09-13 17:21:40 +02007010 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00007011 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012};
7013
Francois Romieu07d3f512007-02-21 22:40:46 +01007014static int __init rtl8169_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015{
Jeff Garzik29917622006-08-19 17:48:59 -04007016 return pci_register_driver(&rtl8169_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017}
7018
Francois Romieu07d3f512007-02-21 22:40:46 +01007019static void __exit rtl8169_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020{
7021 pci_unregister_driver(&rtl8169_pci_driver);
7022}
7023
7024module_init(rtl8169_init_module);
7025module_exit(rtl8169_cleanup_module);