blob: 998974f7874253f67880009d96f1e80f4788a408 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Francois Romieu07d3f512007-02-21 22:40:46 +01002 * r8169.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/delay.h>
17#include <linux/ethtool.h>
18#include <linux/mii.h>
19#include <linux/if_vlan.h>
20#include <linux/crc32.h>
21#include <linux/in.h>
22#include <linux/ip.h>
23#include <linux/tcp.h>
24#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000025#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/dma-mapping.h>
Rafael J. Wysockie1759442010-03-14 14:33:51 +000027#include <linux/pm_runtime.h>
françois romieubca03d52011-01-03 15:07:31 +000028#include <linux/firmware.h>
Stanislaw Gruszkaba04c7c2011-02-22 02:00:11 +000029#include <linux/pci-aspm.h>
Paul Gortmaker70c71602011-05-22 16:47:17 -040030#include <linux/prefetch.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <asm/io.h>
33#include <asm/irq.h>
34
Francois Romieu865c6522008-05-11 14:51:00 +020035#define RTL8169_VERSION "2.3LK-NAPI"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MODULENAME "r8169"
37#define PFX MODULENAME ": "
38
françois romieubca03d52011-01-03 15:07:31 +000039#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
40#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
hayeswang01dc7fe2011-03-21 01:50:28 +000041#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
42#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
Hayes Wang70090422011-07-06 15:58:06 +080043#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
Hayes Wangc2218922011-09-06 16:55:18 +080044#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
45#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
Hayes Wang5a5e4442011-02-22 17:26:21 +080046#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
Hayes Wang7e18dca2012-03-30 14:33:02 +080047#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
Hayes Wangb3d7b2f2012-03-30 14:48:06 +080048#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
Hayes Wang5598bfe2012-07-02 17:23:21 +080049#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
Hayes Wangc5583862012-07-02 17:23:22 +080050#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
françois romieubca03d52011-01-03 15:07:31 +000051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#ifdef RTL8169_DEBUG
53#define assert(expr) \
Francois Romieu5b0384f2006-08-16 16:00:01 +020054 if (!(expr)) { \
55 printk( "Assertion failed! %s,%s,%s,line=%d\n", \
Harvey Harrisonb39d66a2008-08-20 16:52:04 -070056 #expr,__FILE__,__func__,__LINE__); \
Francois Romieu5b0384f2006-08-16 16:00:01 +020057 }
Joe Perches06fa7352007-10-18 21:15:00 +020058#define dprintk(fmt, args...) \
59 do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#else
61#define assert(expr) do {} while (0)
62#define dprintk(fmt, args...) do {} while (0)
63#endif /* RTL8169_DEBUG */
64
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020065#define R8169_MSG_DEFAULT \
Francois Romieuf0e837d2005-09-30 16:54:02 -070066 (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020067
Julien Ducourthial477206a2012-05-09 00:00:06 +020068#define TX_SLOTS_AVAIL(tp) \
69 (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
70
71/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
72#define TX_FRAGS_READY_FOR(tp,nr_frags) \
73 (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
76 The RTL chips use a 64 element hash table based on the Ethernet CRC. */
Arjan van de Venf71e1302006-03-03 21:33:57 -050077static const int multicast_filter_limit = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Francois Romieu9c14cea2008-07-05 00:21:15 +020079#define MAX_READ_REQUEST_SHIFT 12
Michal Schmidtaee77e42012-09-09 13:55:26 +000080#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
82
83#define R8169_REGS_SIZE 256
84#define R8169_NAPI_WEIGHT 64
85#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
86#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
88#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
89
90#define RTL8169_TX_TIMEOUT (6*HZ)
91#define RTL8169_PHY_TIMEOUT (10*HZ)
92
93/* write/read MMIO register */
94#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
95#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
96#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
97#define RTL_R8(reg) readb (ioaddr + (reg))
98#define RTL_R16(reg) readw (ioaddr + (reg))
Junchang Wang06f555f2010-05-30 02:26:07 +000099#define RTL_R32(reg) readl (ioaddr + (reg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
101enum mac_version {
Francois Romieu85bffe62011-04-27 08:22:39 +0200102 RTL_GIGA_MAC_VER_01 = 0,
103 RTL_GIGA_MAC_VER_02,
104 RTL_GIGA_MAC_VER_03,
105 RTL_GIGA_MAC_VER_04,
106 RTL_GIGA_MAC_VER_05,
107 RTL_GIGA_MAC_VER_06,
108 RTL_GIGA_MAC_VER_07,
109 RTL_GIGA_MAC_VER_08,
110 RTL_GIGA_MAC_VER_09,
111 RTL_GIGA_MAC_VER_10,
112 RTL_GIGA_MAC_VER_11,
113 RTL_GIGA_MAC_VER_12,
114 RTL_GIGA_MAC_VER_13,
115 RTL_GIGA_MAC_VER_14,
116 RTL_GIGA_MAC_VER_15,
117 RTL_GIGA_MAC_VER_16,
118 RTL_GIGA_MAC_VER_17,
119 RTL_GIGA_MAC_VER_18,
120 RTL_GIGA_MAC_VER_19,
121 RTL_GIGA_MAC_VER_20,
122 RTL_GIGA_MAC_VER_21,
123 RTL_GIGA_MAC_VER_22,
124 RTL_GIGA_MAC_VER_23,
125 RTL_GIGA_MAC_VER_24,
126 RTL_GIGA_MAC_VER_25,
127 RTL_GIGA_MAC_VER_26,
128 RTL_GIGA_MAC_VER_27,
129 RTL_GIGA_MAC_VER_28,
130 RTL_GIGA_MAC_VER_29,
131 RTL_GIGA_MAC_VER_30,
132 RTL_GIGA_MAC_VER_31,
133 RTL_GIGA_MAC_VER_32,
134 RTL_GIGA_MAC_VER_33,
Hayes Wang70090422011-07-06 15:58:06 +0800135 RTL_GIGA_MAC_VER_34,
Hayes Wangc2218922011-09-06 16:55:18 +0800136 RTL_GIGA_MAC_VER_35,
137 RTL_GIGA_MAC_VER_36,
Hayes Wang7e18dca2012-03-30 14:33:02 +0800138 RTL_GIGA_MAC_VER_37,
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800139 RTL_GIGA_MAC_VER_38,
Hayes Wang5598bfe2012-07-02 17:23:21 +0800140 RTL_GIGA_MAC_VER_39,
Hayes Wangc5583862012-07-02 17:23:22 +0800141 RTL_GIGA_MAC_VER_40,
142 RTL_GIGA_MAC_VER_41,
Francois Romieu85bffe62011-04-27 08:22:39 +0200143 RTL_GIGA_MAC_NONE = 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
Francois Romieu2b7b4312011-04-18 22:53:24 -0700146enum rtl_tx_desc_version {
147 RTL_TD_0 = 0,
148 RTL_TD_1 = 1,
149};
150
Francois Romieud58d46b2011-05-03 16:38:29 +0200151#define JUMBO_1K ETH_DATA_LEN
152#define JUMBO_4K (4*1024 - ETH_HLEN - 2)
153#define JUMBO_6K (6*1024 - ETH_HLEN - 2)
154#define JUMBO_7K (7*1024 - ETH_HLEN - 2)
155#define JUMBO_9K (9*1024 - ETH_HLEN - 2)
156
157#define _R(NAME,TD,FW,SZ,B) { \
158 .name = NAME, \
159 .txd_version = TD, \
160 .fw_name = FW, \
161 .jumbo_max = SZ, \
162 .jumbo_tx_csum = B \
163}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Jesper Juhl3c6bee12006-01-09 20:54:01 -0800165static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 const char *name;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700167 enum rtl_tx_desc_version txd_version;
Francois Romieu85bffe62011-04-27 08:22:39 +0200168 const char *fw_name;
Francois Romieud58d46b2011-05-03 16:38:29 +0200169 u16 jumbo_max;
170 bool jumbo_tx_csum;
Francois Romieu85bffe62011-04-27 08:22:39 +0200171} rtl_chip_infos[] = {
172 /* PCI devices. */
173 [RTL_GIGA_MAC_VER_01] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200174 _R("RTL8169", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200175 [RTL_GIGA_MAC_VER_02] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200176 _R("RTL8169s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200177 [RTL_GIGA_MAC_VER_03] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200178 _R("RTL8110s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200179 [RTL_GIGA_MAC_VER_04] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200180 _R("RTL8169sb/8110sb", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200181 [RTL_GIGA_MAC_VER_05] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200182 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200183 [RTL_GIGA_MAC_VER_06] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200184 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200185 /* PCI-E devices. */
186 [RTL_GIGA_MAC_VER_07] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200187 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200188 [RTL_GIGA_MAC_VER_08] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200189 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200190 [RTL_GIGA_MAC_VER_09] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200191 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200192 [RTL_GIGA_MAC_VER_10] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200193 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200194 [RTL_GIGA_MAC_VER_11] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200195 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200196 [RTL_GIGA_MAC_VER_12] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200197 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200198 [RTL_GIGA_MAC_VER_13] =
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_14] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200201 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200202 [RTL_GIGA_MAC_VER_15] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200203 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200204 [RTL_GIGA_MAC_VER_16] =
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_17] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200207 _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200208 [RTL_GIGA_MAC_VER_18] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200209 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200210 [RTL_GIGA_MAC_VER_19] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200211 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200212 [RTL_GIGA_MAC_VER_20] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200213 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200214 [RTL_GIGA_MAC_VER_21] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200215 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200216 [RTL_GIGA_MAC_VER_22] =
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_23] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200219 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200220 [RTL_GIGA_MAC_VER_24] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200221 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200222 [RTL_GIGA_MAC_VER_25] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200223 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1,
224 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200225 [RTL_GIGA_MAC_VER_26] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200226 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2,
227 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200228 [RTL_GIGA_MAC_VER_27] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200229 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200230 [RTL_GIGA_MAC_VER_28] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200231 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200232 [RTL_GIGA_MAC_VER_29] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200233 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
234 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200235 [RTL_GIGA_MAC_VER_30] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200236 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
237 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200238 [RTL_GIGA_MAC_VER_31] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200239 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200240 [RTL_GIGA_MAC_VER_32] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200241 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1,
242 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200243 [RTL_GIGA_MAC_VER_33] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200244 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2,
245 JUMBO_9K, false),
Hayes Wang70090422011-07-06 15:58:06 +0800246 [RTL_GIGA_MAC_VER_34] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200247 _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
248 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800249 [RTL_GIGA_MAC_VER_35] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200250 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_1,
251 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800252 [RTL_GIGA_MAC_VER_36] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200253 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2,
254 JUMBO_9K, false),
Hayes Wang7e18dca2012-03-30 14:33:02 +0800255 [RTL_GIGA_MAC_VER_37] =
256 _R("RTL8402", RTL_TD_1, FIRMWARE_8402_1,
257 JUMBO_1K, true),
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800258 [RTL_GIGA_MAC_VER_38] =
259 _R("RTL8411", RTL_TD_1, FIRMWARE_8411_1,
260 JUMBO_9K, false),
Hayes Wang5598bfe2012-07-02 17:23:21 +0800261 [RTL_GIGA_MAC_VER_39] =
262 _R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_1,
263 JUMBO_1K, true),
Hayes Wangc5583862012-07-02 17:23:22 +0800264 [RTL_GIGA_MAC_VER_40] =
265 _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_1,
266 JUMBO_9K, false),
267 [RTL_GIGA_MAC_VER_41] =
268 _R("RTL8168g/8111g", RTL_TD_1, NULL, JUMBO_9K, false),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269};
270#undef _R
271
Francois Romieubcf0bf92006-07-26 23:14:13 +0200272enum cfg_version {
273 RTL_CFG_0 = 0x00,
274 RTL_CFG_1,
275 RTL_CFG_2
276};
277
Alexey Dobriyana3aa1882010-01-07 11:58:11 +0000278static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
Francois Romieubcf0bf92006-07-26 23:14:13 +0200279 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
Francois Romieud2eed8c2006-08-31 22:01:07 +0200280 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
Francois Romieud81bf552006-09-20 21:31:20 +0200281 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
Francois Romieu07ce4062007-02-23 23:36:39 +0100282 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200283 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
Francois Romieu2a35cfa2012-08-31 23:06:17 +0200284 { PCI_VENDOR_ID_DLINK, 0x4300,
285 PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200286 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
Lennart Sorensen93a3aa22011-07-28 13:18:11 +0000287 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 },
Francois Romieubc1660b2007-10-12 23:58:09 +0200288 { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200289 { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
290 { PCI_VENDOR_ID_LINKSYS, 0x1032,
291 PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
Ciaran McCreesh11d2e282007-11-01 22:48:15 +0100292 { 0x0001, 0x8168,
293 PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 {0,},
295};
296
297MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
298
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000299static int rx_buf_sz = 16383;
David S. Miller4300e8c2010-03-26 10:23:30 -0700300static int use_dac;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200301static struct {
302 u32 msg_enable;
303} debug = { -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Francois Romieu07d3f512007-02-21 22:40:46 +0100305enum rtl_registers {
306 MAC0 = 0, /* Ethernet hardware address. */
Francois Romieu773d2022007-01-31 23:47:43 +0100307 MAC4 = 4,
Francois Romieu07d3f512007-02-21 22:40:46 +0100308 MAR0 = 8, /* Multicast filter. */
309 CounterAddrLow = 0x10,
310 CounterAddrHigh = 0x14,
311 TxDescStartAddrLow = 0x20,
312 TxDescStartAddrHigh = 0x24,
313 TxHDescStartAddrLow = 0x28,
314 TxHDescStartAddrHigh = 0x2c,
315 FLASH = 0x30,
316 ERSR = 0x36,
317 ChipCmd = 0x37,
318 TxPoll = 0x38,
319 IntrMask = 0x3c,
320 IntrStatus = 0x3e,
Francois Romieu2b7b4312011-04-18 22:53:24 -0700321
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800322 TxConfig = 0x40,
323#define TXCFG_AUTO_FIFO (1 << 7) /* 8111e-vl */
324#define TXCFG_EMPTY (1 << 11) /* 8111e-vl */
325
326 RxConfig = 0x44,
327#define RX128_INT_EN (1 << 15) /* 8111c and later */
328#define RX_MULTI_EN (1 << 14) /* 8111c only */
329#define RXCFG_FIFO_SHIFT 13
330 /* No threshold before first PCI xfer */
331#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
332#define RXCFG_DMA_SHIFT 8
333 /* Unlimited maximum PCI burst. */
334#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
Francois Romieu2b7b4312011-04-18 22:53:24 -0700335
Francois Romieu07d3f512007-02-21 22:40:46 +0100336 RxMissed = 0x4c,
337 Cfg9346 = 0x50,
338 Config0 = 0x51,
339 Config1 = 0x52,
340 Config2 = 0x53,
Francois Romieud387b422012-04-17 11:12:01 +0200341#define PME_SIGNAL (1 << 5) /* 8168c and later */
342
Francois Romieu07d3f512007-02-21 22:40:46 +0100343 Config3 = 0x54,
344 Config4 = 0x55,
345 Config5 = 0x56,
346 MultiIntr = 0x5c,
347 PHYAR = 0x60,
Francois Romieu07d3f512007-02-21 22:40:46 +0100348 PHYstatus = 0x6c,
349 RxMaxSize = 0xda,
350 CPlusCmd = 0xe0,
351 IntrMitigate = 0xe2,
352 RxDescAddrLow = 0xe4,
353 RxDescAddrHigh = 0xe8,
françois romieuf0298f82011-01-03 15:07:42 +0000354 EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
355
356#define NoEarlyTx 0x3f /* Max value : no early transmit. */
357
358 MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
359
360#define TxPacketMax (8064 >> 7)
Hayes Wang3090bd92011-09-06 16:55:15 +0800361#define EarlySize 0x27
françois romieuf0298f82011-01-03 15:07:42 +0000362
Francois Romieu07d3f512007-02-21 22:40:46 +0100363 FuncEvent = 0xf0,
364 FuncEventMask = 0xf4,
365 FuncPresetState = 0xf8,
366 FuncForceEvent = 0xfc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367};
368
Francois Romieuf162a5d2008-06-01 22:37:49 +0200369enum rtl8110_registers {
370 TBICSR = 0x64,
371 TBI_ANAR = 0x68,
372 TBI_LPAR = 0x6a,
373};
374
375enum rtl8168_8101_registers {
376 CSIDR = 0x64,
377 CSIAR = 0x68,
378#define CSIAR_FLAG 0x80000000
379#define CSIAR_WRITE_CMD 0x80000000
380#define CSIAR_BYTE_ENABLE 0x0f
381#define CSIAR_BYTE_ENABLE_SHIFT 12
382#define CSIAR_ADDR_MASK 0x0fff
Hayes Wang7e18dca2012-03-30 14:33:02 +0800383#define CSIAR_FUNC_CARD 0x00000000
384#define CSIAR_FUNC_SDIO 0x00010000
385#define CSIAR_FUNC_NIC 0x00020000
françois romieu065c27c2011-01-03 15:08:12 +0000386 PMCH = 0x6f,
Francois Romieuf162a5d2008-06-01 22:37:49 +0200387 EPHYAR = 0x80,
388#define EPHYAR_FLAG 0x80000000
389#define EPHYAR_WRITE_CMD 0x80000000
390#define EPHYAR_REG_MASK 0x1f
391#define EPHYAR_REG_SHIFT 16
392#define EPHYAR_DATA_MASK 0xffff
Hayes Wang5a5e4442011-02-22 17:26:21 +0800393 DLLPR = 0xd0,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800394#define PFM_EN (1 << 6)
Francois Romieuf162a5d2008-06-01 22:37:49 +0200395 DBG_REG = 0xd1,
396#define FIX_NAK_1 (1 << 4)
397#define FIX_NAK_2 (1 << 3)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800398 TWSI = 0xd2,
399 MCU = 0xd3,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800400#define NOW_IS_OOB (1 << 7)
Hayes Wangc5583862012-07-02 17:23:22 +0800401#define TX_EMPTY (1 << 5)
402#define RX_EMPTY (1 << 4)
403#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800404#define EN_NDP (1 << 3)
405#define EN_OOB_RESET (1 << 2)
Hayes Wangc5583862012-07-02 17:23:22 +0800406#define LINK_LIST_RDY (1 << 1)
françois romieudaf9df62009-10-07 12:44:20 +0000407 EFUSEAR = 0xdc,
408#define EFUSEAR_FLAG 0x80000000
409#define EFUSEAR_WRITE_CMD 0x80000000
410#define EFUSEAR_READ_CMD 0x00000000
411#define EFUSEAR_REG_MASK 0x03ff
412#define EFUSEAR_REG_SHIFT 8
413#define EFUSEAR_DATA_MASK 0xff
Francois Romieuf162a5d2008-06-01 22:37:49 +0200414};
415
françois romieuc0e45c12011-01-03 15:08:04 +0000416enum rtl8168_registers {
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800417 LED_FREQ = 0x1a,
418 EEE_LED = 0x1b,
françois romieub646d902011-01-03 15:08:21 +0000419 ERIDR = 0x70,
420 ERIAR = 0x74,
421#define ERIAR_FLAG 0x80000000
422#define ERIAR_WRITE_CMD 0x80000000
423#define ERIAR_READ_CMD 0x00000000
424#define ERIAR_ADDR_BYTE_ALIGN 4
françois romieub646d902011-01-03 15:08:21 +0000425#define ERIAR_TYPE_SHIFT 16
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800426#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT)
427#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT)
428#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT)
429#define ERIAR_MASK_SHIFT 12
430#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT)
431#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT)
Hayes Wangc5583862012-07-02 17:23:22 +0800432#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT)
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800433#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT)
françois romieuc0e45c12011-01-03 15:08:04 +0000434 EPHY_RXER_NUM = 0x7c,
435 OCPDR = 0xb0, /* OCP GPHY access */
436#define OCPDR_WRITE_CMD 0x80000000
437#define OCPDR_READ_CMD 0x00000000
438#define OCPDR_REG_MASK 0x7f
439#define OCPDR_GPHY_REG_SHIFT 16
440#define OCPDR_DATA_MASK 0xffff
441 OCPAR = 0xb4,
442#define OCPAR_FLAG 0x80000000
443#define OCPAR_GPHY_WRITE_CMD 0x8000f060
444#define OCPAR_GPHY_READ_CMD 0x0000f060
Hayes Wangc5583862012-07-02 17:23:22 +0800445 GPHY_OCP = 0xb8,
hayeswang01dc7fe2011-03-21 01:50:28 +0000446 RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */
447 MISC = 0xf0, /* 8168e only. */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200448#define TXPLA_RST (1 << 29)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800449#define DISABLE_LAN_EN (1 << 23) /* Enable GPIO pin */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800450#define PWM_EN (1 << 22)
Hayes Wangc5583862012-07-02 17:23:22 +0800451#define RXDV_GATED_EN (1 << 19)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800452#define EARLY_TALLY_EN (1 << 16)
françois romieuc0e45c12011-01-03 15:08:04 +0000453};
454
Francois Romieu07d3f512007-02-21 22:40:46 +0100455enum rtl_register_content {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 /* InterruptStatusBits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100457 SYSErr = 0x8000,
458 PCSTimeout = 0x4000,
459 SWInt = 0x0100,
460 TxDescUnavail = 0x0080,
461 RxFIFOOver = 0x0040,
462 LinkChg = 0x0020,
463 RxOverflow = 0x0010,
464 TxErr = 0x0008,
465 TxOK = 0x0004,
466 RxErr = 0x0002,
467 RxOK = 0x0001,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 /* RxStatusDesc */
David S. Miller8decf862011-09-22 03:23:13 -0400470 RxBOVF = (1 << 24),
Francois Romieu9dccf612006-05-14 12:31:17 +0200471 RxFOVF = (1 << 23),
472 RxRWT = (1 << 22),
473 RxRES = (1 << 21),
474 RxRUNT = (1 << 20),
475 RxCRC = (1 << 19),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 /* ChipCmdBits */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800478 StopReq = 0x80,
Francois Romieu07d3f512007-02-21 22:40:46 +0100479 CmdReset = 0x10,
480 CmdRxEnb = 0x08,
481 CmdTxEnb = 0x04,
482 RxBufEmpty = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
Francois Romieu275391a2007-02-23 23:50:28 +0100484 /* TXPoll register p.5 */
485 HPQ = 0x80, /* Poll cmd on the high prio queue */
486 NPQ = 0x40, /* Poll cmd on the low prio queue */
487 FSWInt = 0x01, /* Forced software interrupt */
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 /* Cfg9346Bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100490 Cfg9346_Lock = 0x00,
491 Cfg9346_Unlock = 0xc0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 /* rx_mode_bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100494 AcceptErr = 0x20,
495 AcceptRunt = 0x10,
496 AcceptBroadcast = 0x08,
497 AcceptMulticast = 0x04,
498 AcceptMyPhys = 0x02,
499 AcceptAllPhys = 0x01,
Francois Romieu1687b562011-07-19 17:21:29 +0200500#define RX_CONFIG_ACCEPT_MASK 0x3f
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 /* TxConfigBits */
503 TxInterFrameGapShift = 24,
504 TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
505
Francois Romieu5d06a992006-02-23 00:47:58 +0100506 /* Config1 register p.24 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200507 LEDS1 = (1 << 7),
508 LEDS0 = (1 << 6),
Francois Romieuf162a5d2008-06-01 22:37:49 +0200509 Speed_down = (1 << 4),
510 MEMMAP = (1 << 3),
511 IOMAP = (1 << 2),
512 VPD = (1 << 1),
Francois Romieu5d06a992006-02-23 00:47:58 +0100513 PMEnable = (1 << 0), /* Power Management Enable */
514
Francois Romieu6dccd162007-02-13 23:38:05 +0100515 /* Config2 register p. 25 */
françois romieu2ca6cf02011-12-15 08:37:43 +0000516 MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
Francois Romieu6dccd162007-02-13 23:38:05 +0100517 PCI_Clock_66MHz = 0x01,
518 PCI_Clock_33MHz = 0x00,
519
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100520 /* Config3 register p.25 */
521 MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
522 LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
Francois Romieud58d46b2011-05-03 16:38:29 +0200523 Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200524 Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100525
Francois Romieud58d46b2011-05-03 16:38:29 +0200526 /* Config4 register */
527 Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */
528
Francois Romieu5d06a992006-02-23 00:47:58 +0100529 /* Config5 register p.27 */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100530 BWF = (1 << 6), /* Accept Broadcast wakeup frame */
531 MWF = (1 << 5), /* Accept Multicast wakeup frame */
532 UWF = (1 << 4), /* Accept Unicast wakeup frame */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200533 Spi_en = (1 << 3),
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100534 LanWake = (1 << 1), /* LanWake enable/disable */
Francois Romieu5d06a992006-02-23 00:47:58 +0100535 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 /* TBICSR p.28 */
538 TBIReset = 0x80000000,
539 TBILoopback = 0x40000000,
540 TBINwEnable = 0x20000000,
541 TBINwRestart = 0x10000000,
542 TBILinkOk = 0x02000000,
543 TBINwComplete = 0x01000000,
544
545 /* CPlusCmd p.31 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200546 EnableBist = (1 << 15), // 8168 8101
547 Mac_dbgo_oe = (1 << 14), // 8168 8101
548 Normal_mode = (1 << 13), // unused
549 Force_half_dup = (1 << 12), // 8168 8101
550 Force_rxflow_en = (1 << 11), // 8168 8101
551 Force_txflow_en = (1 << 10), // 8168 8101
552 Cxpl_dbg_sel = (1 << 9), // 8168 8101
553 ASF = (1 << 8), // 8168 8101
554 PktCntrDisable = (1 << 7), // 8168 8101
555 Mac_dbgo_sel = 0x001c, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 RxVlan = (1 << 6),
557 RxChkSum = (1 << 5),
558 PCIDAC = (1 << 4),
559 PCIMulRW = (1 << 3),
Francois Romieu0e485152007-02-20 00:00:26 +0100560 INTT_0 = 0x0000, // 8168
561 INTT_1 = 0x0001, // 8168
562 INTT_2 = 0x0002, // 8168
563 INTT_3 = 0x0003, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565 /* rtl8169_PHYstatus */
Francois Romieu07d3f512007-02-21 22:40:46 +0100566 TBI_Enable = 0x80,
567 TxFlowCtrl = 0x40,
568 RxFlowCtrl = 0x20,
569 _1000bpsF = 0x10,
570 _100bps = 0x08,
571 _10bps = 0x04,
572 LinkStatus = 0x02,
573 FullDup = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 /* _TBICSRBit */
Francois Romieu07d3f512007-02-21 22:40:46 +0100576 TBILinkOK = 0x02000000,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +0200577
578 /* DumpCounterCommand */
Francois Romieu07d3f512007-02-21 22:40:46 +0100579 CounterDump = 0x8,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580};
581
Francois Romieu2b7b4312011-04-18 22:53:24 -0700582enum rtl_desc_bit {
583 /* First doubleword. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 DescOwn = (1 << 31), /* Descriptor is owned by NIC */
585 RingEnd = (1 << 30), /* End of descriptor ring */
586 FirstFrag = (1 << 29), /* First segment of a packet */
587 LastFrag = (1 << 28), /* Final segment of a packet */
Francois Romieu2b7b4312011-04-18 22:53:24 -0700588};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Francois Romieu2b7b4312011-04-18 22:53:24 -0700590/* Generic case. */
591enum rtl_tx_desc_bit {
592 /* First doubleword. */
593 TD_LSO = (1 << 27), /* Large Send Offload */
594#define TD_MSS_MAX 0x07ffu /* MSS value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Francois Romieu2b7b4312011-04-18 22:53:24 -0700596 /* Second doubleword. */
597 TxVlanTag = (1 << 17), /* Add VLAN tag */
598};
599
600/* 8169, 8168b and 810x except 8102e. */
601enum rtl_tx_desc_bit_0 {
602 /* First doubleword. */
603#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */
604 TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */
605 TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */
606 TD0_IP_CS = (1 << 18), /* Calculate IP checksum */
607};
608
609/* 8102e, 8168c and beyond. */
610enum rtl_tx_desc_bit_1 {
611 /* Second doubleword. */
612#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */
613 TD1_IP_CS = (1 << 29), /* Calculate IP checksum */
614 TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */
615 TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */
616};
617
618static const struct rtl_tx_desc_info {
619 struct {
620 u32 udp;
621 u32 tcp;
622 } checksum;
623 u16 mss_shift;
624 u16 opts_offset;
625} tx_desc_info [] = {
626 [RTL_TD_0] = {
627 .checksum = {
628 .udp = TD0_IP_CS | TD0_UDP_CS,
629 .tcp = TD0_IP_CS | TD0_TCP_CS
630 },
631 .mss_shift = TD0_MSS_SHIFT,
632 .opts_offset = 0
633 },
634 [RTL_TD_1] = {
635 .checksum = {
636 .udp = TD1_IP_CS | TD1_UDP_CS,
637 .tcp = TD1_IP_CS | TD1_TCP_CS
638 },
639 .mss_shift = TD1_MSS_SHIFT,
640 .opts_offset = 1
641 }
642};
643
644enum rtl_rx_desc_bit {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /* Rx private */
646 PID1 = (1 << 18), /* Protocol ID bit 1/2 */
647 PID0 = (1 << 17), /* Protocol ID bit 2/2 */
648
649#define RxProtoUDP (PID1)
650#define RxProtoTCP (PID0)
651#define RxProtoIP (PID1 | PID0)
652#define RxProtoMask RxProtoIP
653
654 IPFail = (1 << 16), /* IP checksum failed */
655 UDPFail = (1 << 15), /* UDP/IP checksum failed */
656 TCPFail = (1 << 14), /* TCP/IP checksum failed */
657 RxVlanTag = (1 << 16), /* VLAN tag available */
658};
659
660#define RsvdMask 0x3fffc000
661
662struct TxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200663 __le32 opts1;
664 __le32 opts2;
665 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666};
667
668struct RxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200669 __le32 opts1;
670 __le32 opts2;
671 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672};
673
674struct ring_info {
675 struct sk_buff *skb;
676 u32 len;
677 u8 __pad[sizeof(void *) - sizeof(u32)];
678};
679
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200680enum features {
Francois Romieuccdffb92008-07-26 14:26:06 +0200681 RTL_FEATURE_WOL = (1 << 0),
682 RTL_FEATURE_MSI = (1 << 1),
683 RTL_FEATURE_GMII = (1 << 2),
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200684};
685
Ivan Vecera355423d2009-02-06 21:49:57 -0800686struct rtl8169_counters {
687 __le64 tx_packets;
688 __le64 rx_packets;
689 __le64 tx_errors;
690 __le32 rx_errors;
691 __le16 rx_missed;
692 __le16 align_errors;
693 __le32 tx_one_collision;
694 __le32 tx_multi_collision;
695 __le64 rx_unicast;
696 __le64 rx_broadcast;
697 __le32 rx_multicast;
698 __le16 tx_aborted;
699 __le16 tx_underun;
700};
701
Francois Romieuda78dbf2012-01-26 14:18:23 +0100702enum rtl_flag {
Francois Romieu6c4a70c2012-01-31 10:56:44 +0100703 RTL_FLAG_TASK_ENABLED,
Francois Romieuda78dbf2012-01-26 14:18:23 +0100704 RTL_FLAG_TASK_SLOW_PENDING,
705 RTL_FLAG_TASK_RESET_PENDING,
706 RTL_FLAG_TASK_PHY_PENDING,
707 RTL_FLAG_MAX
708};
709
Junchang Wang8027aa22012-03-04 23:30:32 +0100710struct rtl8169_stats {
711 u64 packets;
712 u64 bytes;
713 struct u64_stats_sync syncp;
714};
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716struct rtl8169_private {
717 void __iomem *mmio_addr; /* memory map physical address */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200718 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000719 struct net_device *dev;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700720 struct napi_struct napi;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200721 u32 msg_enable;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700722 u16 txd_version;
723 u16 mac_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
725 u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
726 u32 dirty_rx;
727 u32 dirty_tx;
Junchang Wang8027aa22012-03-04 23:30:32 +0100728 struct rtl8169_stats rx_stats;
729 struct rtl8169_stats tx_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
731 struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
732 dma_addr_t TxPhyAddr;
733 dma_addr_t RxPhyAddr;
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000734 void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 struct timer_list timer;
737 u16 cp_cmd;
Francois Romieuda78dbf2012-01-26 14:18:23 +0100738
739 u16 event_slow;
françois romieuc0e45c12011-01-03 15:08:04 +0000740
741 struct mdio_ops {
Francois Romieu24192212012-07-06 20:19:42 +0200742 void (*write)(struct rtl8169_private *, int, int);
743 int (*read)(struct rtl8169_private *, int);
françois romieuc0e45c12011-01-03 15:08:04 +0000744 } mdio_ops;
745
françois romieu065c27c2011-01-03 15:08:12 +0000746 struct pll_power_ops {
747 void (*down)(struct rtl8169_private *);
748 void (*up)(struct rtl8169_private *);
749 } pll_power_ops;
750
Francois Romieud58d46b2011-05-03 16:38:29 +0200751 struct jumbo_ops {
752 void (*enable)(struct rtl8169_private *);
753 void (*disable)(struct rtl8169_private *);
754 } jumbo_ops;
755
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800756 struct csi_ops {
Francois Romieu52989f02012-07-06 13:37:00 +0200757 void (*write)(struct rtl8169_private *, int, int);
758 u32 (*read)(struct rtl8169_private *, int);
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800759 } csi_ops;
760
Oliver Neukum54405cd2011-01-06 21:55:13 +0100761 int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
Francois Romieuccdffb92008-07-26 14:26:06 +0200762 int (*get_settings)(struct net_device *, struct ethtool_cmd *);
françois romieu4da19632011-01-03 15:07:55 +0000763 void (*phy_reset_enable)(struct rtl8169_private *tp);
Francois Romieu07ce4062007-02-23 23:36:39 +0100764 void (*hw_start)(struct net_device *);
françois romieu4da19632011-01-03 15:07:55 +0000765 unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 unsigned int (*link_ok)(void __iomem *);
Francois Romieu8b4ab282008-11-19 22:05:25 -0800767 int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
Francois Romieu4422bcd2012-01-26 11:23:32 +0100768
769 struct {
Francois Romieuda78dbf2012-01-26 14:18:23 +0100770 DECLARE_BITMAP(flags, RTL_FLAG_MAX);
771 struct mutex mutex;
Francois Romieu4422bcd2012-01-26 11:23:32 +0100772 struct work_struct work;
773 } wk;
774
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200775 unsigned features;
Francois Romieuccdffb92008-07-26 14:26:06 +0200776
777 struct mii_if_info mii;
Ivan Vecera355423d2009-02-06 21:49:57 -0800778 struct rtl8169_counters counters;
Rafael J. Wysockie1759442010-03-14 14:33:51 +0000779 u32 saved_wolopts;
David S. Miller8decf862011-09-22 03:23:13 -0400780 u32 opts1_mask;
françois romieuf1e02ed2011-01-13 13:07:53 +0000781
Francois Romieub6ffd972011-06-17 17:00:05 +0200782 struct rtl_fw {
783 const struct firmware *fw;
Francois Romieu1c361ef2011-06-17 17:16:24 +0200784
785#define RTL_VER_SIZE 32
786
787 char version[RTL_VER_SIZE];
788
789 struct rtl_fw_phy_action {
790 __le32 *code;
791 size_t size;
792 } phy_action;
Francois Romieub6ffd972011-06-17 17:00:05 +0200793 } *rtl_fw;
Phil Carmody497888c2011-07-14 15:07:13 +0300794#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
Hayes Wangc5583862012-07-02 17:23:22 +0800795
796 u32 ocp_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797};
798
Ralf Baechle979b6c12005-06-13 14:30:40 -0700799MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801module_param(use_dac, int, 0);
David S. Miller4300e8c2010-03-26 10:23:30 -0700802MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200803module_param_named(debug, debug.msg_enable, int, 0);
804MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805MODULE_LICENSE("GPL");
806MODULE_VERSION(RTL8169_VERSION);
françois romieubca03d52011-01-03 15:07:31 +0000807MODULE_FIRMWARE(FIRMWARE_8168D_1);
808MODULE_FIRMWARE(FIRMWARE_8168D_2);
hayeswang01dc7fe2011-03-21 01:50:28 +0000809MODULE_FIRMWARE(FIRMWARE_8168E_1);
810MODULE_FIRMWARE(FIRMWARE_8168E_2);
David S. Miller8decf862011-09-22 03:23:13 -0400811MODULE_FIRMWARE(FIRMWARE_8168E_3);
Hayes Wang5a5e4442011-02-22 17:26:21 +0800812MODULE_FIRMWARE(FIRMWARE_8105E_1);
Hayes Wangc2218922011-09-06 16:55:18 +0800813MODULE_FIRMWARE(FIRMWARE_8168F_1);
814MODULE_FIRMWARE(FIRMWARE_8168F_2);
Hayes Wang7e18dca2012-03-30 14:33:02 +0800815MODULE_FIRMWARE(FIRMWARE_8402_1);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800816MODULE_FIRMWARE(FIRMWARE_8411_1);
Hayes Wang5598bfe2012-07-02 17:23:21 +0800817MODULE_FIRMWARE(FIRMWARE_8106E_1);
Hayes Wangc5583862012-07-02 17:23:22 +0800818MODULE_FIRMWARE(FIRMWARE_8168G_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Francois Romieuda78dbf2012-01-26 14:18:23 +0100820static void rtl_lock_work(struct rtl8169_private *tp)
821{
822 mutex_lock(&tp->wk.mutex);
823}
824
825static void rtl_unlock_work(struct rtl8169_private *tp)
826{
827 mutex_unlock(&tp->wk.mutex);
828}
829
Francois Romieud58d46b2011-05-03 16:38:29 +0200830static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
831{
Jiang Liu7d7903b2012-07-24 17:20:16 +0800832 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
833 PCI_EXP_DEVCTL_READRQ, force);
Francois Romieud58d46b2011-05-03 16:38:29 +0200834}
835
Francois Romieuffc46952012-07-06 14:19:23 +0200836struct rtl_cond {
837 bool (*check)(struct rtl8169_private *);
838 const char *msg;
839};
840
841static void rtl_udelay(unsigned int d)
842{
843 udelay(d);
844}
845
846static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
847 void (*delay)(unsigned int), unsigned int d, int n,
848 bool high)
849{
850 int i;
851
852 for (i = 0; i < n; i++) {
853 delay(d);
854 if (c->check(tp) == high)
855 return true;
856 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200857 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
858 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200859 return false;
860}
861
862static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
863 const struct rtl_cond *c,
864 unsigned int d, int n)
865{
866 return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
867}
868
869static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
870 const struct rtl_cond *c,
871 unsigned int d, int n)
872{
873 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
874}
875
876static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
877 const struct rtl_cond *c,
878 unsigned int d, int n)
879{
880 return rtl_loop_wait(tp, c, msleep, d, n, true);
881}
882
883static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
884 const struct rtl_cond *c,
885 unsigned int d, int n)
886{
887 return rtl_loop_wait(tp, c, msleep, d, n, false);
888}
889
890#define DECLARE_RTL_COND(name) \
891static bool name ## _check(struct rtl8169_private *); \
892 \
893static const struct rtl_cond name = { \
894 .check = name ## _check, \
895 .msg = #name \
896}; \
897 \
898static bool name ## _check(struct rtl8169_private *tp)
899
900DECLARE_RTL_COND(rtl_ocpar_cond)
901{
902 void __iomem *ioaddr = tp->mmio_addr;
903
904 return RTL_R32(OCPAR) & OCPAR_FLAG;
905}
906
françois romieub646d902011-01-03 15:08:21 +0000907static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
908{
909 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000910
911 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200912
913 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
914 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000915}
916
917static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
918{
919 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000920
921 RTL_W32(OCPDR, data);
922 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200923
924 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
925}
926
927DECLARE_RTL_COND(rtl_eriar_cond)
928{
929 void __iomem *ioaddr = tp->mmio_addr;
930
931 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000932}
933
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800934static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000935{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800936 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000937
938 RTL_W8(ERIDR, cmd);
939 RTL_W32(ERIAR, 0x800010e8);
940 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200941
942 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
943 return;
françois romieub646d902011-01-03 15:08:21 +0000944
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800945 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000946}
947
948#define OOB_CMD_RESET 0x00
949#define OOB_CMD_DRIVER_START 0x05
950#define OOB_CMD_DRIVER_STOP 0x06
951
Francois Romieucecb5fd2011-04-01 10:21:07 +0200952static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
953{
954 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
955}
956
Francois Romieuffc46952012-07-06 14:19:23 +0200957DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000958{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200959 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000960
Francois Romieucecb5fd2011-04-01 10:21:07 +0200961 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000962
Francois Romieuffc46952012-07-06 14:19:23 +0200963 return ocp_read(tp, 0x0f, reg) & 0x00000800;
964}
965
966static void rtl8168_driver_start(struct rtl8169_private *tp)
967{
968 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
969
970 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000971}
972
973static void rtl8168_driver_stop(struct rtl8169_private *tp)
974{
françois romieub646d902011-01-03 15:08:21 +0000975 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
976
Francois Romieuffc46952012-07-06 14:19:23 +0200977 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000978}
979
hayeswang4804b3b2011-03-21 01:50:29 +0000980static int r8168dp_check_dash(struct rtl8169_private *tp)
981{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200982 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000983
Francois Romieucecb5fd2011-04-01 10:21:07 +0200984 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000985}
françois romieub646d902011-01-03 15:08:21 +0000986
Hayes Wangc5583862012-07-02 17:23:22 +0800987static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
988{
989 if (reg & 0xffff0001) {
990 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
991 return true;
992 }
993 return false;
994}
995
996DECLARE_RTL_COND(rtl_ocp_gphy_cond)
997{
998 void __iomem *ioaddr = tp->mmio_addr;
999
1000 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1001}
1002
1003static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1004{
1005 void __iomem *ioaddr = tp->mmio_addr;
1006
1007 if (rtl_ocp_reg_failure(tp, reg))
1008 return;
1009
1010 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1011
1012 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1013}
1014
1015static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1016{
1017 void __iomem *ioaddr = tp->mmio_addr;
1018
1019 if (rtl_ocp_reg_failure(tp, reg))
1020 return 0;
1021
1022 RTL_W32(GPHY_OCP, reg << 15);
1023
1024 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1025 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1026}
1027
1028static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1029{
1030 int val;
1031
1032 val = r8168_phy_ocp_read(tp, reg);
1033 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1034}
1035
Hayes Wangc5583862012-07-02 17:23:22 +08001036static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1037{
1038 void __iomem *ioaddr = tp->mmio_addr;
1039
1040 if (rtl_ocp_reg_failure(tp, reg))
1041 return;
1042
1043 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001044}
1045
1046static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1047{
1048 void __iomem *ioaddr = tp->mmio_addr;
1049
1050 if (rtl_ocp_reg_failure(tp, reg))
1051 return 0;
1052
1053 RTL_W32(OCPDR, reg << 15);
1054
Hayes Wang3a83ad12012-07-11 20:31:56 +08001055 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001056}
1057
1058#define OCP_STD_PHY_BASE 0xa400
1059
1060static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1061{
1062 if (reg == 0x1f) {
1063 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1064 return;
1065 }
1066
1067 if (tp->ocp_base != OCP_STD_PHY_BASE)
1068 reg -= 0x10;
1069
1070 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1071}
1072
1073static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1074{
1075 if (tp->ocp_base != OCP_STD_PHY_BASE)
1076 reg -= 0x10;
1077
1078 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1079}
1080
Francois Romieuffc46952012-07-06 14:19:23 +02001081DECLARE_RTL_COND(rtl_phyar_cond)
1082{
1083 void __iomem *ioaddr = tp->mmio_addr;
1084
1085 return RTL_R32(PHYAR) & 0x80000000;
1086}
1087
Francois Romieu24192212012-07-06 20:19:42 +02001088static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089{
Francois Romieu24192212012-07-06 20:19:42 +02001090 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Francois Romieu24192212012-07-06 20:19:42 +02001092 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Francois Romieuffc46952012-07-06 14:19:23 +02001094 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001095 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001096 * According to hardware specs a 20us delay is required after write
1097 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001098 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001099 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100}
1101
Francois Romieu24192212012-07-06 20:19:42 +02001102static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
Francois Romieu24192212012-07-06 20:19:42 +02001104 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001105 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Francois Romieu24192212012-07-06 20:19:42 +02001107 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Francois Romieuffc46952012-07-06 14:19:23 +02001109 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1110 RTL_R32(PHYAR) & 0xffff : ~0;
1111
Timo Teräs81a95f02010-06-09 17:31:48 -07001112 /*
1113 * According to hardware specs a 20us delay is required after read
1114 * complete indication, but before sending next command.
1115 */
1116 udelay(20);
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 return value;
1119}
1120
Francois Romieu24192212012-07-06 20:19:42 +02001121static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001122{
Francois Romieu24192212012-07-06 20:19:42 +02001123 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001124
Francois Romieu24192212012-07-06 20:19:42 +02001125 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001126 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1127 RTL_W32(EPHY_RXER_NUM, 0);
1128
Francois Romieuffc46952012-07-06 14:19:23 +02001129 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001130}
1131
Francois Romieu24192212012-07-06 20:19:42 +02001132static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001133{
Francois Romieu24192212012-07-06 20:19:42 +02001134 r8168dp_1_mdio_access(tp, reg,
1135 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001136}
1137
Francois Romieu24192212012-07-06 20:19:42 +02001138static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001139{
Francois Romieu24192212012-07-06 20:19:42 +02001140 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001141
Francois Romieu24192212012-07-06 20:19:42 +02001142 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001143
1144 mdelay(1);
1145 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1146 RTL_W32(EPHY_RXER_NUM, 0);
1147
Francois Romieuffc46952012-07-06 14:19:23 +02001148 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1149 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001150}
1151
françois romieue6de30d2011-01-03 15:08:37 +00001152#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1153
1154static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1155{
1156 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1157}
1158
1159static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1160{
1161 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1162}
1163
Francois Romieu24192212012-07-06 20:19:42 +02001164static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001165{
Francois Romieu24192212012-07-06 20:19:42 +02001166 void __iomem *ioaddr = tp->mmio_addr;
1167
françois romieue6de30d2011-01-03 15:08:37 +00001168 r8168dp_2_mdio_start(ioaddr);
1169
Francois Romieu24192212012-07-06 20:19:42 +02001170 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001171
1172 r8168dp_2_mdio_stop(ioaddr);
1173}
1174
Francois Romieu24192212012-07-06 20:19:42 +02001175static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001176{
Francois Romieu24192212012-07-06 20:19:42 +02001177 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001178 int value;
1179
1180 r8168dp_2_mdio_start(ioaddr);
1181
Francois Romieu24192212012-07-06 20:19:42 +02001182 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001183
1184 r8168dp_2_mdio_stop(ioaddr);
1185
1186 return value;
1187}
1188
françois romieu4da19632011-01-03 15:07:55 +00001189static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001190{
Francois Romieu24192212012-07-06 20:19:42 +02001191 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001192}
1193
françois romieu4da19632011-01-03 15:07:55 +00001194static int rtl_readphy(struct rtl8169_private *tp, int location)
1195{
Francois Romieu24192212012-07-06 20:19:42 +02001196 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001197}
1198
1199static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1200{
1201 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1202}
1203
1204static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001205{
1206 int val;
1207
françois romieu4da19632011-01-03 15:07:55 +00001208 val = rtl_readphy(tp, reg_addr);
1209 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001210}
1211
Francois Romieuccdffb92008-07-26 14:26:06 +02001212static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1213 int val)
1214{
1215 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001216
françois romieu4da19632011-01-03 15:07:55 +00001217 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001218}
1219
1220static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1221{
1222 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001223
françois romieu4da19632011-01-03 15:07:55 +00001224 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001225}
1226
Francois Romieuffc46952012-07-06 14:19:23 +02001227DECLARE_RTL_COND(rtl_ephyar_cond)
1228{
1229 void __iomem *ioaddr = tp->mmio_addr;
1230
1231 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1232}
1233
Francois Romieufdf6fc02012-07-06 22:40:38 +02001234static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001235{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001236 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001237
1238 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1239 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1240
Francois Romieuffc46952012-07-06 14:19:23 +02001241 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1242
1243 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001244}
1245
Francois Romieufdf6fc02012-07-06 22:40:38 +02001246static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001247{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001248 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001249
1250 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1251
Francois Romieuffc46952012-07-06 14:19:23 +02001252 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1253 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001254}
1255
Francois Romieufdf6fc02012-07-06 22:40:38 +02001256static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1257 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001258{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001259 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001260
1261 BUG_ON((addr & 3) || (mask == 0));
1262 RTL_W32(ERIDR, val);
1263 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1264
Francois Romieuffc46952012-07-06 14:19:23 +02001265 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001266}
1267
Francois Romieufdf6fc02012-07-06 22:40:38 +02001268static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, 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 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1273
Francois Romieuffc46952012-07-06 14:19:23 +02001274 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1275 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001276}
1277
Francois Romieufdf6fc02012-07-06 22:40:38 +02001278static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1279 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001280{
1281 u32 val;
1282
Francois Romieufdf6fc02012-07-06 22:40:38 +02001283 val = rtl_eri_read(tp, addr, type);
1284 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001285}
1286
françois romieuc28aa382011-08-02 03:53:43 +00001287struct exgmac_reg {
1288 u16 addr;
1289 u16 mask;
1290 u32 val;
1291};
1292
Francois Romieufdf6fc02012-07-06 22:40:38 +02001293static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001294 const struct exgmac_reg *r, int len)
1295{
1296 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001297 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001298 r++;
1299 }
1300}
1301
Francois Romieuffc46952012-07-06 14:19:23 +02001302DECLARE_RTL_COND(rtl_efusear_cond)
1303{
1304 void __iomem *ioaddr = tp->mmio_addr;
1305
1306 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1307}
1308
Francois Romieufdf6fc02012-07-06 22:40:38 +02001309static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001310{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001311 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001312
1313 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1314
Francois Romieuffc46952012-07-06 14:19:23 +02001315 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1316 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001317}
1318
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001319static u16 rtl_get_events(struct rtl8169_private *tp)
1320{
1321 void __iomem *ioaddr = tp->mmio_addr;
1322
1323 return RTL_R16(IntrStatus);
1324}
1325
1326static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1327{
1328 void __iomem *ioaddr = tp->mmio_addr;
1329
1330 RTL_W16(IntrStatus, bits);
1331 mmiowb();
1332}
1333
1334static void rtl_irq_disable(struct rtl8169_private *tp)
1335{
1336 void __iomem *ioaddr = tp->mmio_addr;
1337
1338 RTL_W16(IntrMask, 0);
1339 mmiowb();
1340}
1341
Francois Romieu3e990ff2012-01-26 12:50:01 +01001342static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1343{
1344 void __iomem *ioaddr = tp->mmio_addr;
1345
1346 RTL_W16(IntrMask, bits);
1347}
1348
Francois Romieuda78dbf2012-01-26 14:18:23 +01001349#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1350#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1351#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1352
1353static void rtl_irq_enable_all(struct rtl8169_private *tp)
1354{
1355 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1356}
1357
françois romieu811fd302011-12-04 20:30:45 +00001358static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359{
françois romieu811fd302011-12-04 20:30:45 +00001360 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001362 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001363 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001364 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365}
1366
françois romieu4da19632011-01-03 15:07:55 +00001367static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368{
françois romieu4da19632011-01-03 15:07:55 +00001369 void __iomem *ioaddr = tp->mmio_addr;
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return RTL_R32(TBICSR) & TBIReset;
1372}
1373
françois romieu4da19632011-01-03 15:07:55 +00001374static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375{
françois romieu4da19632011-01-03 15:07:55 +00001376 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
1378
1379static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1380{
1381 return RTL_R32(TBICSR) & TBILinkOk;
1382}
1383
1384static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1385{
1386 return RTL_R8(PHYstatus) & LinkStatus;
1387}
1388
françois romieu4da19632011-01-03 15:07:55 +00001389static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
françois romieu4da19632011-01-03 15:07:55 +00001391 void __iomem *ioaddr = tp->mmio_addr;
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1394}
1395
françois romieu4da19632011-01-03 15:07:55 +00001396static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398 unsigned int val;
1399
françois romieu4da19632011-01-03 15:07:55 +00001400 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1401 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402}
1403
Hayes Wang70090422011-07-06 15:58:06 +08001404static void rtl_link_chg_patch(struct rtl8169_private *tp)
1405{
1406 void __iomem *ioaddr = tp->mmio_addr;
1407 struct net_device *dev = tp->dev;
1408
1409 if (!netif_running(dev))
1410 return;
1411
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001412 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1413 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001414 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001415 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1416 ERIAR_EXGMAC);
1417 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1418 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001419 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001420 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1421 ERIAR_EXGMAC);
1422 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1423 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001424 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001425 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1426 ERIAR_EXGMAC);
1427 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1428 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001429 }
1430 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001431 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001432 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001433 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001434 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001435 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1436 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1437 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001438 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1439 ERIAR_EXGMAC);
1440 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1441 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001442 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001443 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1444 ERIAR_EXGMAC);
1445 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1446 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001447 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001448 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1449 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001450 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1451 ERIAR_EXGMAC);
1452 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1453 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001454 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001455 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1456 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001457 }
Hayes Wang70090422011-07-06 15:58:06 +08001458 }
1459}
1460
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001461static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001462 struct rtl8169_private *tp,
1463 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001466 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001467 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001468 if (pm)
1469 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001471 if (net_ratelimit())
1472 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001473 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001475 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001476 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001477 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479}
1480
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001481static void rtl8169_check_link_status(struct net_device *dev,
1482 struct rtl8169_private *tp,
1483 void __iomem *ioaddr)
1484{
1485 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1486}
1487
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001488#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1489
1490static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1491{
1492 void __iomem *ioaddr = tp->mmio_addr;
1493 u8 options;
1494 u32 wolopts = 0;
1495
1496 options = RTL_R8(Config1);
1497 if (!(options & PMEnable))
1498 return 0;
1499
1500 options = RTL_R8(Config3);
1501 if (options & LinkUp)
1502 wolopts |= WAKE_PHY;
1503 if (options & MagicPacket)
1504 wolopts |= WAKE_MAGIC;
1505
1506 options = RTL_R8(Config5);
1507 if (options & UWF)
1508 wolopts |= WAKE_UCAST;
1509 if (options & BWF)
1510 wolopts |= WAKE_BCAST;
1511 if (options & MWF)
1512 wolopts |= WAKE_MCAST;
1513
1514 return wolopts;
1515}
1516
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001517static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1518{
1519 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001520
Francois Romieuda78dbf2012-01-26 14:18:23 +01001521 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001522
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001523 wol->supported = WAKE_ANY;
1524 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001525
Francois Romieuda78dbf2012-01-26 14:18:23 +01001526 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001527}
1528
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001529static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001530{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001531 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001532 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001533 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001534 u32 opt;
1535 u16 reg;
1536 u8 mask;
1537 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001538 { WAKE_PHY, Config3, LinkUp },
1539 { WAKE_MAGIC, Config3, MagicPacket },
1540 { WAKE_UCAST, Config5, UWF },
1541 { WAKE_BCAST, Config5, BWF },
1542 { WAKE_MCAST, Config5, MWF },
1543 { WAKE_ANY, Config5, LanWake }
1544 };
Francois Romieu851e6022012-04-17 11:10:11 +02001545 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001546
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001547 RTL_W8(Cfg9346, Cfg9346_Unlock);
1548
1549 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001550 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001551 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001552 options |= cfg[i].mask;
1553 RTL_W8(cfg[i].reg, options);
1554 }
1555
Francois Romieu851e6022012-04-17 11:10:11 +02001556 switch (tp->mac_version) {
1557 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1558 options = RTL_R8(Config1) & ~PMEnable;
1559 if (wolopts)
1560 options |= PMEnable;
1561 RTL_W8(Config1, options);
1562 break;
1563 default:
Francois Romieud387b422012-04-17 11:12:01 +02001564 options = RTL_R8(Config2) & ~PME_SIGNAL;
1565 if (wolopts)
1566 options |= PME_SIGNAL;
1567 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001568 break;
1569 }
1570
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001571 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001572}
1573
1574static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1575{
1576 struct rtl8169_private *tp = netdev_priv(dev);
1577
Francois Romieuda78dbf2012-01-26 14:18:23 +01001578 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001579
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001580 if (wol->wolopts)
1581 tp->features |= RTL_FEATURE_WOL;
1582 else
1583 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001584 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001585
1586 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001587
françois romieuea809072010-11-08 13:23:58 +00001588 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1589
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001590 return 0;
1591}
1592
Francois Romieu31bd2042011-04-26 18:58:59 +02001593static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1594{
Francois Romieu85bffe62011-04-27 08:22:39 +02001595 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001596}
1597
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598static void rtl8169_get_drvinfo(struct net_device *dev,
1599 struct ethtool_drvinfo *info)
1600{
1601 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001602 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
Rick Jones68aad782011-11-07 13:29:27 +00001604 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1605 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1606 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001607 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001608 if (!IS_ERR_OR_NULL(rtl_fw))
1609 strlcpy(info->fw_version, rtl_fw->version,
1610 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
1613static int rtl8169_get_regs_len(struct net_device *dev)
1614{
1615 return R8169_REGS_SIZE;
1616}
1617
1618static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001619 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
1621 struct rtl8169_private *tp = netdev_priv(dev);
1622 void __iomem *ioaddr = tp->mmio_addr;
1623 int ret = 0;
1624 u32 reg;
1625
1626 reg = RTL_R32(TBICSR);
1627 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1628 (duplex == DUPLEX_FULL)) {
1629 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1630 } else if (autoneg == AUTONEG_ENABLE)
1631 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1632 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001633 netif_warn(tp, link, dev,
1634 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 ret = -EOPNOTSUPP;
1636 }
1637
1638 return ret;
1639}
1640
1641static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001642 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643{
1644 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001645 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001646 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Hayes Wang716b50a2011-02-22 17:26:18 +08001648 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001651 int auto_nego;
1652
françois romieu4da19632011-01-03 15:07:55 +00001653 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001654 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1655 ADVERTISE_100HALF | ADVERTISE_100FULL);
1656
1657 if (adv & ADVERTISED_10baseT_Half)
1658 auto_nego |= ADVERTISE_10HALF;
1659 if (adv & ADVERTISED_10baseT_Full)
1660 auto_nego |= ADVERTISE_10FULL;
1661 if (adv & ADVERTISED_100baseT_Half)
1662 auto_nego |= ADVERTISE_100HALF;
1663 if (adv & ADVERTISED_100baseT_Full)
1664 auto_nego |= ADVERTISE_100FULL;
1665
françois romieu3577aa12009-05-19 10:46:48 +00001666 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1667
françois romieu4da19632011-01-03 15:07:55 +00001668 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001669 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1670
1671 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001672 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001673 if (adv & ADVERTISED_1000baseT_Half)
1674 giga_ctrl |= ADVERTISE_1000HALF;
1675 if (adv & ADVERTISED_1000baseT_Full)
1676 giga_ctrl |= ADVERTISE_1000FULL;
1677 } else if (adv & (ADVERTISED_1000baseT_Half |
1678 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001679 netif_info(tp, link, dev,
1680 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001681 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
françois romieu3577aa12009-05-19 10:46:48 +00001684 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001685
françois romieu4da19632011-01-03 15:07:55 +00001686 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1687 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001688 } else {
1689 giga_ctrl = 0;
1690
1691 if (speed == SPEED_10)
1692 bmcr = 0;
1693 else if (speed == SPEED_100)
1694 bmcr = BMCR_SPEED100;
1695 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001696 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001697
1698 if (duplex == DUPLEX_FULL)
1699 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001700 }
1701
françois romieu4da19632011-01-03 15:07:55 +00001702 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001703
Francois Romieucecb5fd2011-04-01 10:21:07 +02001704 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1705 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001706 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001707 rtl_writephy(tp, 0x17, 0x2138);
1708 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001709 } else {
françois romieu4da19632011-01-03 15:07:55 +00001710 rtl_writephy(tp, 0x17, 0x2108);
1711 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001712 }
1713 }
1714
Oliver Neukum54405cd2011-01-06 21:55:13 +01001715 rc = 0;
1716out:
1717 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718}
1719
1720static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001721 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722{
1723 struct rtl8169_private *tp = netdev_priv(dev);
1724 int ret;
1725
Oliver Neukum54405cd2011-01-06 21:55:13 +01001726 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001727 if (ret < 0)
1728 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Francois Romieu4876cc12011-03-11 21:07:11 +01001730 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1731 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001733 }
1734out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 return ret;
1736}
1737
1738static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1739{
1740 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 int ret;
1742
Francois Romieu4876cc12011-03-11 21:07:11 +01001743 del_timer_sync(&tp->timer);
1744
Francois Romieuda78dbf2012-01-26 14:18:23 +01001745 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001746 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001747 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001748 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 return ret;
1751}
1752
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001753static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1754 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
Francois Romieud58d46b2011-05-03 16:38:29 +02001756 struct rtl8169_private *tp = netdev_priv(dev);
1757
Francois Romieu2b7b4312011-04-18 22:53:24 -07001758 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001759 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
Francois Romieud58d46b2011-05-03 16:38:29 +02001761 if (dev->mtu > JUMBO_1K &&
1762 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1763 features &= ~NETIF_F_IP_CSUM;
1764
Michał Mirosław350fb322011-04-08 06:35:56 +00001765 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766}
1767
Francois Romieuda78dbf2012-01-26 14:18:23 +01001768static void __rtl8169_set_features(struct net_device *dev,
1769 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770{
1771 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001772 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001773 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Ben Greear6bbe0212012-02-10 15:04:33 +00001775 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1776 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Ben Greear6bbe0212012-02-10 15:04:33 +00001778 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1779 if (features & NETIF_F_RXCSUM)
1780 tp->cp_cmd |= RxChkSum;
1781 else
1782 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001783
Ben Greear6bbe0212012-02-10 15:04:33 +00001784 if (dev->features & NETIF_F_HW_VLAN_RX)
1785 tp->cp_cmd |= RxVlan;
1786 else
1787 tp->cp_cmd &= ~RxVlan;
1788
1789 RTL_W16(CPlusCmd, tp->cp_cmd);
1790 RTL_R16(CPlusCmd);
1791 }
1792 if (changed & NETIF_F_RXALL) {
1793 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1794 if (features & NETIF_F_RXALL)
1795 tmp |= (AcceptErr | AcceptRunt);
1796 RTL_W32(RxConfig, tmp);
1797 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001798}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Francois Romieuda78dbf2012-01-26 14:18:23 +01001800static int rtl8169_set_features(struct net_device *dev,
1801 netdev_features_t features)
1802{
1803 struct rtl8169_private *tp = netdev_priv(dev);
1804
1805 rtl_lock_work(tp);
1806 __rtl8169_set_features(dev, features);
1807 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809 return 0;
1810}
1811
Francois Romieuda78dbf2012-01-26 14:18:23 +01001812
Kirill Smelkov810f4892012-11-10 21:11:02 +04001813static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814{
Jesse Grosseab6d182010-10-20 13:56:03 +00001815 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1817}
1818
Francois Romieu7a8fc772011-03-01 17:18:33 +01001819static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820{
1821 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
Francois Romieu7a8fc772011-03-01 17:18:33 +01001823 if (opts2 & RxVlanTag)
1824 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825}
1826
Francois Romieuccdffb92008-07-26 14:26:06 +02001827static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
1829 struct rtl8169_private *tp = netdev_priv(dev);
1830 void __iomem *ioaddr = tp->mmio_addr;
1831 u32 status;
1832
1833 cmd->supported =
1834 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1835 cmd->port = PORT_FIBRE;
1836 cmd->transceiver = XCVR_INTERNAL;
1837
1838 status = RTL_R32(TBICSR);
1839 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1840 cmd->autoneg = !!(status & TBINwEnable);
1841
David Decotigny70739492011-04-27 18:32:40 +00001842 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001844
1845 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846}
1847
Francois Romieuccdffb92008-07-26 14:26:06 +02001848static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
1850 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Francois Romieuccdffb92008-07-26 14:26:06 +02001852 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
1855static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1856{
1857 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001858 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
Francois Romieuda78dbf2012-01-26 14:18:23 +01001860 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001861 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001862 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
Francois Romieuccdffb92008-07-26 14:26:06 +02001864 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865}
1866
1867static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1868 void *p)
1869{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001870 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Francois Romieu5b0384f2006-08-16 16:00:01 +02001872 if (regs->len > R8169_REGS_SIZE)
1873 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Francois Romieuda78dbf2012-01-26 14:18:23 +01001875 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001876 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001877 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878}
1879
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001880static u32 rtl8169_get_msglevel(struct net_device *dev)
1881{
1882 struct rtl8169_private *tp = netdev_priv(dev);
1883
1884 return tp->msg_enable;
1885}
1886
1887static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1888{
1889 struct rtl8169_private *tp = netdev_priv(dev);
1890
1891 tp->msg_enable = value;
1892}
1893
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001894static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1895 "tx_packets",
1896 "rx_packets",
1897 "tx_errors",
1898 "rx_errors",
1899 "rx_missed",
1900 "align_errors",
1901 "tx_single_collisions",
1902 "tx_multi_collisions",
1903 "unicast",
1904 "broadcast",
1905 "multicast",
1906 "tx_aborted",
1907 "tx_underrun",
1908};
1909
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001910static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001911{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001912 switch (sset) {
1913 case ETH_SS_STATS:
1914 return ARRAY_SIZE(rtl8169_gstrings);
1915 default:
1916 return -EOPNOTSUPP;
1917 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001918}
1919
Francois Romieuffc46952012-07-06 14:19:23 +02001920DECLARE_RTL_COND(rtl_counters_cond)
1921{
1922 void __iomem *ioaddr = tp->mmio_addr;
1923
1924 return RTL_R32(CounterAddrLow) & CounterDump;
1925}
1926
Ivan Vecera355423d2009-02-06 21:49:57 -08001927static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001928{
1929 struct rtl8169_private *tp = netdev_priv(dev);
1930 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001931 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001932 struct rtl8169_counters *counters;
1933 dma_addr_t paddr;
1934 u32 cmd;
1935
Ivan Vecera355423d2009-02-06 21:49:57 -08001936 /*
1937 * Some chips are unable to dump tally counters when the receiver
1938 * is disabled.
1939 */
1940 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1941 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001942
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001943 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001944 if (!counters)
1945 return;
1946
1947 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001948 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001949 RTL_W32(CounterAddrLow, cmd);
1950 RTL_W32(CounterAddrLow, cmd | CounterDump);
1951
Francois Romieuffc46952012-07-06 14:19:23 +02001952 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1953 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001954
1955 RTL_W32(CounterAddrLow, 0);
1956 RTL_W32(CounterAddrHigh, 0);
1957
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001958 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001959}
1960
Ivan Vecera355423d2009-02-06 21:49:57 -08001961static void rtl8169_get_ethtool_stats(struct net_device *dev,
1962 struct ethtool_stats *stats, u64 *data)
1963{
1964 struct rtl8169_private *tp = netdev_priv(dev);
1965
1966 ASSERT_RTNL();
1967
1968 rtl8169_update_counters(dev);
1969
1970 data[0] = le64_to_cpu(tp->counters.tx_packets);
1971 data[1] = le64_to_cpu(tp->counters.rx_packets);
1972 data[2] = le64_to_cpu(tp->counters.tx_errors);
1973 data[3] = le32_to_cpu(tp->counters.rx_errors);
1974 data[4] = le16_to_cpu(tp->counters.rx_missed);
1975 data[5] = le16_to_cpu(tp->counters.align_errors);
1976 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1977 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1978 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1979 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1980 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1981 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1982 data[12] = le16_to_cpu(tp->counters.tx_underun);
1983}
1984
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001985static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
1986{
1987 switch(stringset) {
1988 case ETH_SS_STATS:
1989 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
1990 break;
1991 }
1992}
1993
Jeff Garzik7282d492006-09-13 14:30:00 -04001994static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 .get_drvinfo = rtl8169_get_drvinfo,
1996 .get_regs_len = rtl8169_get_regs_len,
1997 .get_link = ethtool_op_get_link,
1998 .get_settings = rtl8169_get_settings,
1999 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002000 .get_msglevel = rtl8169_get_msglevel,
2001 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002003 .get_wol = rtl8169_get_wol,
2004 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002005 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002006 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002007 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002008 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009};
2010
Francois Romieu07d3f512007-02-21 22:40:46 +01002011static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002012 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
Francois Romieu5d320a22011-05-08 17:47:36 +02002014 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002015 /*
2016 * The driver currently handles the 8168Bf and the 8168Be identically
2017 * but they can be identified more specifically through the test below
2018 * if needed:
2019 *
2020 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002021 *
2022 * Same thing for the 8101Eb and the 8101Ec:
2023 *
2024 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002025 */
Francois Romieu37441002011-06-17 22:58:54 +02002026 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002028 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 int mac_version;
2030 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002031 /* 8168G family. */
2032 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2033 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2034
Hayes Wangc2218922011-09-06 16:55:18 +08002035 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002036 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002037 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2038 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2039
hayeswang01dc7fe2011-03-21 01:50:28 +00002040 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002041 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002042 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2043 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2044 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2045
Francois Romieu5b538df2008-07-20 16:22:45 +02002046 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002047 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2048 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002049 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002050
françois romieue6de30d2011-01-03 15:08:37 +00002051 /* 8168DP family. */
2052 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2053 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002054 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002055
Francois Romieuef808d52008-06-29 13:10:54 +02002056 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002057 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002058 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002059 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002060 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002061 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2062 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002063 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002064 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002065 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002066
2067 /* 8168B family. */
2068 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2069 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2070 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2071 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2072
2073 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002074 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2075 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002076 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002077 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002078 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2079 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2080 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002081 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2082 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2083 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2084 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2085 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2086 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002087 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002088 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002089 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002090 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2091 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002092 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2093 /* FIXME: where did these entries come from ? -- FR */
2094 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2095 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2096
2097 /* 8110 family. */
2098 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2099 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2100 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2101 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2102 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2103 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2104
Jean Delvaref21b75e2009-05-26 20:54:48 -07002105 /* Catch-all */
2106 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002107 };
2108 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 u32 reg;
2110
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002111 reg = RTL_R32(TxConfig);
2112 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 p++;
2114 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002115
2116 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2117 netif_notice(tp, probe, dev,
2118 "unknown MAC, using family default\n");
2119 tp->mac_version = default_version;
2120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121}
2122
2123static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2124{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002125 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126}
2127
Francois Romieu867763c2007-08-17 18:21:58 +02002128struct phy_reg {
2129 u16 reg;
2130 u16 val;
2131};
2132
françois romieu4da19632011-01-03 15:07:55 +00002133static void rtl_writephy_batch(struct rtl8169_private *tp,
2134 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002135{
2136 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002137 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002138 regs++;
2139 }
2140}
2141
françois romieubca03d52011-01-03 15:07:31 +00002142#define PHY_READ 0x00000000
2143#define PHY_DATA_OR 0x10000000
2144#define PHY_DATA_AND 0x20000000
2145#define PHY_BJMPN 0x30000000
2146#define PHY_READ_EFUSE 0x40000000
2147#define PHY_READ_MAC_BYTE 0x50000000
2148#define PHY_WRITE_MAC_BYTE 0x60000000
2149#define PHY_CLEAR_READCOUNT 0x70000000
2150#define PHY_WRITE 0x80000000
2151#define PHY_READCOUNT_EQ_SKIP 0x90000000
2152#define PHY_COMP_EQ_SKIPN 0xa0000000
2153#define PHY_COMP_NEQ_SKIPN 0xb0000000
2154#define PHY_WRITE_PREVIOUS 0xc0000000
2155#define PHY_SKIPN 0xd0000000
2156#define PHY_DELAY_MS 0xe0000000
2157#define PHY_WRITE_ERI_WORD 0xf0000000
2158
Hayes Wang960aee62011-06-18 11:37:48 +02002159struct fw_info {
2160 u32 magic;
2161 char version[RTL_VER_SIZE];
2162 __le32 fw_start;
2163 __le32 fw_len;
2164 u8 chksum;
2165} __packed;
2166
Francois Romieu1c361ef2011-06-17 17:16:24 +02002167#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2168
2169static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002170{
Francois Romieub6ffd972011-06-17 17:00:05 +02002171 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002172 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002173 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2174 char *version = rtl_fw->version;
2175 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002176
Francois Romieu1c361ef2011-06-17 17:16:24 +02002177 if (fw->size < FW_OPCODE_SIZE)
2178 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002179
2180 if (!fw_info->magic) {
2181 size_t i, size, start;
2182 u8 checksum = 0;
2183
2184 if (fw->size < sizeof(*fw_info))
2185 goto out;
2186
2187 for (i = 0; i < fw->size; i++)
2188 checksum += fw->data[i];
2189 if (checksum != 0)
2190 goto out;
2191
2192 start = le32_to_cpu(fw_info->fw_start);
2193 if (start > fw->size)
2194 goto out;
2195
2196 size = le32_to_cpu(fw_info->fw_len);
2197 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2198 goto out;
2199
2200 memcpy(version, fw_info->version, RTL_VER_SIZE);
2201
2202 pa->code = (__le32 *)(fw->data + start);
2203 pa->size = size;
2204 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002205 if (fw->size % FW_OPCODE_SIZE)
2206 goto out;
2207
2208 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2209
2210 pa->code = (__le32 *)fw->data;
2211 pa->size = fw->size / FW_OPCODE_SIZE;
2212 }
2213 version[RTL_VER_SIZE - 1] = 0;
2214
2215 rc = true;
2216out:
2217 return rc;
2218}
2219
Francois Romieufd112f22011-06-18 00:10:29 +02002220static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2221 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002222{
Francois Romieufd112f22011-06-18 00:10:29 +02002223 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002224 size_t index;
2225
Francois Romieu1c361ef2011-06-17 17:16:24 +02002226 for (index = 0; index < pa->size; index++) {
2227 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002228 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002229
hayeswang42b82dc2011-01-10 02:07:25 +00002230 switch(action & 0xf0000000) {
2231 case PHY_READ:
2232 case PHY_DATA_OR:
2233 case PHY_DATA_AND:
2234 case PHY_READ_EFUSE:
2235 case PHY_CLEAR_READCOUNT:
2236 case PHY_WRITE:
2237 case PHY_WRITE_PREVIOUS:
2238 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002239 break;
2240
hayeswang42b82dc2011-01-10 02:07:25 +00002241 case PHY_BJMPN:
2242 if (regno > index) {
Francois Romieufd112f22011-06-18 00:10:29 +02002243 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002244 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002245 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002246 }
2247 break;
2248 case PHY_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002249 if (index + 2 >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002250 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002251 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002252 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002253 }
2254 break;
2255 case PHY_COMP_EQ_SKIPN:
2256 case PHY_COMP_NEQ_SKIPN:
2257 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002258 if (index + 1 + regno >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002259 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002260 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002261 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002262 }
2263 break;
2264
2265 case PHY_READ_MAC_BYTE:
2266 case PHY_WRITE_MAC_BYTE:
2267 case PHY_WRITE_ERI_WORD:
2268 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002269 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002270 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002271 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002272 }
2273 }
Francois Romieufd112f22011-06-18 00:10:29 +02002274 rc = true;
2275out:
2276 return rc;
2277}
françois romieubca03d52011-01-03 15:07:31 +00002278
Francois Romieufd112f22011-06-18 00:10:29 +02002279static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2280{
2281 struct net_device *dev = tp->dev;
2282 int rc = -EINVAL;
2283
2284 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2285 netif_err(tp, ifup, dev, "invalid firwmare\n");
2286 goto out;
2287 }
2288
2289 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2290 rc = 0;
2291out:
2292 return rc;
2293}
2294
2295static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2296{
2297 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2298 u32 predata, count;
2299 size_t index;
2300
2301 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002302
Francois Romieu1c361ef2011-06-17 17:16:24 +02002303 for (index = 0; index < pa->size; ) {
2304 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002305 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002306 u32 regno = (action & 0x0fff0000) >> 16;
2307
2308 if (!action)
2309 break;
françois romieubca03d52011-01-03 15:07:31 +00002310
2311 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002312 case PHY_READ:
2313 predata = rtl_readphy(tp, regno);
2314 count++;
2315 index++;
françois romieubca03d52011-01-03 15:07:31 +00002316 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002317 case PHY_DATA_OR:
2318 predata |= data;
2319 index++;
2320 break;
2321 case PHY_DATA_AND:
2322 predata &= data;
2323 index++;
2324 break;
2325 case PHY_BJMPN:
2326 index -= regno;
2327 break;
2328 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002329 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002330 index++;
2331 break;
2332 case PHY_CLEAR_READCOUNT:
2333 count = 0;
2334 index++;
2335 break;
2336 case PHY_WRITE:
2337 rtl_writephy(tp, regno, data);
2338 index++;
2339 break;
2340 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002341 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002342 break;
2343 case PHY_COMP_EQ_SKIPN:
2344 if (predata == data)
2345 index += regno;
2346 index++;
2347 break;
2348 case PHY_COMP_NEQ_SKIPN:
2349 if (predata != data)
2350 index += regno;
2351 index++;
2352 break;
2353 case PHY_WRITE_PREVIOUS:
2354 rtl_writephy(tp, regno, predata);
2355 index++;
2356 break;
2357 case PHY_SKIPN:
2358 index += regno + 1;
2359 break;
2360 case PHY_DELAY_MS:
2361 mdelay(data);
2362 index++;
2363 break;
2364
2365 case PHY_READ_MAC_BYTE:
2366 case PHY_WRITE_MAC_BYTE:
2367 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002368 default:
2369 BUG();
2370 }
2371 }
2372}
2373
françois romieuf1e02ed2011-01-13 13:07:53 +00002374static void rtl_release_firmware(struct rtl8169_private *tp)
2375{
Francois Romieub6ffd972011-06-17 17:00:05 +02002376 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2377 release_firmware(tp->rtl_fw->fw);
2378 kfree(tp->rtl_fw);
2379 }
2380 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002381}
2382
François Romieu953a12c2011-04-24 17:38:48 +02002383static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002384{
Francois Romieub6ffd972011-06-17 17:00:05 +02002385 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002386
2387 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
Francois Romieueef63cc2013-02-08 23:43:20 +01002388 if (!IS_ERR_OR_NULL(rtl_fw))
Francois Romieub6ffd972011-06-17 17:00:05 +02002389 rtl_phy_write_fw(tp, rtl_fw);
François Romieu953a12c2011-04-24 17:38:48 +02002390}
2391
2392static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2393{
2394 if (rtl_readphy(tp, reg) != val)
2395 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2396 else
2397 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002398}
2399
françois romieu4da19632011-01-03 15:07:55 +00002400static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002402 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002403 { 0x1f, 0x0001 },
2404 { 0x06, 0x006e },
2405 { 0x08, 0x0708 },
2406 { 0x15, 0x4000 },
2407 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
françois romieu0b9b5712009-08-10 19:44:56 +00002409 { 0x1f, 0x0001 },
2410 { 0x03, 0x00a1 },
2411 { 0x02, 0x0008 },
2412 { 0x01, 0x0120 },
2413 { 0x00, 0x1000 },
2414 { 0x04, 0x0800 },
2415 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416
françois romieu0b9b5712009-08-10 19:44:56 +00002417 { 0x03, 0xff41 },
2418 { 0x02, 0xdf60 },
2419 { 0x01, 0x0140 },
2420 { 0x00, 0x0077 },
2421 { 0x04, 0x7800 },
2422 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
françois romieu0b9b5712009-08-10 19:44:56 +00002424 { 0x03, 0x802f },
2425 { 0x02, 0x4f02 },
2426 { 0x01, 0x0409 },
2427 { 0x00, 0xf0f9 },
2428 { 0x04, 0x9800 },
2429 { 0x04, 0x9000 },
2430
2431 { 0x03, 0xdf01 },
2432 { 0x02, 0xdf20 },
2433 { 0x01, 0xff95 },
2434 { 0x00, 0xba00 },
2435 { 0x04, 0xa800 },
2436 { 0x04, 0xa000 },
2437
2438 { 0x03, 0xff41 },
2439 { 0x02, 0xdf20 },
2440 { 0x01, 0x0140 },
2441 { 0x00, 0x00bb },
2442 { 0x04, 0xb800 },
2443 { 0x04, 0xb000 },
2444
2445 { 0x03, 0xdf41 },
2446 { 0x02, 0xdc60 },
2447 { 0x01, 0x6340 },
2448 { 0x00, 0x007d },
2449 { 0x04, 0xd800 },
2450 { 0x04, 0xd000 },
2451
2452 { 0x03, 0xdf01 },
2453 { 0x02, 0xdf20 },
2454 { 0x01, 0x100a },
2455 { 0x00, 0xa0ff },
2456 { 0x04, 0xf800 },
2457 { 0x04, 0xf000 },
2458
2459 { 0x1f, 0x0000 },
2460 { 0x0b, 0x0000 },
2461 { 0x00, 0x9200 }
2462 };
2463
françois romieu4da19632011-01-03 15:07:55 +00002464 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465}
2466
françois romieu4da19632011-01-03 15:07:55 +00002467static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002468{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002469 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002470 { 0x1f, 0x0002 },
2471 { 0x01, 0x90d0 },
2472 { 0x1f, 0x0000 }
2473 };
2474
françois romieu4da19632011-01-03 15:07:55 +00002475 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002476}
2477
françois romieu4da19632011-01-03 15:07:55 +00002478static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002479{
2480 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002481
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002482 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2483 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002484 return;
2485
françois romieu4da19632011-01-03 15:07:55 +00002486 rtl_writephy(tp, 0x1f, 0x0001);
2487 rtl_writephy(tp, 0x10, 0xf01b);
2488 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002489}
2490
françois romieu4da19632011-01-03 15:07:55 +00002491static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002492{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002493 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002494 { 0x1f, 0x0001 },
2495 { 0x04, 0x0000 },
2496 { 0x03, 0x00a1 },
2497 { 0x02, 0x0008 },
2498 { 0x01, 0x0120 },
2499 { 0x00, 0x1000 },
2500 { 0x04, 0x0800 },
2501 { 0x04, 0x9000 },
2502 { 0x03, 0x802f },
2503 { 0x02, 0x4f02 },
2504 { 0x01, 0x0409 },
2505 { 0x00, 0xf099 },
2506 { 0x04, 0x9800 },
2507 { 0x04, 0xa000 },
2508 { 0x03, 0xdf01 },
2509 { 0x02, 0xdf20 },
2510 { 0x01, 0xff95 },
2511 { 0x00, 0xba00 },
2512 { 0x04, 0xa800 },
2513 { 0x04, 0xf000 },
2514 { 0x03, 0xdf01 },
2515 { 0x02, 0xdf20 },
2516 { 0x01, 0x101a },
2517 { 0x00, 0xa0ff },
2518 { 0x04, 0xf800 },
2519 { 0x04, 0x0000 },
2520 { 0x1f, 0x0000 },
2521
2522 { 0x1f, 0x0001 },
2523 { 0x10, 0xf41b },
2524 { 0x14, 0xfb54 },
2525 { 0x18, 0xf5c7 },
2526 { 0x1f, 0x0000 },
2527
2528 { 0x1f, 0x0001 },
2529 { 0x17, 0x0cc0 },
2530 { 0x1f, 0x0000 }
2531 };
2532
françois romieu4da19632011-01-03 15:07:55 +00002533 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002534
françois romieu4da19632011-01-03 15:07:55 +00002535 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002536}
2537
françois romieu4da19632011-01-03 15:07:55 +00002538static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002539{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002540 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002541 { 0x1f, 0x0001 },
2542 { 0x04, 0x0000 },
2543 { 0x03, 0x00a1 },
2544 { 0x02, 0x0008 },
2545 { 0x01, 0x0120 },
2546 { 0x00, 0x1000 },
2547 { 0x04, 0x0800 },
2548 { 0x04, 0x9000 },
2549 { 0x03, 0x802f },
2550 { 0x02, 0x4f02 },
2551 { 0x01, 0x0409 },
2552 { 0x00, 0xf099 },
2553 { 0x04, 0x9800 },
2554 { 0x04, 0xa000 },
2555 { 0x03, 0xdf01 },
2556 { 0x02, 0xdf20 },
2557 { 0x01, 0xff95 },
2558 { 0x00, 0xba00 },
2559 { 0x04, 0xa800 },
2560 { 0x04, 0xf000 },
2561 { 0x03, 0xdf01 },
2562 { 0x02, 0xdf20 },
2563 { 0x01, 0x101a },
2564 { 0x00, 0xa0ff },
2565 { 0x04, 0xf800 },
2566 { 0x04, 0x0000 },
2567 { 0x1f, 0x0000 },
2568
2569 { 0x1f, 0x0001 },
2570 { 0x0b, 0x8480 },
2571 { 0x1f, 0x0000 },
2572
2573 { 0x1f, 0x0001 },
2574 { 0x18, 0x67c7 },
2575 { 0x04, 0x2000 },
2576 { 0x03, 0x002f },
2577 { 0x02, 0x4360 },
2578 { 0x01, 0x0109 },
2579 { 0x00, 0x3022 },
2580 { 0x04, 0x2800 },
2581 { 0x1f, 0x0000 },
2582
2583 { 0x1f, 0x0001 },
2584 { 0x17, 0x0cc0 },
2585 { 0x1f, 0x0000 }
2586 };
2587
françois romieu4da19632011-01-03 15:07:55 +00002588 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002589}
2590
françois romieu4da19632011-01-03 15:07:55 +00002591static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002592{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002593 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002594 { 0x10, 0xf41b },
2595 { 0x1f, 0x0000 }
2596 };
2597
françois romieu4da19632011-01-03 15:07:55 +00002598 rtl_writephy(tp, 0x1f, 0x0001);
2599 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002600
françois romieu4da19632011-01-03 15:07:55 +00002601 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002602}
2603
françois romieu4da19632011-01-03 15:07:55 +00002604static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002605{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002606 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002607 { 0x1f, 0x0001 },
2608 { 0x10, 0xf41b },
2609 { 0x1f, 0x0000 }
2610 };
2611
françois romieu4da19632011-01-03 15:07:55 +00002612 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002613}
2614
françois romieu4da19632011-01-03 15:07:55 +00002615static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002616{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002617 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002618 { 0x1f, 0x0000 },
2619 { 0x1d, 0x0f00 },
2620 { 0x1f, 0x0002 },
2621 { 0x0c, 0x1ec8 },
2622 { 0x1f, 0x0000 }
2623 };
2624
françois romieu4da19632011-01-03 15:07:55 +00002625 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002626}
2627
françois romieu4da19632011-01-03 15:07:55 +00002628static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002629{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002630 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002631 { 0x1f, 0x0001 },
2632 { 0x1d, 0x3d98 },
2633 { 0x1f, 0x0000 }
2634 };
2635
françois romieu4da19632011-01-03 15:07:55 +00002636 rtl_writephy(tp, 0x1f, 0x0000);
2637 rtl_patchphy(tp, 0x14, 1 << 5);
2638 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002639
françois romieu4da19632011-01-03 15:07:55 +00002640 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002641}
2642
françois romieu4da19632011-01-03 15:07:55 +00002643static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002644{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002645 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002646 { 0x1f, 0x0001 },
2647 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002648 { 0x1f, 0x0002 },
2649 { 0x00, 0x88d4 },
2650 { 0x01, 0x82b1 },
2651 { 0x03, 0x7002 },
2652 { 0x08, 0x9e30 },
2653 { 0x09, 0x01f0 },
2654 { 0x0a, 0x5500 },
2655 { 0x0c, 0x00c8 },
2656 { 0x1f, 0x0003 },
2657 { 0x12, 0xc096 },
2658 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002659 { 0x1f, 0x0000 },
2660 { 0x1f, 0x0000 },
2661 { 0x09, 0x2000 },
2662 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002663 };
2664
françois romieu4da19632011-01-03 15:07:55 +00002665 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002666
françois romieu4da19632011-01-03 15:07:55 +00002667 rtl_patchphy(tp, 0x14, 1 << 5);
2668 rtl_patchphy(tp, 0x0d, 1 << 5);
2669 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002670}
2671
françois romieu4da19632011-01-03 15:07:55 +00002672static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002673{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002674 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002675 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002676 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002677 { 0x03, 0x802f },
2678 { 0x02, 0x4f02 },
2679 { 0x01, 0x0409 },
2680 { 0x00, 0xf099 },
2681 { 0x04, 0x9800 },
2682 { 0x04, 0x9000 },
2683 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002684 { 0x1f, 0x0002 },
2685 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002686 { 0x06, 0x0761 },
2687 { 0x1f, 0x0003 },
2688 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002689 { 0x1f, 0x0000 }
2690 };
2691
françois romieu4da19632011-01-03 15:07:55 +00002692 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002693
françois romieu4da19632011-01-03 15:07:55 +00002694 rtl_patchphy(tp, 0x16, 1 << 0);
2695 rtl_patchphy(tp, 0x14, 1 << 5);
2696 rtl_patchphy(tp, 0x0d, 1 << 5);
2697 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002698}
2699
françois romieu4da19632011-01-03 15:07:55 +00002700static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002701{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002702 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002703 { 0x1f, 0x0001 },
2704 { 0x12, 0x2300 },
2705 { 0x1d, 0x3d98 },
2706 { 0x1f, 0x0002 },
2707 { 0x0c, 0x7eb8 },
2708 { 0x06, 0x5461 },
2709 { 0x1f, 0x0003 },
2710 { 0x16, 0x0f0a },
2711 { 0x1f, 0x0000 }
2712 };
2713
françois romieu4da19632011-01-03 15:07:55 +00002714 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002715
françois romieu4da19632011-01-03 15:07:55 +00002716 rtl_patchphy(tp, 0x16, 1 << 0);
2717 rtl_patchphy(tp, 0x14, 1 << 5);
2718 rtl_patchphy(tp, 0x0d, 1 << 5);
2719 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002720}
2721
françois romieu4da19632011-01-03 15:07:55 +00002722static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002723{
françois romieu4da19632011-01-03 15:07:55 +00002724 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002725}
2726
françois romieubca03d52011-01-03 15:07:31 +00002727static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002728{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002729 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002730 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002731 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002732 { 0x06, 0x4064 },
2733 { 0x07, 0x2863 },
2734 { 0x08, 0x059c },
2735 { 0x09, 0x26b4 },
2736 { 0x0a, 0x6a19 },
2737 { 0x0b, 0xdcc8 },
2738 { 0x10, 0xf06d },
2739 { 0x14, 0x7f68 },
2740 { 0x18, 0x7fd9 },
2741 { 0x1c, 0xf0ff },
2742 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002743 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002744 { 0x12, 0xf49f },
2745 { 0x13, 0x070b },
2746 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002747 { 0x14, 0x94c0 },
2748
2749 /*
2750 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002751 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002752 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002753 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002754 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002755 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002756 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002757 { 0x06, 0x5561 },
2758
2759 /*
2760 * Can not link to 1Gbps with bad cable
2761 * Decrease SNR threshold form 21.07dB to 19.04dB
2762 */
2763 { 0x1f, 0x0001 },
2764 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002765
2766 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002767 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002768 };
2769
françois romieu4da19632011-01-03 15:07:55 +00002770 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002771
françois romieubca03d52011-01-03 15:07:31 +00002772 /*
2773 * Rx Error Issue
2774 * Fine Tune Switching regulator parameter
2775 */
françois romieu4da19632011-01-03 15:07:55 +00002776 rtl_writephy(tp, 0x1f, 0x0002);
2777 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2778 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002779
Francois Romieufdf6fc02012-07-06 22:40:38 +02002780 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002781 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002782 { 0x1f, 0x0002 },
2783 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002784 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002785 { 0x05, 0x8330 },
2786 { 0x06, 0x669a },
2787 { 0x1f, 0x0002 }
2788 };
2789 int val;
2790
françois romieu4da19632011-01-03 15:07:55 +00002791 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002792
françois romieu4da19632011-01-03 15:07:55 +00002793 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002794
2795 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002796 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002797 0x0065, 0x0066, 0x0067, 0x0068,
2798 0x0069, 0x006a, 0x006b, 0x006c
2799 };
2800 int i;
2801
françois romieu4da19632011-01-03 15:07:55 +00002802 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002803
2804 val &= 0xff00;
2805 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002806 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002807 }
2808 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002809 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002810 { 0x1f, 0x0002 },
2811 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002812 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002813 { 0x05, 0x8330 },
2814 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002815 };
2816
françois romieu4da19632011-01-03 15:07:55 +00002817 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002818 }
2819
françois romieubca03d52011-01-03 15:07:31 +00002820 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002821 rtl_writephy(tp, 0x1f, 0x0002);
2822 rtl_patchphy(tp, 0x0d, 0x0300);
2823 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002824
françois romieubca03d52011-01-03 15:07:31 +00002825 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002826 rtl_writephy(tp, 0x1f, 0x0002);
2827 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2828 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002829
françois romieu4da19632011-01-03 15:07:55 +00002830 rtl_writephy(tp, 0x1f, 0x0005);
2831 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002832
2833 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002834
françois romieu4da19632011-01-03 15:07:55 +00002835 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002836}
2837
françois romieubca03d52011-01-03 15:07:31 +00002838static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002839{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002840 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002841 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002842 { 0x1f, 0x0001 },
2843 { 0x06, 0x4064 },
2844 { 0x07, 0x2863 },
2845 { 0x08, 0x059c },
2846 { 0x09, 0x26b4 },
2847 { 0x0a, 0x6a19 },
2848 { 0x0b, 0xdcc8 },
2849 { 0x10, 0xf06d },
2850 { 0x14, 0x7f68 },
2851 { 0x18, 0x7fd9 },
2852 { 0x1c, 0xf0ff },
2853 { 0x1d, 0x3d9c },
2854 { 0x1f, 0x0003 },
2855 { 0x12, 0xf49f },
2856 { 0x13, 0x070b },
2857 { 0x1a, 0x05ad },
2858 { 0x14, 0x94c0 },
2859
françois romieubca03d52011-01-03 15:07:31 +00002860 /*
2861 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002862 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002863 */
françois romieudaf9df62009-10-07 12:44:20 +00002864 { 0x1f, 0x0002 },
2865 { 0x06, 0x5561 },
2866 { 0x1f, 0x0005 },
2867 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002868 { 0x06, 0x5561 },
2869
2870 /*
2871 * Can not link to 1Gbps with bad cable
2872 * Decrease SNR threshold form 21.07dB to 19.04dB
2873 */
2874 { 0x1f, 0x0001 },
2875 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002876
2877 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002878 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002879 };
2880
françois romieu4da19632011-01-03 15:07:55 +00002881 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002882
Francois Romieufdf6fc02012-07-06 22:40:38 +02002883 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002884 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002885 { 0x1f, 0x0002 },
2886 { 0x05, 0x669a },
2887 { 0x1f, 0x0005 },
2888 { 0x05, 0x8330 },
2889 { 0x06, 0x669a },
2890
2891 { 0x1f, 0x0002 }
2892 };
2893 int val;
2894
françois romieu4da19632011-01-03 15:07:55 +00002895 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002896
françois romieu4da19632011-01-03 15:07:55 +00002897 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002898 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002899 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002900 0x0065, 0x0066, 0x0067, 0x0068,
2901 0x0069, 0x006a, 0x006b, 0x006c
2902 };
2903 int i;
2904
françois romieu4da19632011-01-03 15:07:55 +00002905 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002906
2907 val &= 0xff00;
2908 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002909 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002910 }
2911 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002912 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002913 { 0x1f, 0x0002 },
2914 { 0x05, 0x2642 },
2915 { 0x1f, 0x0005 },
2916 { 0x05, 0x8330 },
2917 { 0x06, 0x2642 }
2918 };
2919
françois romieu4da19632011-01-03 15:07:55 +00002920 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002921 }
2922
françois romieubca03d52011-01-03 15:07:31 +00002923 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002924 rtl_writephy(tp, 0x1f, 0x0002);
2925 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2926 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002927
françois romieubca03d52011-01-03 15:07:31 +00002928 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002929 rtl_writephy(tp, 0x1f, 0x0002);
2930 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002931
françois romieu4da19632011-01-03 15:07:55 +00002932 rtl_writephy(tp, 0x1f, 0x0005);
2933 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002934
2935 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002936
françois romieu4da19632011-01-03 15:07:55 +00002937 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002938}
2939
françois romieu4da19632011-01-03 15:07:55 +00002940static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002941{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002942 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002943 { 0x1f, 0x0002 },
2944 { 0x10, 0x0008 },
2945 { 0x0d, 0x006c },
2946
2947 { 0x1f, 0x0000 },
2948 { 0x0d, 0xf880 },
2949
2950 { 0x1f, 0x0001 },
2951 { 0x17, 0x0cc0 },
2952
2953 { 0x1f, 0x0001 },
2954 { 0x0b, 0xa4d8 },
2955 { 0x09, 0x281c },
2956 { 0x07, 0x2883 },
2957 { 0x0a, 0x6b35 },
2958 { 0x1d, 0x3da4 },
2959 { 0x1c, 0xeffd },
2960 { 0x14, 0x7f52 },
2961 { 0x18, 0x7fc6 },
2962 { 0x08, 0x0601 },
2963 { 0x06, 0x4063 },
2964 { 0x10, 0xf074 },
2965 { 0x1f, 0x0003 },
2966 { 0x13, 0x0789 },
2967 { 0x12, 0xf4bd },
2968 { 0x1a, 0x04fd },
2969 { 0x14, 0x84b0 },
2970 { 0x1f, 0x0000 },
2971 { 0x00, 0x9200 },
2972
2973 { 0x1f, 0x0005 },
2974 { 0x01, 0x0340 },
2975 { 0x1f, 0x0001 },
2976 { 0x04, 0x4000 },
2977 { 0x03, 0x1d21 },
2978 { 0x02, 0x0c32 },
2979 { 0x01, 0x0200 },
2980 { 0x00, 0x5554 },
2981 { 0x04, 0x4800 },
2982 { 0x04, 0x4000 },
2983 { 0x04, 0xf000 },
2984 { 0x03, 0xdf01 },
2985 { 0x02, 0xdf20 },
2986 { 0x01, 0x101a },
2987 { 0x00, 0xa0ff },
2988 { 0x04, 0xf800 },
2989 { 0x04, 0xf000 },
2990 { 0x1f, 0x0000 },
2991
2992 { 0x1f, 0x0007 },
2993 { 0x1e, 0x0023 },
2994 { 0x16, 0x0000 },
2995 { 0x1f, 0x0000 }
2996 };
2997
françois romieu4da19632011-01-03 15:07:55 +00002998 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002999}
3000
françois romieue6de30d2011-01-03 15:08:37 +00003001static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3002{
3003 static const struct phy_reg phy_reg_init[] = {
3004 { 0x1f, 0x0001 },
3005 { 0x17, 0x0cc0 },
3006
3007 { 0x1f, 0x0007 },
3008 { 0x1e, 0x002d },
3009 { 0x18, 0x0040 },
3010 { 0x1f, 0x0000 }
3011 };
3012
3013 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3014 rtl_patchphy(tp, 0x0d, 1 << 5);
3015}
3016
Hayes Wang70090422011-07-06 15:58:06 +08003017static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003018{
3019 static const struct phy_reg phy_reg_init[] = {
3020 /* Enable Delay cap */
3021 { 0x1f, 0x0005 },
3022 { 0x05, 0x8b80 },
3023 { 0x06, 0xc896 },
3024 { 0x1f, 0x0000 },
3025
3026 /* Channel estimation fine tune */
3027 { 0x1f, 0x0001 },
3028 { 0x0b, 0x6c20 },
3029 { 0x07, 0x2872 },
3030 { 0x1c, 0xefff },
3031 { 0x1f, 0x0003 },
3032 { 0x14, 0x6420 },
3033 { 0x1f, 0x0000 },
3034
3035 /* Update PFM & 10M TX idle timer */
3036 { 0x1f, 0x0007 },
3037 { 0x1e, 0x002f },
3038 { 0x15, 0x1919 },
3039 { 0x1f, 0x0000 },
3040
3041 { 0x1f, 0x0007 },
3042 { 0x1e, 0x00ac },
3043 { 0x18, 0x0006 },
3044 { 0x1f, 0x0000 }
3045 };
3046
Francois Romieu15ecd032011-04-27 13:52:22 -07003047 rtl_apply_firmware(tp);
3048
hayeswang01dc7fe2011-03-21 01:50:28 +00003049 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3050
3051 /* DCO enable for 10M IDLE Power */
3052 rtl_writephy(tp, 0x1f, 0x0007);
3053 rtl_writephy(tp, 0x1e, 0x0023);
3054 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3055 rtl_writephy(tp, 0x1f, 0x0000);
3056
3057 /* For impedance matching */
3058 rtl_writephy(tp, 0x1f, 0x0002);
3059 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003060 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003061
3062 /* PHY auto speed down */
3063 rtl_writephy(tp, 0x1f, 0x0007);
3064 rtl_writephy(tp, 0x1e, 0x002d);
3065 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3066 rtl_writephy(tp, 0x1f, 0x0000);
3067 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3068
3069 rtl_writephy(tp, 0x1f, 0x0005);
3070 rtl_writephy(tp, 0x05, 0x8b86);
3071 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3072 rtl_writephy(tp, 0x1f, 0x0000);
3073
3074 rtl_writephy(tp, 0x1f, 0x0005);
3075 rtl_writephy(tp, 0x05, 0x8b85);
3076 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3077 rtl_writephy(tp, 0x1f, 0x0007);
3078 rtl_writephy(tp, 0x1e, 0x0020);
3079 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3080 rtl_writephy(tp, 0x1f, 0x0006);
3081 rtl_writephy(tp, 0x00, 0x5a00);
3082 rtl_writephy(tp, 0x1f, 0x0000);
3083 rtl_writephy(tp, 0x0d, 0x0007);
3084 rtl_writephy(tp, 0x0e, 0x003c);
3085 rtl_writephy(tp, 0x0d, 0x4007);
3086 rtl_writephy(tp, 0x0e, 0x0000);
3087 rtl_writephy(tp, 0x0d, 0x0000);
3088}
3089
françois romieu9ecb9aa2012-12-07 11:20:21 +00003090static void rtl_rar_exgmac_set(struct rtl8169_private *tp, u8 *addr)
3091{
3092 const u16 w[] = {
3093 addr[0] | (addr[1] << 8),
3094 addr[2] | (addr[3] << 8),
3095 addr[4] | (addr[5] << 8)
3096 };
3097 const struct exgmac_reg e[] = {
3098 { .addr = 0xe0, ERIAR_MASK_1111, .val = w[0] | (w[1] << 16) },
3099 { .addr = 0xe4, ERIAR_MASK_1111, .val = w[2] },
3100 { .addr = 0xf0, ERIAR_MASK_1111, .val = w[0] << 16 },
3101 { .addr = 0xf4, ERIAR_MASK_1111, .val = w[1] | (w[2] << 16) }
3102 };
3103
3104 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
3105}
3106
Hayes Wang70090422011-07-06 15:58:06 +08003107static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3108{
3109 static const struct phy_reg phy_reg_init[] = {
3110 /* Enable Delay cap */
3111 { 0x1f, 0x0004 },
3112 { 0x1f, 0x0007 },
3113 { 0x1e, 0x00ac },
3114 { 0x18, 0x0006 },
3115 { 0x1f, 0x0002 },
3116 { 0x1f, 0x0000 },
3117 { 0x1f, 0x0000 },
3118
3119 /* Channel estimation fine tune */
3120 { 0x1f, 0x0003 },
3121 { 0x09, 0xa20f },
3122 { 0x1f, 0x0000 },
3123 { 0x1f, 0x0000 },
3124
3125 /* Green Setting */
3126 { 0x1f, 0x0005 },
3127 { 0x05, 0x8b5b },
3128 { 0x06, 0x9222 },
3129 { 0x05, 0x8b6d },
3130 { 0x06, 0x8000 },
3131 { 0x05, 0x8b76 },
3132 { 0x06, 0x8000 },
3133 { 0x1f, 0x0000 }
3134 };
3135
3136 rtl_apply_firmware(tp);
3137
3138 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3139
3140 /* For 4-corner performance improve */
3141 rtl_writephy(tp, 0x1f, 0x0005);
3142 rtl_writephy(tp, 0x05, 0x8b80);
3143 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3144 rtl_writephy(tp, 0x1f, 0x0000);
3145
3146 /* PHY auto speed down */
3147 rtl_writephy(tp, 0x1f, 0x0004);
3148 rtl_writephy(tp, 0x1f, 0x0007);
3149 rtl_writephy(tp, 0x1e, 0x002d);
3150 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3151 rtl_writephy(tp, 0x1f, 0x0002);
3152 rtl_writephy(tp, 0x1f, 0x0000);
3153 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3154
3155 /* improve 10M EEE waveform */
3156 rtl_writephy(tp, 0x1f, 0x0005);
3157 rtl_writephy(tp, 0x05, 0x8b86);
3158 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3159 rtl_writephy(tp, 0x1f, 0x0000);
3160
3161 /* Improve 2-pair detection performance */
3162 rtl_writephy(tp, 0x1f, 0x0005);
3163 rtl_writephy(tp, 0x05, 0x8b85);
3164 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3165 rtl_writephy(tp, 0x1f, 0x0000);
3166
3167 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003168 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003169 rtl_writephy(tp, 0x1f, 0x0005);
3170 rtl_writephy(tp, 0x05, 0x8b85);
3171 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3172 rtl_writephy(tp, 0x1f, 0x0004);
3173 rtl_writephy(tp, 0x1f, 0x0007);
3174 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003175 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003176 rtl_writephy(tp, 0x1f, 0x0002);
3177 rtl_writephy(tp, 0x1f, 0x0000);
3178 rtl_writephy(tp, 0x0d, 0x0007);
3179 rtl_writephy(tp, 0x0e, 0x003c);
3180 rtl_writephy(tp, 0x0d, 0x4007);
3181 rtl_writephy(tp, 0x0e, 0x0000);
3182 rtl_writephy(tp, 0x0d, 0x0000);
3183
3184 /* Green feature */
3185 rtl_writephy(tp, 0x1f, 0x0003);
3186 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3187 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3188 rtl_writephy(tp, 0x1f, 0x0000);
hayeswange0c07552012-10-23 20:24:03 +00003189
françois romieu9ecb9aa2012-12-07 11:20:21 +00003190 /* Broken BIOS workaround: feed GigaMAC registers with MAC address. */
3191 rtl_rar_exgmac_set(tp, tp->dev->dev_addr);
Hayes Wang70090422011-07-06 15:58:06 +08003192}
3193
Hayes Wang5f886e02012-03-30 14:33:03 +08003194static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3195{
3196 /* For 4-corner performance improve */
3197 rtl_writephy(tp, 0x1f, 0x0005);
3198 rtl_writephy(tp, 0x05, 0x8b80);
3199 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3200 rtl_writephy(tp, 0x1f, 0x0000);
3201
3202 /* PHY auto speed down */
3203 rtl_writephy(tp, 0x1f, 0x0007);
3204 rtl_writephy(tp, 0x1e, 0x002d);
3205 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3206 rtl_writephy(tp, 0x1f, 0x0000);
3207 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3208
3209 /* Improve 10M EEE waveform */
3210 rtl_writephy(tp, 0x1f, 0x0005);
3211 rtl_writephy(tp, 0x05, 0x8b86);
3212 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3213 rtl_writephy(tp, 0x1f, 0x0000);
3214}
3215
Hayes Wangc2218922011-09-06 16:55:18 +08003216static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3217{
3218 static const struct phy_reg phy_reg_init[] = {
3219 /* Channel estimation fine tune */
3220 { 0x1f, 0x0003 },
3221 { 0x09, 0xa20f },
3222 { 0x1f, 0x0000 },
3223
3224 /* Modify green table for giga & fnet */
3225 { 0x1f, 0x0005 },
3226 { 0x05, 0x8b55 },
3227 { 0x06, 0x0000 },
3228 { 0x05, 0x8b5e },
3229 { 0x06, 0x0000 },
3230 { 0x05, 0x8b67 },
3231 { 0x06, 0x0000 },
3232 { 0x05, 0x8b70 },
3233 { 0x06, 0x0000 },
3234 { 0x1f, 0x0000 },
3235 { 0x1f, 0x0007 },
3236 { 0x1e, 0x0078 },
3237 { 0x17, 0x0000 },
3238 { 0x19, 0x00fb },
3239 { 0x1f, 0x0000 },
3240
3241 /* Modify green table for 10M */
3242 { 0x1f, 0x0005 },
3243 { 0x05, 0x8b79 },
3244 { 0x06, 0xaa00 },
3245 { 0x1f, 0x0000 },
3246
3247 /* Disable hiimpedance detection (RTCT) */
3248 { 0x1f, 0x0003 },
3249 { 0x01, 0x328a },
3250 { 0x1f, 0x0000 }
3251 };
3252
3253 rtl_apply_firmware(tp);
3254
3255 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3256
Hayes Wang5f886e02012-03-30 14:33:03 +08003257 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003258
3259 /* Improve 2-pair detection performance */
3260 rtl_writephy(tp, 0x1f, 0x0005);
3261 rtl_writephy(tp, 0x05, 0x8b85);
3262 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3263 rtl_writephy(tp, 0x1f, 0x0000);
3264}
3265
3266static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3267{
3268 rtl_apply_firmware(tp);
3269
Hayes Wang5f886e02012-03-30 14:33:03 +08003270 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003271}
3272
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003273static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3274{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003275 static const struct phy_reg phy_reg_init[] = {
3276 /* Channel estimation fine tune */
3277 { 0x1f, 0x0003 },
3278 { 0x09, 0xa20f },
3279 { 0x1f, 0x0000 },
3280
3281 /* Modify green table for giga & fnet */
3282 { 0x1f, 0x0005 },
3283 { 0x05, 0x8b55 },
3284 { 0x06, 0x0000 },
3285 { 0x05, 0x8b5e },
3286 { 0x06, 0x0000 },
3287 { 0x05, 0x8b67 },
3288 { 0x06, 0x0000 },
3289 { 0x05, 0x8b70 },
3290 { 0x06, 0x0000 },
3291 { 0x1f, 0x0000 },
3292 { 0x1f, 0x0007 },
3293 { 0x1e, 0x0078 },
3294 { 0x17, 0x0000 },
3295 { 0x19, 0x00aa },
3296 { 0x1f, 0x0000 },
3297
3298 /* Modify green table for 10M */
3299 { 0x1f, 0x0005 },
3300 { 0x05, 0x8b79 },
3301 { 0x06, 0xaa00 },
3302 { 0x1f, 0x0000 },
3303
3304 /* Disable hiimpedance detection (RTCT) */
3305 { 0x1f, 0x0003 },
3306 { 0x01, 0x328a },
3307 { 0x1f, 0x0000 }
3308 };
3309
3310
3311 rtl_apply_firmware(tp);
3312
3313 rtl8168f_hw_phy_config(tp);
3314
3315 /* Improve 2-pair detection performance */
3316 rtl_writephy(tp, 0x1f, 0x0005);
3317 rtl_writephy(tp, 0x05, 0x8b85);
3318 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3319 rtl_writephy(tp, 0x1f, 0x0000);
3320
3321 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3322
3323 /* Modify green table for giga */
3324 rtl_writephy(tp, 0x1f, 0x0005);
3325 rtl_writephy(tp, 0x05, 0x8b54);
3326 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3327 rtl_writephy(tp, 0x05, 0x8b5d);
3328 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3329 rtl_writephy(tp, 0x05, 0x8a7c);
3330 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3331 rtl_writephy(tp, 0x05, 0x8a7f);
3332 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3333 rtl_writephy(tp, 0x05, 0x8a82);
3334 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3335 rtl_writephy(tp, 0x05, 0x8a85);
3336 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3337 rtl_writephy(tp, 0x05, 0x8a88);
3338 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3339 rtl_writephy(tp, 0x1f, 0x0000);
3340
3341 /* uc same-seed solution */
3342 rtl_writephy(tp, 0x1f, 0x0005);
3343 rtl_writephy(tp, 0x05, 0x8b85);
3344 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3345 rtl_writephy(tp, 0x1f, 0x0000);
3346
3347 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003348 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003349 rtl_writephy(tp, 0x1f, 0x0005);
3350 rtl_writephy(tp, 0x05, 0x8b85);
3351 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3352 rtl_writephy(tp, 0x1f, 0x0004);
3353 rtl_writephy(tp, 0x1f, 0x0007);
3354 rtl_writephy(tp, 0x1e, 0x0020);
3355 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3356 rtl_writephy(tp, 0x1f, 0x0000);
3357 rtl_writephy(tp, 0x0d, 0x0007);
3358 rtl_writephy(tp, 0x0e, 0x003c);
3359 rtl_writephy(tp, 0x0d, 0x4007);
3360 rtl_writephy(tp, 0x0e, 0x0000);
3361 rtl_writephy(tp, 0x0d, 0x0000);
3362
3363 /* Green feature */
3364 rtl_writephy(tp, 0x1f, 0x0003);
3365 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3366 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3367 rtl_writephy(tp, 0x1f, 0x0000);
3368}
3369
Hayes Wangc5583862012-07-02 17:23:22 +08003370static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3371{
3372 static const u16 mac_ocp_patch[] = {
3373 0xe008, 0xe01b, 0xe01d, 0xe01f,
3374 0xe021, 0xe023, 0xe025, 0xe027,
3375 0x49d2, 0xf10d, 0x766c, 0x49e2,
3376 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3377
3378 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3379 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3380 0xbe00, 0xb416, 0x0076, 0xe86c,
3381 0xc602, 0xbe00, 0x0000, 0xc602,
3382
3383 0xbe00, 0x0000, 0xc602, 0xbe00,
3384 0x0000, 0xc602, 0xbe00, 0x0000,
3385 0xc602, 0xbe00, 0x0000, 0xc602,
3386 0xbe00, 0x0000, 0xc602, 0xbe00,
3387
3388 0x0000, 0x0000, 0x0000, 0x0000
3389 };
3390 u32 i;
3391
3392 /* Patch code for GPHY reset */
3393 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3394 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3395 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3396 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3397
3398 rtl_apply_firmware(tp);
3399
3400 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3401 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3402 else
3403 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3404
3405 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3406 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3407 else
3408 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3409
3410 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3411 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3412
3413 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3414 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3415
3416 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3417}
3418
françois romieu4da19632011-01-03 15:07:55 +00003419static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003420{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003421 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003422 { 0x1f, 0x0003 },
3423 { 0x08, 0x441d },
3424 { 0x01, 0x9100 },
3425 { 0x1f, 0x0000 }
3426 };
3427
françois romieu4da19632011-01-03 15:07:55 +00003428 rtl_writephy(tp, 0x1f, 0x0000);
3429 rtl_patchphy(tp, 0x11, 1 << 12);
3430 rtl_patchphy(tp, 0x19, 1 << 13);
3431 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003432
françois romieu4da19632011-01-03 15:07:55 +00003433 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003434}
3435
Hayes Wang5a5e4442011-02-22 17:26:21 +08003436static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3437{
3438 static const struct phy_reg phy_reg_init[] = {
3439 { 0x1f, 0x0005 },
3440 { 0x1a, 0x0000 },
3441 { 0x1f, 0x0000 },
3442
3443 { 0x1f, 0x0004 },
3444 { 0x1c, 0x0000 },
3445 { 0x1f, 0x0000 },
3446
3447 { 0x1f, 0x0001 },
3448 { 0x15, 0x7701 },
3449 { 0x1f, 0x0000 }
3450 };
3451
3452 /* Disable ALDPS before ram code */
Francois Romieueef63cc2013-02-08 23:43:20 +01003453 rtl_writephy(tp, 0x1f, 0x0000);
3454 rtl_writephy(tp, 0x18, 0x0310);
3455 msleep(100);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003456
François Romieu953a12c2011-04-24 17:38:48 +02003457 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003458
3459 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3460}
3461
Hayes Wang7e18dca2012-03-30 14:33:02 +08003462static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3463{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003464 /* Disable ALDPS before setting firmware */
Francois Romieueef63cc2013-02-08 23:43:20 +01003465 rtl_writephy(tp, 0x1f, 0x0000);
3466 rtl_writephy(tp, 0x18, 0x0310);
3467 msleep(20);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003468
3469 rtl_apply_firmware(tp);
3470
3471 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003472 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003473 rtl_writephy(tp, 0x1f, 0x0004);
3474 rtl_writephy(tp, 0x10, 0x401f);
3475 rtl_writephy(tp, 0x19, 0x7030);
3476 rtl_writephy(tp, 0x1f, 0x0000);
3477}
3478
Hayes Wang5598bfe2012-07-02 17:23:21 +08003479static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3480{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003481 static const struct phy_reg phy_reg_init[] = {
3482 { 0x1f, 0x0004 },
3483 { 0x10, 0xc07f },
3484 { 0x19, 0x7030 },
3485 { 0x1f, 0x0000 }
3486 };
3487
3488 /* Disable ALDPS before ram code */
Francois Romieueef63cc2013-02-08 23:43:20 +01003489 rtl_writephy(tp, 0x1f, 0x0000);
3490 rtl_writephy(tp, 0x18, 0x0310);
3491 msleep(100);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003492
3493 rtl_apply_firmware(tp);
3494
Francois Romieufdf6fc02012-07-06 22:40:38 +02003495 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003496 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3497
Francois Romieufdf6fc02012-07-06 22:40:38 +02003498 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003499}
3500
Francois Romieu5615d9f2007-08-17 17:50:46 +02003501static void rtl_hw_phy_config(struct net_device *dev)
3502{
3503 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003504
3505 rtl8169_print_mac_version(tp);
3506
3507 switch (tp->mac_version) {
3508 case RTL_GIGA_MAC_VER_01:
3509 break;
3510 case RTL_GIGA_MAC_VER_02:
3511 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003512 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003513 break;
3514 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003515 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003516 break;
françois romieu2e9558562009-08-10 19:44:19 +00003517 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003518 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003519 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003520 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003521 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003522 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003523 case RTL_GIGA_MAC_VER_07:
3524 case RTL_GIGA_MAC_VER_08:
3525 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003526 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003527 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003528 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003529 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003530 break;
3531 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003532 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003533 break;
3534 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003535 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003536 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003537 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003538 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003539 break;
3540 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003541 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003542 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003543 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003544 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003545 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003546 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003547 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003548 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003549 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003550 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003551 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003552 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003553 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003554 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003555 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003556 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003557 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003558 break;
3559 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003560 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003561 break;
3562 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003563 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003564 break;
françois romieue6de30d2011-01-03 15:08:37 +00003565 case RTL_GIGA_MAC_VER_28:
3566 rtl8168d_4_hw_phy_config(tp);
3567 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003568 case RTL_GIGA_MAC_VER_29:
3569 case RTL_GIGA_MAC_VER_30:
3570 rtl8105e_hw_phy_config(tp);
3571 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003572 case RTL_GIGA_MAC_VER_31:
3573 /* None. */
3574 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003575 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003576 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003577 rtl8168e_1_hw_phy_config(tp);
3578 break;
3579 case RTL_GIGA_MAC_VER_34:
3580 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003581 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003582 case RTL_GIGA_MAC_VER_35:
3583 rtl8168f_1_hw_phy_config(tp);
3584 break;
3585 case RTL_GIGA_MAC_VER_36:
3586 rtl8168f_2_hw_phy_config(tp);
3587 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003588
Hayes Wang7e18dca2012-03-30 14:33:02 +08003589 case RTL_GIGA_MAC_VER_37:
3590 rtl8402_hw_phy_config(tp);
3591 break;
3592
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003593 case RTL_GIGA_MAC_VER_38:
3594 rtl8411_hw_phy_config(tp);
3595 break;
3596
Hayes Wang5598bfe2012-07-02 17:23:21 +08003597 case RTL_GIGA_MAC_VER_39:
3598 rtl8106e_hw_phy_config(tp);
3599 break;
3600
Hayes Wangc5583862012-07-02 17:23:22 +08003601 case RTL_GIGA_MAC_VER_40:
3602 rtl8168g_1_hw_phy_config(tp);
3603 break;
3604
3605 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003606 default:
3607 break;
3608 }
3609}
3610
Francois Romieuda78dbf2012-01-26 14:18:23 +01003611static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 struct timer_list *timer = &tp->timer;
3614 void __iomem *ioaddr = tp->mmio_addr;
3615 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3616
Francois Romieubcf0bf92006-07-26 23:14:13 +02003617 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618
françois romieu4da19632011-01-03 15:07:55 +00003619 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003620 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 * A busy loop could burn quite a few cycles on nowadays CPU.
3622 * Let's delay the execution of the timer for a few ticks.
3623 */
3624 timeout = HZ/10;
3625 goto out_mod_timer;
3626 }
3627
3628 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003629 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630
Francois Romieuda78dbf2012-01-26 14:18:23 +01003631 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632
françois romieu4da19632011-01-03 15:07:55 +00003633 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634
3635out_mod_timer:
3636 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003637}
3638
3639static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3640{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003641 if (!test_and_set_bit(flag, tp->wk.flags))
3642 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003643}
3644
3645static void rtl8169_phy_timer(unsigned long __opaque)
3646{
3647 struct net_device *dev = (struct net_device *)__opaque;
3648 struct rtl8169_private *tp = netdev_priv(dev);
3649
Francois Romieu98ddf982012-01-31 10:47:34 +01003650 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651}
3652
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3654 void __iomem *ioaddr)
3655{
3656 iounmap(ioaddr);
3657 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003658 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 pci_disable_device(pdev);
3660 free_netdev(dev);
3661}
3662
Francois Romieuffc46952012-07-06 14:19:23 +02003663DECLARE_RTL_COND(rtl_phy_reset_cond)
3664{
3665 return tp->phy_reset_pending(tp);
3666}
3667
Francois Romieubf793292006-11-01 00:53:05 +01003668static void rtl8169_phy_reset(struct net_device *dev,
3669 struct rtl8169_private *tp)
3670{
françois romieu4da19632011-01-03 15:07:55 +00003671 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003672 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003673}
3674
David S. Miller8decf862011-09-22 03:23:13 -04003675static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3676{
3677 void __iomem *ioaddr = tp->mmio_addr;
3678
3679 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3680 (RTL_R8(PHYstatus) & TBI_Enable);
3681}
3682
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003683static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003685 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003686
Francois Romieu5615d9f2007-08-17 17:50:46 +02003687 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003688
Marcus Sundberg773328942008-07-10 21:28:08 +02003689 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3690 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3691 RTL_W8(0x82, 0x01);
3692 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003693
Francois Romieu6dccd162007-02-13 23:38:05 +01003694 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3695
3696 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3697 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003698
Francois Romieubcf0bf92006-07-26 23:14:13 +02003699 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003700 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3701 RTL_W8(0x82, 0x01);
3702 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003703 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003704 }
3705
Francois Romieubf793292006-11-01 00:53:05 +01003706 rtl8169_phy_reset(dev, tp);
3707
Oliver Neukum54405cd2011-01-06 21:55:13 +01003708 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003709 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3710 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3711 (tp->mii.supports_gmii ?
3712 ADVERTISED_1000baseT_Half |
3713 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003714
David S. Miller8decf862011-09-22 03:23:13 -04003715 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003716 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003717}
3718
Francois Romieu773d2022007-01-31 23:47:43 +01003719static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3720{
3721 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu773d2022007-01-31 23:47:43 +01003722
Francois Romieuda78dbf2012-01-26 14:18:23 +01003723 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003724
3725 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2b2010-04-26 11:42:58 +00003726
françois romieu9ecb9aa2012-12-07 11:20:21 +00003727 RTL_W32(MAC4, addr[4] | addr[5] << 8);
françois romieu908ba2b2010-04-26 11:42:58 +00003728 RTL_R32(MAC4);
3729
françois romieu9ecb9aa2012-12-07 11:20:21 +00003730 RTL_W32(MAC0, addr[0] | addr[1] << 8 | addr[2] << 16 | addr[3] << 24);
françois romieu908ba2b2010-04-26 11:42:58 +00003731 RTL_R32(MAC0);
3732
françois romieu9ecb9aa2012-12-07 11:20:21 +00003733 if (tp->mac_version == RTL_GIGA_MAC_VER_34)
3734 rtl_rar_exgmac_set(tp, addr);
françois romieuc28aa382011-08-02 03:53:43 +00003735
Francois Romieu773d2022007-01-31 23:47:43 +01003736 RTL_W8(Cfg9346, Cfg9346_Lock);
3737
Francois Romieuda78dbf2012-01-26 14:18:23 +01003738 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003739}
3740
3741static int rtl_set_mac_address(struct net_device *dev, void *p)
3742{
3743 struct rtl8169_private *tp = netdev_priv(dev);
3744 struct sockaddr *addr = p;
3745
3746 if (!is_valid_ether_addr(addr->sa_data))
3747 return -EADDRNOTAVAIL;
3748
3749 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3750
3751 rtl_rar_set(tp, dev->dev_addr);
3752
3753 return 0;
3754}
3755
Francois Romieu5f787a12006-08-17 13:02:36 +02003756static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3757{
3758 struct rtl8169_private *tp = netdev_priv(dev);
3759 struct mii_ioctl_data *data = if_mii(ifr);
3760
Francois Romieu8b4ab282008-11-19 22:05:25 -08003761 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3762}
Francois Romieu5f787a12006-08-17 13:02:36 +02003763
Francois Romieucecb5fd2011-04-01 10:21:07 +02003764static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3765 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003766{
Francois Romieu5f787a12006-08-17 13:02:36 +02003767 switch (cmd) {
3768 case SIOCGMIIPHY:
3769 data->phy_id = 32; /* Internal PHY */
3770 return 0;
3771
3772 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003773 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003774 return 0;
3775
3776 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003777 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003778 return 0;
3779 }
3780 return -EOPNOTSUPP;
3781}
3782
Francois Romieu8b4ab282008-11-19 22:05:25 -08003783static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3784{
3785 return -EOPNOTSUPP;
3786}
3787
Francois Romieufbac58f2007-10-04 22:51:38 +02003788static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3789{
3790 if (tp->features & RTL_FEATURE_MSI) {
3791 pci_disable_msi(pdev);
3792 tp->features &= ~RTL_FEATURE_MSI;
3793 }
3794}
3795
Bill Pembertonbaf63292012-12-03 09:23:28 -05003796static void rtl_init_mdio_ops(struct rtl8169_private *tp)
françois romieuc0e45c12011-01-03 15:08:04 +00003797{
3798 struct mdio_ops *ops = &tp->mdio_ops;
3799
3800 switch (tp->mac_version) {
3801 case RTL_GIGA_MAC_VER_27:
3802 ops->write = r8168dp_1_mdio_write;
3803 ops->read = r8168dp_1_mdio_read;
3804 break;
françois romieue6de30d2011-01-03 15:08:37 +00003805 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003806 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003807 ops->write = r8168dp_2_mdio_write;
3808 ops->read = r8168dp_2_mdio_read;
3809 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003810 case RTL_GIGA_MAC_VER_40:
3811 case RTL_GIGA_MAC_VER_41:
3812 ops->write = r8168g_mdio_write;
3813 ops->read = r8168g_mdio_read;
3814 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003815 default:
3816 ops->write = r8169_mdio_write;
3817 ops->read = r8169_mdio_read;
3818 break;
3819 }
3820}
3821
David S. Miller1805b2f2011-10-24 18:18:09 -04003822static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3823{
3824 void __iomem *ioaddr = tp->mmio_addr;
3825
3826 switch (tp->mac_version) {
Cyril Bruleboisb00e69d2012-10-31 14:00:46 +00003827 case RTL_GIGA_MAC_VER_25:
3828 case RTL_GIGA_MAC_VER_26:
David S. Miller1805b2f2011-10-24 18:18:09 -04003829 case RTL_GIGA_MAC_VER_29:
3830 case RTL_GIGA_MAC_VER_30:
3831 case RTL_GIGA_MAC_VER_32:
3832 case RTL_GIGA_MAC_VER_33:
3833 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003834 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003835 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003836 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003837 case RTL_GIGA_MAC_VER_40:
3838 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003839 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3840 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3841 break;
3842 default:
3843 break;
3844 }
3845}
3846
3847static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3848{
3849 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3850 return false;
3851
3852 rtl_writephy(tp, 0x1f, 0x0000);
3853 rtl_writephy(tp, MII_BMCR, 0x0000);
3854
3855 rtl_wol_suspend_quirk(tp);
3856
3857 return true;
3858}
3859
françois romieu065c27c2011-01-03 15:08:12 +00003860static void r810x_phy_power_down(struct rtl8169_private *tp)
3861{
3862 rtl_writephy(tp, 0x1f, 0x0000);
3863 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3864}
3865
3866static void r810x_phy_power_up(struct rtl8169_private *tp)
3867{
3868 rtl_writephy(tp, 0x1f, 0x0000);
3869 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3870}
3871
3872static void r810x_pll_power_down(struct rtl8169_private *tp)
3873{
Hayes Wang00042992012-03-30 14:33:00 +08003874 void __iomem *ioaddr = tp->mmio_addr;
3875
David S. Miller1805b2f2011-10-24 18:18:09 -04003876 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003877 return;
françois romieu065c27c2011-01-03 15:08:12 +00003878
3879 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003880
3881 switch (tp->mac_version) {
3882 case RTL_GIGA_MAC_VER_07:
3883 case RTL_GIGA_MAC_VER_08:
3884 case RTL_GIGA_MAC_VER_09:
3885 case RTL_GIGA_MAC_VER_10:
3886 case RTL_GIGA_MAC_VER_13:
3887 case RTL_GIGA_MAC_VER_16:
3888 break;
3889 default:
3890 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3891 break;
3892 }
françois romieu065c27c2011-01-03 15:08:12 +00003893}
3894
3895static void r810x_pll_power_up(struct rtl8169_private *tp)
3896{
Hayes Wang00042992012-03-30 14:33:00 +08003897 void __iomem *ioaddr = tp->mmio_addr;
3898
françois romieu065c27c2011-01-03 15:08:12 +00003899 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003900
3901 switch (tp->mac_version) {
3902 case RTL_GIGA_MAC_VER_07:
3903 case RTL_GIGA_MAC_VER_08:
3904 case RTL_GIGA_MAC_VER_09:
3905 case RTL_GIGA_MAC_VER_10:
3906 case RTL_GIGA_MAC_VER_13:
3907 case RTL_GIGA_MAC_VER_16:
3908 break;
3909 default:
3910 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3911 break;
3912 }
françois romieu065c27c2011-01-03 15:08:12 +00003913}
3914
3915static void r8168_phy_power_up(struct rtl8169_private *tp)
3916{
3917 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003918 switch (tp->mac_version) {
3919 case RTL_GIGA_MAC_VER_11:
3920 case RTL_GIGA_MAC_VER_12:
3921 case RTL_GIGA_MAC_VER_17:
3922 case RTL_GIGA_MAC_VER_18:
3923 case RTL_GIGA_MAC_VER_19:
3924 case RTL_GIGA_MAC_VER_20:
3925 case RTL_GIGA_MAC_VER_21:
3926 case RTL_GIGA_MAC_VER_22:
3927 case RTL_GIGA_MAC_VER_23:
3928 case RTL_GIGA_MAC_VER_24:
3929 case RTL_GIGA_MAC_VER_25:
3930 case RTL_GIGA_MAC_VER_26:
3931 case RTL_GIGA_MAC_VER_27:
3932 case RTL_GIGA_MAC_VER_28:
3933 case RTL_GIGA_MAC_VER_31:
3934 rtl_writephy(tp, 0x0e, 0x0000);
3935 break;
3936 default:
3937 break;
3938 }
françois romieu065c27c2011-01-03 15:08:12 +00003939 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3940}
3941
3942static void r8168_phy_power_down(struct rtl8169_private *tp)
3943{
3944 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003945 switch (tp->mac_version) {
3946 case RTL_GIGA_MAC_VER_32:
3947 case RTL_GIGA_MAC_VER_33:
3948 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3949 break;
3950
3951 case RTL_GIGA_MAC_VER_11:
3952 case RTL_GIGA_MAC_VER_12:
3953 case RTL_GIGA_MAC_VER_17:
3954 case RTL_GIGA_MAC_VER_18:
3955 case RTL_GIGA_MAC_VER_19:
3956 case RTL_GIGA_MAC_VER_20:
3957 case RTL_GIGA_MAC_VER_21:
3958 case RTL_GIGA_MAC_VER_22:
3959 case RTL_GIGA_MAC_VER_23:
3960 case RTL_GIGA_MAC_VER_24:
3961 case RTL_GIGA_MAC_VER_25:
3962 case RTL_GIGA_MAC_VER_26:
3963 case RTL_GIGA_MAC_VER_27:
3964 case RTL_GIGA_MAC_VER_28:
3965 case RTL_GIGA_MAC_VER_31:
3966 rtl_writephy(tp, 0x0e, 0x0200);
3967 default:
3968 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3969 break;
3970 }
françois romieu065c27c2011-01-03 15:08:12 +00003971}
3972
3973static void r8168_pll_power_down(struct rtl8169_private *tp)
3974{
3975 void __iomem *ioaddr = tp->mmio_addr;
3976
Francois Romieucecb5fd2011-04-01 10:21:07 +02003977 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
3978 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
3979 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00003980 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00003981 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08003982 }
françois romieu065c27c2011-01-03 15:08:12 +00003983
Francois Romieucecb5fd2011-04-01 10:21:07 +02003984 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
3985 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00003986 (RTL_R16(CPlusCmd) & ASF)) {
3987 return;
3988 }
3989
hayeswang01dc7fe2011-03-21 01:50:28 +00003990 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
3991 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02003992 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00003993
David S. Miller1805b2f2011-10-24 18:18:09 -04003994 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003995 return;
françois romieu065c27c2011-01-03 15:08:12 +00003996
3997 r8168_phy_power_down(tp);
3998
3999 switch (tp->mac_version) {
4000 case RTL_GIGA_MAC_VER_25:
4001 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004002 case RTL_GIGA_MAC_VER_27:
4003 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004004 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004005 case RTL_GIGA_MAC_VER_32:
4006 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004007 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4008 break;
4009 }
4010}
4011
4012static void r8168_pll_power_up(struct rtl8169_private *tp)
4013{
4014 void __iomem *ioaddr = tp->mmio_addr;
4015
françois romieu065c27c2011-01-03 15:08:12 +00004016 switch (tp->mac_version) {
4017 case RTL_GIGA_MAC_VER_25:
4018 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004019 case RTL_GIGA_MAC_VER_27:
4020 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004021 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004022 case RTL_GIGA_MAC_VER_32:
4023 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004024 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4025 break;
4026 }
4027
4028 r8168_phy_power_up(tp);
4029}
4030
Francois Romieud58d46b2011-05-03 16:38:29 +02004031static void rtl_generic_op(struct rtl8169_private *tp,
4032 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004033{
4034 if (op)
4035 op(tp);
4036}
4037
4038static void rtl_pll_power_down(struct rtl8169_private *tp)
4039{
Francois Romieud58d46b2011-05-03 16:38:29 +02004040 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004041}
4042
4043static void rtl_pll_power_up(struct rtl8169_private *tp)
4044{
Francois Romieud58d46b2011-05-03 16:38:29 +02004045 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004046}
4047
Bill Pembertonbaf63292012-12-03 09:23:28 -05004048static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
françois romieu065c27c2011-01-03 15:08:12 +00004049{
4050 struct pll_power_ops *ops = &tp->pll_power_ops;
4051
4052 switch (tp->mac_version) {
4053 case RTL_GIGA_MAC_VER_07:
4054 case RTL_GIGA_MAC_VER_08:
4055 case RTL_GIGA_MAC_VER_09:
4056 case RTL_GIGA_MAC_VER_10:
4057 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004058 case RTL_GIGA_MAC_VER_29:
4059 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004060 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004061 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004062 ops->down = r810x_pll_power_down;
4063 ops->up = r810x_pll_power_up;
4064 break;
4065
4066 case RTL_GIGA_MAC_VER_11:
4067 case RTL_GIGA_MAC_VER_12:
4068 case RTL_GIGA_MAC_VER_17:
4069 case RTL_GIGA_MAC_VER_18:
4070 case RTL_GIGA_MAC_VER_19:
4071 case RTL_GIGA_MAC_VER_20:
4072 case RTL_GIGA_MAC_VER_21:
4073 case RTL_GIGA_MAC_VER_22:
4074 case RTL_GIGA_MAC_VER_23:
4075 case RTL_GIGA_MAC_VER_24:
4076 case RTL_GIGA_MAC_VER_25:
4077 case RTL_GIGA_MAC_VER_26:
4078 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004079 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004080 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004081 case RTL_GIGA_MAC_VER_32:
4082 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004083 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004084 case RTL_GIGA_MAC_VER_35:
4085 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004086 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004087 case RTL_GIGA_MAC_VER_40:
4088 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004089 ops->down = r8168_pll_power_down;
4090 ops->up = r8168_pll_power_up;
4091 break;
4092
4093 default:
4094 ops->down = NULL;
4095 ops->up = NULL;
4096 break;
4097 }
4098}
4099
Hayes Wange542a222011-07-06 15:58:04 +08004100static void rtl_init_rxcfg(struct rtl8169_private *tp)
4101{
4102 void __iomem *ioaddr = tp->mmio_addr;
4103
4104 switch (tp->mac_version) {
4105 case RTL_GIGA_MAC_VER_01:
4106 case RTL_GIGA_MAC_VER_02:
4107 case RTL_GIGA_MAC_VER_03:
4108 case RTL_GIGA_MAC_VER_04:
4109 case RTL_GIGA_MAC_VER_05:
4110 case RTL_GIGA_MAC_VER_06:
4111 case RTL_GIGA_MAC_VER_10:
4112 case RTL_GIGA_MAC_VER_11:
4113 case RTL_GIGA_MAC_VER_12:
4114 case RTL_GIGA_MAC_VER_13:
4115 case RTL_GIGA_MAC_VER_14:
4116 case RTL_GIGA_MAC_VER_15:
4117 case RTL_GIGA_MAC_VER_16:
4118 case RTL_GIGA_MAC_VER_17:
4119 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4120 break;
4121 case RTL_GIGA_MAC_VER_18:
4122 case RTL_GIGA_MAC_VER_19:
4123 case RTL_GIGA_MAC_VER_20:
4124 case RTL_GIGA_MAC_VER_21:
4125 case RTL_GIGA_MAC_VER_22:
4126 case RTL_GIGA_MAC_VER_23:
4127 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004128 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004129 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4130 break;
4131 default:
4132 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4133 break;
4134 }
4135}
4136
Hayes Wang92fc43b2011-07-06 15:58:03 +08004137static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4138{
4139 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4140}
4141
Francois Romieud58d46b2011-05-03 16:38:29 +02004142static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4143{
françois romieu9c5028e2012-03-02 04:43:14 +00004144 void __iomem *ioaddr = tp->mmio_addr;
4145
4146 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004147 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004148 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004149}
4150
4151static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
4152{
françois romieu9c5028e2012-03-02 04:43:14 +00004153 void __iomem *ioaddr = tp->mmio_addr;
4154
4155 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004156 rtl_generic_op(tp, tp->jumbo_ops.disable);
françois romieu9c5028e2012-03-02 04:43:14 +00004157 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004158}
4159
4160static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4161{
4162 void __iomem *ioaddr = tp->mmio_addr;
4163
4164 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4165 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4166 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4167}
4168
4169static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
4170{
4171 void __iomem *ioaddr = tp->mmio_addr;
4172
4173 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4174 RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
4175 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
4176}
4177
4178static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
4179{
4180 void __iomem *ioaddr = tp->mmio_addr;
4181
4182 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4183}
4184
4185static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4186{
4187 void __iomem *ioaddr = tp->mmio_addr;
4188
4189 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4190}
4191
4192static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4193{
4194 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004195
4196 RTL_W8(MaxTxPacketSize, 0x3f);
4197 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4198 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004199 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004200}
4201
4202static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4203{
4204 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004205
4206 RTL_W8(MaxTxPacketSize, 0x0c);
4207 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4208 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004209 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004210}
4211
4212static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4213{
4214 rtl_tx_performance_tweak(tp->pci_dev,
4215 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4216}
4217
4218static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4219{
4220 rtl_tx_performance_tweak(tp->pci_dev,
4221 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4222}
4223
4224static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4225{
4226 void __iomem *ioaddr = tp->mmio_addr;
4227
4228 r8168b_0_hw_jumbo_enable(tp);
4229
4230 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4231}
4232
4233static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4234{
4235 void __iomem *ioaddr = tp->mmio_addr;
4236
4237 r8168b_0_hw_jumbo_disable(tp);
4238
4239 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4240}
4241
Bill Pembertonbaf63292012-12-03 09:23:28 -05004242static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
Francois Romieud58d46b2011-05-03 16:38:29 +02004243{
4244 struct jumbo_ops *ops = &tp->jumbo_ops;
4245
4246 switch (tp->mac_version) {
4247 case RTL_GIGA_MAC_VER_11:
4248 ops->disable = r8168b_0_hw_jumbo_disable;
4249 ops->enable = r8168b_0_hw_jumbo_enable;
4250 break;
4251 case RTL_GIGA_MAC_VER_12:
4252 case RTL_GIGA_MAC_VER_17:
4253 ops->disable = r8168b_1_hw_jumbo_disable;
4254 ops->enable = r8168b_1_hw_jumbo_enable;
4255 break;
4256 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4257 case RTL_GIGA_MAC_VER_19:
4258 case RTL_GIGA_MAC_VER_20:
4259 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4260 case RTL_GIGA_MAC_VER_22:
4261 case RTL_GIGA_MAC_VER_23:
4262 case RTL_GIGA_MAC_VER_24:
4263 case RTL_GIGA_MAC_VER_25:
4264 case RTL_GIGA_MAC_VER_26:
4265 ops->disable = r8168c_hw_jumbo_disable;
4266 ops->enable = r8168c_hw_jumbo_enable;
4267 break;
4268 case RTL_GIGA_MAC_VER_27:
4269 case RTL_GIGA_MAC_VER_28:
4270 ops->disable = r8168dp_hw_jumbo_disable;
4271 ops->enable = r8168dp_hw_jumbo_enable;
4272 break;
4273 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4274 case RTL_GIGA_MAC_VER_32:
4275 case RTL_GIGA_MAC_VER_33:
4276 case RTL_GIGA_MAC_VER_34:
4277 ops->disable = r8168e_hw_jumbo_disable;
4278 ops->enable = r8168e_hw_jumbo_enable;
4279 break;
4280
4281 /*
4282 * No action needed for jumbo frames with 8169.
4283 * No jumbo for 810x at all.
4284 */
Hayes Wangc5583862012-07-02 17:23:22 +08004285 case RTL_GIGA_MAC_VER_40:
4286 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004287 default:
4288 ops->disable = NULL;
4289 ops->enable = NULL;
4290 break;
4291 }
4292}
4293
Francois Romieuffc46952012-07-06 14:19:23 +02004294DECLARE_RTL_COND(rtl_chipcmd_cond)
4295{
4296 void __iomem *ioaddr = tp->mmio_addr;
4297
4298 return RTL_R8(ChipCmd) & CmdReset;
4299}
4300
Francois Romieu6f43adc2011-04-29 15:05:51 +02004301static void rtl_hw_reset(struct rtl8169_private *tp)
4302{
4303 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004304
Francois Romieu6f43adc2011-04-29 15:05:51 +02004305 RTL_W8(ChipCmd, CmdReset);
4306
Francois Romieuffc46952012-07-06 14:19:23 +02004307 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004308}
4309
Francois Romieub6ffd972011-06-17 17:00:05 +02004310static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4311{
4312 struct rtl_fw *rtl_fw;
4313 const char *name;
4314 int rc = -ENOMEM;
4315
4316 name = rtl_lookup_firmware_name(tp);
4317 if (!name)
4318 goto out_no_firmware;
4319
4320 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4321 if (!rtl_fw)
4322 goto err_warn;
4323
4324 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4325 if (rc < 0)
4326 goto err_free;
4327
Francois Romieufd112f22011-06-18 00:10:29 +02004328 rc = rtl_check_firmware(tp, rtl_fw);
4329 if (rc < 0)
4330 goto err_release_firmware;
4331
Francois Romieub6ffd972011-06-17 17:00:05 +02004332 tp->rtl_fw = rtl_fw;
4333out:
4334 return;
4335
Francois Romieufd112f22011-06-18 00:10:29 +02004336err_release_firmware:
4337 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004338err_free:
4339 kfree(rtl_fw);
4340err_warn:
4341 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4342 name, rc);
4343out_no_firmware:
4344 tp->rtl_fw = NULL;
4345 goto out;
4346}
4347
François Romieu953a12c2011-04-24 17:38:48 +02004348static void rtl_request_firmware(struct rtl8169_private *tp)
4349{
Francois Romieub6ffd972011-06-17 17:00:05 +02004350 if (IS_ERR(tp->rtl_fw))
4351 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004352}
4353
Hayes Wang92fc43b2011-07-06 15:58:03 +08004354static void rtl_rx_close(struct rtl8169_private *tp)
4355{
4356 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004357
Francois Romieu1687b562011-07-19 17:21:29 +02004358 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004359}
4360
Francois Romieuffc46952012-07-06 14:19:23 +02004361DECLARE_RTL_COND(rtl_npq_cond)
4362{
4363 void __iomem *ioaddr = tp->mmio_addr;
4364
4365 return RTL_R8(TxPoll) & NPQ;
4366}
4367
4368DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4369{
4370 void __iomem *ioaddr = tp->mmio_addr;
4371
4372 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4373}
4374
françois romieue6de30d2011-01-03 15:08:37 +00004375static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376{
françois romieue6de30d2011-01-03 15:08:37 +00004377 void __iomem *ioaddr = tp->mmio_addr;
4378
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004380 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Hayes Wang92fc43b2011-07-06 15:58:03 +08004382 rtl_rx_close(tp);
4383
Hayes Wang5d2e1952011-02-22 17:26:22 +08004384 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004385 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4386 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004387 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004388 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4389 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004390 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004391 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004392 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4393 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004394 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004395 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004396 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004397 } else {
4398 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4399 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004400 }
4401
Hayes Wang92fc43b2011-07-06 15:58:03 +08004402 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403}
4404
Francois Romieu7f796d832007-06-11 23:04:41 +02004405static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004406{
4407 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004408
4409 /* Set DMA burst size and Interframe Gap Time */
4410 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4411 (InterFrameGap << TxInterFrameGapShift));
4412}
4413
Francois Romieu07ce4062007-02-23 23:36:39 +01004414static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415{
4416 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Francois Romieu07ce4062007-02-23 23:36:39 +01004418 tp->hw_start(dev);
4419
Francois Romieuda78dbf2012-01-26 14:18:23 +01004420 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004421}
4422
Francois Romieu7f796d832007-06-11 23:04:41 +02004423static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4424 void __iomem *ioaddr)
4425{
4426 /*
4427 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4428 * register to be written before TxDescAddrLow to work.
4429 * Switching from MMIO to I/O access fixes the issue as well.
4430 */
4431 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004432 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004433 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004434 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004435}
4436
4437static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4438{
4439 u16 cmd;
4440
4441 cmd = RTL_R16(CPlusCmd);
4442 RTL_W16(CPlusCmd, cmd);
4443 return cmd;
4444}
4445
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004446static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004447{
4448 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e82009-10-26 10:52:37 +00004449 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004450}
4451
Francois Romieu6dccd162007-02-13 23:38:05 +01004452static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4453{
Francois Romieu37441002011-06-17 22:58:54 +02004454 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004455 u32 mac_version;
4456 u32 clk;
4457 u32 val;
4458 } cfg2_info [] = {
4459 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4460 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4461 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4462 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004463 };
4464 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004465 unsigned int i;
4466 u32 clk;
4467
4468 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004469 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004470 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4471 RTL_W32(0x7c, p->val);
4472 break;
4473 }
4474 }
4475}
4476
Francois Romieue6b763e2012-03-08 09:35:39 +01004477static void rtl_set_rx_mode(struct net_device *dev)
4478{
4479 struct rtl8169_private *tp = netdev_priv(dev);
4480 void __iomem *ioaddr = tp->mmio_addr;
4481 u32 mc_filter[2]; /* Multicast hash filter */
4482 int rx_mode;
4483 u32 tmp = 0;
4484
4485 if (dev->flags & IFF_PROMISC) {
4486 /* Unconditionally log net taps. */
4487 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4488 rx_mode =
4489 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4490 AcceptAllPhys;
4491 mc_filter[1] = mc_filter[0] = 0xffffffff;
4492 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4493 (dev->flags & IFF_ALLMULTI)) {
4494 /* Too many to filter perfectly -- accept all multicasts. */
4495 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4496 mc_filter[1] = mc_filter[0] = 0xffffffff;
4497 } else {
4498 struct netdev_hw_addr *ha;
4499
4500 rx_mode = AcceptBroadcast | AcceptMyPhys;
4501 mc_filter[1] = mc_filter[0] = 0;
4502 netdev_for_each_mc_addr(ha, dev) {
4503 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4504 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4505 rx_mode |= AcceptMulticast;
4506 }
4507 }
4508
4509 if (dev->features & NETIF_F_RXALL)
4510 rx_mode |= (AcceptErr | AcceptRunt);
4511
4512 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4513
4514 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4515 u32 data = mc_filter[0];
4516
4517 mc_filter[0] = swab32(mc_filter[1]);
4518 mc_filter[1] = swab32(data);
4519 }
4520
Nathan Walp04817762012-11-01 12:08:47 +00004521 if (tp->mac_version == RTL_GIGA_MAC_VER_35)
4522 mc_filter[1] = mc_filter[0] = 0xffffffff;
4523
Francois Romieue6b763e2012-03-08 09:35:39 +01004524 RTL_W32(MAR0 + 4, mc_filter[1]);
4525 RTL_W32(MAR0 + 0, mc_filter[0]);
4526
4527 RTL_W32(RxConfig, tmp);
4528}
4529
Francois Romieu07ce4062007-02-23 23:36:39 +01004530static void rtl_hw_start_8169(struct net_device *dev)
4531{
4532 struct rtl8169_private *tp = netdev_priv(dev);
4533 void __iomem *ioaddr = tp->mmio_addr;
4534 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004535
Francois Romieu9cb427b2006-11-02 00:10:16 +01004536 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4537 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4538 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4539 }
4540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004542 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4543 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4544 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4545 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004546 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4547
Hayes Wange542a222011-07-06 15:58:04 +08004548 rtl_init_rxcfg(tp);
4549
françois romieuf0298f82011-01-03 15:07:42 +00004550 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004552 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553
Francois Romieucecb5fd2011-04-01 10:21:07 +02004554 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4555 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4556 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4557 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004558 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559
Francois Romieu7f796d832007-06-11 23:04:41 +02004560 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004561
Francois Romieucecb5fd2011-04-01 10:21:07 +02004562 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4563 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004564 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004566 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 }
4568
Francois Romieubcf0bf92006-07-26 23:14:13 +02004569 RTL_W16(CPlusCmd, tp->cp_cmd);
4570
Francois Romieu6dccd162007-02-13 23:38:05 +01004571 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4572
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 /*
4574 * Undocumented corner. Supposedly:
4575 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4576 */
4577 RTL_W16(IntrMitigate, 0x0000);
4578
Francois Romieu7f796d832007-06-11 23:04:41 +02004579 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004580
Francois Romieucecb5fd2011-04-01 10:21:07 +02004581 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4582 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4583 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4584 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004585 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4586 rtl_set_rx_tx_config_registers(tp);
4587 }
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004590
4591 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4592 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593
4594 RTL_W32(RxMissed, 0);
4595
Francois Romieu07ce4062007-02-23 23:36:39 +01004596 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597
4598 /* no early-rx interrupts */
4599 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004600}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004602static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4603{
4604 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004605 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004606}
4607
4608static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4609{
Francois Romieu52989f02012-07-06 13:37:00 +02004610 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004611}
4612
4613static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004614{
4615 u32 csi;
4616
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004617 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4618 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004619}
4620
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004621static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004622{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004623 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004624}
4625
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004626static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004627{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004628 rtl_csi_access_enable(tp, 0x27000000);
4629}
4630
Francois Romieuffc46952012-07-06 14:19:23 +02004631DECLARE_RTL_COND(rtl_csiar_cond)
4632{
4633 void __iomem *ioaddr = tp->mmio_addr;
4634
4635 return RTL_R32(CSIAR) & CSIAR_FLAG;
4636}
4637
Francois Romieu52989f02012-07-06 13:37:00 +02004638static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004639{
Francois Romieu52989f02012-07-06 13:37:00 +02004640 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004641
4642 RTL_W32(CSIDR, value);
4643 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4644 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4645
Francois Romieuffc46952012-07-06 14:19:23 +02004646 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004647}
4648
Francois Romieu52989f02012-07-06 13:37:00 +02004649static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004650{
Francois Romieu52989f02012-07-06 13:37:00 +02004651 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004652
4653 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4654 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4655
Francois Romieuffc46952012-07-06 14:19:23 +02004656 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4657 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004658}
4659
Francois Romieu52989f02012-07-06 13:37:00 +02004660static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004661{
Francois Romieu52989f02012-07-06 13:37:00 +02004662 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004663
4664 RTL_W32(CSIDR, value);
4665 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4666 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4667 CSIAR_FUNC_NIC);
4668
Francois Romieuffc46952012-07-06 14:19:23 +02004669 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004670}
4671
Francois Romieu52989f02012-07-06 13:37:00 +02004672static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004673{
Francois Romieu52989f02012-07-06 13:37:00 +02004674 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004675
4676 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4677 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4678
Francois Romieuffc46952012-07-06 14:19:23 +02004679 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4680 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004681}
4682
Bill Pembertonbaf63292012-12-03 09:23:28 -05004683static void rtl_init_csi_ops(struct rtl8169_private *tp)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004684{
4685 struct csi_ops *ops = &tp->csi_ops;
4686
4687 switch (tp->mac_version) {
4688 case RTL_GIGA_MAC_VER_01:
4689 case RTL_GIGA_MAC_VER_02:
4690 case RTL_GIGA_MAC_VER_03:
4691 case RTL_GIGA_MAC_VER_04:
4692 case RTL_GIGA_MAC_VER_05:
4693 case RTL_GIGA_MAC_VER_06:
4694 case RTL_GIGA_MAC_VER_10:
4695 case RTL_GIGA_MAC_VER_11:
4696 case RTL_GIGA_MAC_VER_12:
4697 case RTL_GIGA_MAC_VER_13:
4698 case RTL_GIGA_MAC_VER_14:
4699 case RTL_GIGA_MAC_VER_15:
4700 case RTL_GIGA_MAC_VER_16:
4701 case RTL_GIGA_MAC_VER_17:
4702 ops->write = NULL;
4703 ops->read = NULL;
4704 break;
4705
Hayes Wang7e18dca2012-03-30 14:33:02 +08004706 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004707 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004708 ops->write = r8402_csi_write;
4709 ops->read = r8402_csi_read;
4710 break;
4711
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004712 default:
4713 ops->write = r8169_csi_write;
4714 ops->read = r8169_csi_read;
4715 break;
4716 }
Francois Romieudacf8152008-08-02 20:44:13 +02004717}
4718
4719struct ephy_info {
4720 unsigned int offset;
4721 u16 mask;
4722 u16 bits;
4723};
4724
Francois Romieufdf6fc02012-07-06 22:40:38 +02004725static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4726 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004727{
4728 u16 w;
4729
4730 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004731 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4732 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004733 e++;
4734 }
4735}
4736
Francois Romieub726e492008-06-28 12:22:59 +02004737static void rtl_disable_clock_request(struct pci_dev *pdev)
4738{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004739 pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
4740 PCI_EXP_LNKCTL_CLKREQ_EN);
Francois Romieub726e492008-06-28 12:22:59 +02004741}
4742
françois romieue6de30d2011-01-03 15:08:37 +00004743static void rtl_enable_clock_request(struct pci_dev *pdev)
4744{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004745 pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
4746 PCI_EXP_LNKCTL_CLKREQ_EN);
françois romieue6de30d2011-01-03 15:08:37 +00004747}
4748
Francois Romieub726e492008-06-28 12:22:59 +02004749#define R8168_CPCMD_QUIRK_MASK (\
4750 EnableBist | \
4751 Mac_dbgo_oe | \
4752 Force_half_dup | \
4753 Force_rxflow_en | \
4754 Force_txflow_en | \
4755 Cxpl_dbg_sel | \
4756 ASF | \
4757 PktCntrDisable | \
4758 Mac_dbgo_sel)
4759
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004760static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004761{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004762 void __iomem *ioaddr = tp->mmio_addr;
4763 struct pci_dev *pdev = tp->pci_dev;
4764
Francois Romieub726e492008-06-28 12:22:59 +02004765 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4766
4767 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4768
Francois Romieu2e68ae42008-06-28 12:00:55 +02004769 rtl_tx_performance_tweak(pdev,
4770 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004771}
4772
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004773static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004774{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004775 void __iomem *ioaddr = tp->mmio_addr;
4776
4777 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004778
françois romieuf0298f82011-01-03 15:07:42 +00004779 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004780
4781 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004782}
4783
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004784static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004785{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004786 void __iomem *ioaddr = tp->mmio_addr;
4787 struct pci_dev *pdev = tp->pci_dev;
4788
Francois Romieub726e492008-06-28 12:22:59 +02004789 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4790
4791 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4792
Francois Romieu219a1e92008-06-28 11:58:39 +02004793 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004794
4795 rtl_disable_clock_request(pdev);
4796
4797 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004798}
4799
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004800static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004801{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004802 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004803 { 0x01, 0, 0x0001 },
4804 { 0x02, 0x0800, 0x1000 },
4805 { 0x03, 0, 0x0042 },
4806 { 0x06, 0x0080, 0x0000 },
4807 { 0x07, 0, 0x2000 }
4808 };
4809
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004810 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004811
Francois Romieufdf6fc02012-07-06 22:40:38 +02004812 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004813
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004814 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004815}
4816
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004817static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004818{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004819 void __iomem *ioaddr = tp->mmio_addr;
4820 struct pci_dev *pdev = tp->pci_dev;
4821
4822 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004823
4824 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4825
4826 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4827
4828 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4829}
4830
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004831static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004832{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004833 void __iomem *ioaddr = tp->mmio_addr;
4834 struct pci_dev *pdev = tp->pci_dev;
4835
4836 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004837
4838 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4839
4840 /* Magic. */
4841 RTL_W8(DBG_REG, 0x20);
4842
françois romieuf0298f82011-01-03 15:07:42 +00004843 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004844
4845 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4846
4847 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4848}
4849
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004850static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004851{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004852 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004853 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004854 { 0x02, 0x0800, 0x1000 },
4855 { 0x03, 0, 0x0002 },
4856 { 0x06, 0x0080, 0x0000 }
4857 };
4858
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004859 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004860
4861 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4862
Francois Romieufdf6fc02012-07-06 22:40:38 +02004863 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004864
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004865 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004866}
4867
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004868static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004869{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004870 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004871 { 0x01, 0, 0x0001 },
4872 { 0x03, 0x0400, 0x0220 }
4873 };
4874
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004875 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004876
Francois Romieufdf6fc02012-07-06 22:40:38 +02004877 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004878
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004879 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004880}
4881
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004882static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004883{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004884 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004885}
4886
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004887static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004888{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004889 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004890
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004891 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004892}
4893
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004894static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004895{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004896 void __iomem *ioaddr = tp->mmio_addr;
4897 struct pci_dev *pdev = tp->pci_dev;
4898
4899 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004900
4901 rtl_disable_clock_request(pdev);
4902
françois romieuf0298f82011-01-03 15:07:42 +00004903 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004904
4905 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4906
4907 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4908}
4909
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004910static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004911{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004912 void __iomem *ioaddr = tp->mmio_addr;
4913 struct pci_dev *pdev = tp->pci_dev;
4914
4915 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004916
4917 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4918
4919 RTL_W8(MaxTxPacketSize, TxPacketMax);
4920
4921 rtl_disable_clock_request(pdev);
4922}
4923
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004924static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004925{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004926 void __iomem *ioaddr = tp->mmio_addr;
4927 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004928 static const struct ephy_info e_info_8168d_4[] = {
4929 { 0x0b, ~0, 0x48 },
4930 { 0x19, 0x20, 0x50 },
4931 { 0x0c, ~0, 0x20 }
4932 };
4933 int i;
4934
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004935 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004936
4937 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4938
4939 RTL_W8(MaxTxPacketSize, TxPacketMax);
4940
4941 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4942 const struct ephy_info *e = e_info_8168d_4 + i;
4943 u16 w;
4944
Francois Romieufdf6fc02012-07-06 22:40:38 +02004945 w = rtl_ephy_read(tp, e->offset);
4946 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004947 }
4948
4949 rtl_enable_clock_request(pdev);
4950}
4951
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004952static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004953{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004954 void __iomem *ioaddr = tp->mmio_addr;
4955 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004956 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004957 { 0x00, 0x0200, 0x0100 },
4958 { 0x00, 0x0000, 0x0004 },
4959 { 0x06, 0x0002, 0x0001 },
4960 { 0x06, 0x0000, 0x0030 },
4961 { 0x07, 0x0000, 0x2000 },
4962 { 0x00, 0x0000, 0x0020 },
4963 { 0x03, 0x5800, 0x2000 },
4964 { 0x03, 0x0000, 0x0001 },
4965 { 0x01, 0x0800, 0x1000 },
4966 { 0x07, 0x0000, 0x4000 },
4967 { 0x1e, 0x0000, 0x2000 },
4968 { 0x19, 0xffff, 0xfe6c },
4969 { 0x0a, 0x0000, 0x0040 }
4970 };
4971
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004972 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00004973
Francois Romieufdf6fc02012-07-06 22:40:38 +02004974 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00004975
4976 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4977
4978 RTL_W8(MaxTxPacketSize, TxPacketMax);
4979
4980 rtl_disable_clock_request(pdev);
4981
4982 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02004983 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
4984 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00004985
Francois Romieucecb5fd2011-04-01 10:21:07 +02004986 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00004987}
4988
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004989static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08004990{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004991 void __iomem *ioaddr = tp->mmio_addr;
4992 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004993 static const struct ephy_info e_info_8168e_2[] = {
4994 { 0x09, 0x0000, 0x0080 },
4995 { 0x19, 0x0000, 0x0224 }
4996 };
4997
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004998 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08004999
Francois Romieufdf6fc02012-07-06 22:40:38 +02005000 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08005001
5002 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5003
Francois Romieufdf6fc02012-07-06 22:40:38 +02005004 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5005 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5006 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5007 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5008 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5009 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5010 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5011 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005012
Hayes Wang3090bd92011-09-06 16:55:15 +08005013 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005014
Francois Romieu4521e1a92012-11-01 16:46:28 +00005015 rtl_disable_clock_request(pdev);
5016
Hayes Wang70090422011-07-06 15:58:06 +08005017 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5018 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5019
5020 /* Adjust EEE LED frequency */
5021 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5022
5023 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5024 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
Francois Romieu4521e1a92012-11-01 16:46:28 +00005025 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
Hayes Wang70090422011-07-06 15:58:06 +08005026}
5027
Hayes Wang5f886e02012-03-30 14:33:03 +08005028static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005029{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005030 void __iomem *ioaddr = tp->mmio_addr;
5031 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005032
Hayes Wang5f886e02012-03-30 14:33:03 +08005033 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005034
5035 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5036
Francois Romieufdf6fc02012-07-06 22:40:38 +02005037 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5038 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5039 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5040 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5041 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5042 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5043 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5044 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5045 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5046 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005047
5048 RTL_W8(MaxTxPacketSize, EarlySize);
5049
Francois Romieu4521e1a92012-11-01 16:46:28 +00005050 rtl_disable_clock_request(pdev);
5051
Hayes Wangc2218922011-09-06 16:55:18 +08005052 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5053 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005054 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Francois Romieu4521e1a92012-11-01 16:46:28 +00005055 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5056 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
Hayes Wangc2218922011-09-06 16:55:18 +08005057}
5058
Hayes Wang5f886e02012-03-30 14:33:03 +08005059static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5060{
5061 void __iomem *ioaddr = tp->mmio_addr;
5062 static const struct ephy_info e_info_8168f_1[] = {
5063 { 0x06, 0x00c0, 0x0020 },
5064 { 0x08, 0x0001, 0x0002 },
5065 { 0x09, 0x0000, 0x0080 },
5066 { 0x19, 0x0000, 0x0224 }
5067 };
5068
5069 rtl_hw_start_8168f(tp);
5070
Francois Romieufdf6fc02012-07-06 22:40:38 +02005071 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005072
Francois Romieufdf6fc02012-07-06 22:40:38 +02005073 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005074
5075 /* Adjust EEE LED frequency */
5076 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5077}
5078
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005079static void rtl_hw_start_8411(struct rtl8169_private *tp)
5080{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005081 static const struct ephy_info e_info_8168f_1[] = {
5082 { 0x06, 0x00c0, 0x0020 },
5083 { 0x0f, 0xffff, 0x5200 },
5084 { 0x1e, 0x0000, 0x4000 },
5085 { 0x19, 0x0000, 0x0224 }
5086 };
5087
5088 rtl_hw_start_8168f(tp);
5089
Francois Romieufdf6fc02012-07-06 22:40:38 +02005090 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005091
Francois Romieufdf6fc02012-07-06 22:40:38 +02005092 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005093}
5094
Hayes Wangc5583862012-07-02 17:23:22 +08005095static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5096{
5097 void __iomem *ioaddr = tp->mmio_addr;
5098 struct pci_dev *pdev = tp->pci_dev;
5099
5100 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5101 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5102 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5103 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5104
5105 rtl_csi_access_enable_1(tp);
5106
5107 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5108
5109 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5110 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5111
5112 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
Francois Romieu4521e1a92012-11-01 16:46:28 +00005113 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
Hayes Wangc5583862012-07-02 17:23:22 +08005114 RTL_W8(MaxTxPacketSize, EarlySize);
5115
5116 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5117 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5118
5119 /* Adjust EEE LED frequency */
5120 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5121
5122 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5123}
5124
Francois Romieu07ce4062007-02-23 23:36:39 +01005125static void rtl_hw_start_8168(struct net_device *dev)
5126{
Francois Romieu2dd99532007-06-11 23:22:52 +02005127 struct rtl8169_private *tp = netdev_priv(dev);
5128 void __iomem *ioaddr = tp->mmio_addr;
5129
5130 RTL_W8(Cfg9346, Cfg9346_Unlock);
5131
françois romieuf0298f82011-01-03 15:07:42 +00005132 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005133
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005134 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005135
Francois Romieu0e485152007-02-20 00:00:26 +01005136 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005137
5138 RTL_W16(CPlusCmd, tp->cp_cmd);
5139
Francois Romieu0e485152007-02-20 00:00:26 +01005140 RTL_W16(IntrMitigate, 0x5151);
5141
5142 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005143 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005144 tp->event_slow |= RxFIFOOver | PCSTimeout;
5145 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005146 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005147
5148 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5149
Francois Romieub8363902008-06-01 12:31:57 +02005150 rtl_set_rx_mode(dev);
5151
5152 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5153 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005154
5155 RTL_R8(IntrMask);
5156
Francois Romieu219a1e92008-06-28 11:58:39 +02005157 switch (tp->mac_version) {
5158 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005159 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005160 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005161
5162 case RTL_GIGA_MAC_VER_12:
5163 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005164 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005165 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005166
5167 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005168 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005169 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005170
5171 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005172 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005173 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005174
5175 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005176 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005177 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005178
Francois Romieu197ff762008-06-28 13:16:02 +02005179 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005180 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005181 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005182
Francois Romieu6fb07052008-06-29 11:54:28 +02005183 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005184 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005185 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005186
Francois Romieuef3386f2008-06-29 12:24:30 +02005187 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005188 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005189 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005190
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005191 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005192 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005193 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005194
Francois Romieu5b538df2008-07-20 16:22:45 +02005195 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005196 case RTL_GIGA_MAC_VER_26:
5197 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005198 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005199 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005200
françois romieue6de30d2011-01-03 15:08:37 +00005201 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005202 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005203 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005204
hayeswang4804b3b2011-03-21 01:50:29 +00005205 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005206 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005207 break;
5208
hayeswang01dc7fe2011-03-21 01:50:28 +00005209 case RTL_GIGA_MAC_VER_32:
5210 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005211 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005212 break;
5213 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005214 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005215 break;
françois romieue6de30d2011-01-03 15:08:37 +00005216
Hayes Wangc2218922011-09-06 16:55:18 +08005217 case RTL_GIGA_MAC_VER_35:
5218 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005219 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005220 break;
5221
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005222 case RTL_GIGA_MAC_VER_38:
5223 rtl_hw_start_8411(tp);
5224 break;
5225
Hayes Wangc5583862012-07-02 17:23:22 +08005226 case RTL_GIGA_MAC_VER_40:
5227 case RTL_GIGA_MAC_VER_41:
5228 rtl_hw_start_8168g_1(tp);
5229 break;
5230
Francois Romieu219a1e92008-06-28 11:58:39 +02005231 default:
5232 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5233 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005234 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005235 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005236
Francois Romieu0e485152007-02-20 00:00:26 +01005237 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5238
Francois Romieub8363902008-06-01 12:31:57 +02005239 RTL_W8(Cfg9346, Cfg9346_Lock);
5240
Francois Romieu2dd99532007-06-11 23:22:52 +02005241 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005242}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243
Francois Romieu2857ffb2008-08-02 21:08:49 +02005244#define R810X_CPCMD_QUIRK_MASK (\
5245 EnableBist | \
5246 Mac_dbgo_oe | \
5247 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005248 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005249 Force_txflow_en | \
5250 Cxpl_dbg_sel | \
5251 ASF | \
5252 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005253 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005254
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005255static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005256{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005257 void __iomem *ioaddr = tp->mmio_addr;
5258 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005259 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005260 { 0x01, 0, 0x6e65 },
5261 { 0x02, 0, 0x091f },
5262 { 0x03, 0, 0xc2f9 },
5263 { 0x06, 0, 0xafb5 },
5264 { 0x07, 0, 0x0e00 },
5265 { 0x19, 0, 0xec80 },
5266 { 0x01, 0, 0x2e65 },
5267 { 0x01, 0, 0x6e65 }
5268 };
5269 u8 cfg1;
5270
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005271 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005272
5273 RTL_W8(DBG_REG, FIX_NAK_1);
5274
5275 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5276
5277 RTL_W8(Config1,
5278 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5279 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5280
5281 cfg1 = RTL_R8(Config1);
5282 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5283 RTL_W8(Config1, cfg1 & ~LEDS0);
5284
Francois Romieufdf6fc02012-07-06 22:40:38 +02005285 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005286}
5287
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005288static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005289{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005290 void __iomem *ioaddr = tp->mmio_addr;
5291 struct pci_dev *pdev = tp->pci_dev;
5292
5293 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005294
5295 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5296
5297 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5298 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005299}
5300
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005301static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005302{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005303 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005304
Francois Romieufdf6fc02012-07-06 22:40:38 +02005305 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005306}
5307
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005308static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005309{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005310 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005311 static const struct ephy_info e_info_8105e_1[] = {
5312 { 0x07, 0, 0x4000 },
5313 { 0x19, 0, 0x0200 },
5314 { 0x19, 0, 0x0020 },
5315 { 0x1e, 0, 0x2000 },
5316 { 0x03, 0, 0x0001 },
5317 { 0x19, 0, 0x0100 },
5318 { 0x19, 0, 0x0004 },
5319 { 0x0a, 0, 0x0020 }
5320 };
5321
Francois Romieucecb5fd2011-04-01 10:21:07 +02005322 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005323 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5324
Francois Romieucecb5fd2011-04-01 10:21:07 +02005325 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005326 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5327
5328 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e2011-07-06 15:58:02 +08005329 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005330
Francois Romieufdf6fc02012-07-06 22:40:38 +02005331 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005332}
5333
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005334static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005335{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005336 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005337 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005338}
5339
Hayes Wang7e18dca2012-03-30 14:33:02 +08005340static void rtl_hw_start_8402(struct rtl8169_private *tp)
5341{
5342 void __iomem *ioaddr = tp->mmio_addr;
5343 static const struct ephy_info e_info_8402[] = {
5344 { 0x19, 0xffff, 0xff64 },
5345 { 0x1e, 0, 0x4000 }
5346 };
5347
5348 rtl_csi_access_enable_2(tp);
5349
5350 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5351 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5352
5353 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5354 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5355
Francois Romieufdf6fc02012-07-06 22:40:38 +02005356 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005357
5358 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5359
Francois Romieufdf6fc02012-07-06 22:40:38 +02005360 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5361 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5362 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5363 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5364 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5365 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5366 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005367}
5368
Hayes Wang5598bfe2012-07-02 17:23:21 +08005369static void rtl_hw_start_8106(struct rtl8169_private *tp)
5370{
5371 void __iomem *ioaddr = tp->mmio_addr;
5372
5373 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5374 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5375
Francois Romieu4521e1a92012-11-01 16:46:28 +00005376 RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
Hayes Wang5598bfe2012-07-02 17:23:21 +08005377 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5378 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5379}
5380
Francois Romieu07ce4062007-02-23 23:36:39 +01005381static void rtl_hw_start_8101(struct net_device *dev)
5382{
Francois Romieucdf1a602007-06-11 23:29:50 +02005383 struct rtl8169_private *tp = netdev_priv(dev);
5384 void __iomem *ioaddr = tp->mmio_addr;
5385 struct pci_dev *pdev = tp->pci_dev;
5386
Francois Romieuda78dbf2012-01-26 14:18:23 +01005387 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5388 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005389
Francois Romieucecb5fd2011-04-01 10:21:07 +02005390 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
Jiang Liu7d7903b2012-07-24 17:20:16 +08005391 tp->mac_version == RTL_GIGA_MAC_VER_16)
Bjorn Helgaas8200bc72012-08-22 10:29:42 -06005392 pcie_capability_set_word(pdev, PCI_EXP_DEVCTL,
5393 PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieucdf1a602007-06-11 23:29:50 +02005394
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005395 RTL_W8(Cfg9346, Cfg9346_Unlock);
5396
Francois Romieu2857ffb2008-08-02 21:08:49 +02005397 switch (tp->mac_version) {
5398 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005399 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005400 break;
5401
5402 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005403 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005404 break;
5405
5406 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005407 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005408 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005409
5410 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005411 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005412 break;
5413 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005414 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005415 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005416
5417 case RTL_GIGA_MAC_VER_37:
5418 rtl_hw_start_8402(tp);
5419 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005420
5421 case RTL_GIGA_MAC_VER_39:
5422 rtl_hw_start_8106(tp);
5423 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005424 }
5425
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005426 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005427
françois romieuf0298f82011-01-03 15:07:42 +00005428 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005429
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005430 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005431
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005432 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005433 RTL_W16(CPlusCmd, tp->cp_cmd);
5434
5435 RTL_W16(IntrMitigate, 0x0000);
5436
5437 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5438
5439 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5440 rtl_set_rx_tx_config_registers(tp);
5441
Francois Romieucdf1a602007-06-11 23:29:50 +02005442 RTL_R8(IntrMask);
5443
Francois Romieucdf1a602007-06-11 23:29:50 +02005444 rtl_set_rx_mode(dev);
5445
5446 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447}
5448
5449static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5450{
Francois Romieud58d46b2011-05-03 16:38:29 +02005451 struct rtl8169_private *tp = netdev_priv(dev);
5452
5453 if (new_mtu < ETH_ZLEN ||
5454 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 return -EINVAL;
5456
Francois Romieud58d46b2011-05-03 16:38:29 +02005457 if (new_mtu > ETH_DATA_LEN)
5458 rtl_hw_jumbo_enable(tp);
5459 else
5460 rtl_hw_jumbo_disable(tp);
5461
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005463 netdev_update_features(dev);
5464
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005465 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466}
5467
5468static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5469{
Al Viro95e09182007-12-22 18:55:39 +00005470 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5472}
5473
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005474static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5475 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005477 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005478 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005479
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005480 kfree(*data_buff);
5481 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 rtl8169_make_unusable_by_asic(desc);
5483}
5484
5485static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5486{
5487 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5488
5489 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5490}
5491
5492static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5493 u32 rx_buf_sz)
5494{
5495 desc->addr = cpu_to_le64(mapping);
5496 wmb();
5497 rtl8169_mark_to_asic(desc, rx_buf_sz);
5498}
5499
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005500static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005502 return (void *)ALIGN((long)data, 16);
5503}
5504
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005505static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5506 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005507{
5508 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005510 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005511 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005512 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005514 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5515 if (!data)
5516 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005517
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005518 if (rtl8169_align(data) != data) {
5519 kfree(data);
5520 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5521 if (!data)
5522 return NULL;
5523 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005524
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005525 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005526 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005527 if (unlikely(dma_mapping_error(d, mapping))) {
5528 if (net_ratelimit())
5529 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005530 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532
5533 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005534 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005535
5536err_out:
5537 kfree(data);
5538 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539}
5540
5541static void rtl8169_rx_clear(struct rtl8169_private *tp)
5542{
Francois Romieu07d3f512007-02-21 22:40:46 +01005543 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
5545 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005546 if (tp->Rx_databuff[i]) {
5547 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 tp->RxDescArray + i);
5549 }
5550 }
5551}
5552
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005553static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005555 desc->opts1 |= cpu_to_le32(RingEnd);
5556}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005557
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005558static int rtl8169_rx_fill(struct rtl8169_private *tp)
5559{
5560 unsigned int i;
5561
5562 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005563 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005564
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005565 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005567
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005568 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005569 if (!data) {
5570 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005571 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005572 }
5573 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005576 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5577 return 0;
5578
5579err_out:
5580 rtl8169_rx_clear(tp);
5581 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582}
5583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584static int rtl8169_init_ring(struct net_device *dev)
5585{
5586 struct rtl8169_private *tp = netdev_priv(dev);
5587
5588 rtl8169_init_ring_indexes(tp);
5589
5590 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005591 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005593 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594}
5595
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005596static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 struct TxDesc *desc)
5598{
5599 unsigned int len = tx_skb->len;
5600
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005601 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5602
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 desc->opts1 = 0x00;
5604 desc->opts2 = 0x00;
5605 desc->addr = 0x00;
5606 tx_skb->len = 0;
5607}
5608
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005609static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5610 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611{
5612 unsigned int i;
5613
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005614 for (i = 0; i < n; i++) {
5615 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 struct ring_info *tx_skb = tp->tx_skb + entry;
5617 unsigned int len = tx_skb->len;
5618
5619 if (len) {
5620 struct sk_buff *skb = tx_skb->skb;
5621
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005622 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 tp->TxDescArray + entry);
5624 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005625 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 dev_kfree_skb(skb);
5627 tx_skb->skb = NULL;
5628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 }
5630 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005631}
5632
5633static void rtl8169_tx_clear(struct rtl8169_private *tp)
5634{
5635 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 tp->cur_tx = tp->dirty_tx = 0;
5637}
5638
Francois Romieu4422bcd2012-01-26 11:23:32 +01005639static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640{
David Howellsc4028952006-11-22 14:57:56 +00005641 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005642 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
Francois Romieuda78dbf2012-01-26 14:18:23 +01005644 napi_disable(&tp->napi);
5645 netif_stop_queue(dev);
5646 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647
françois romieuc7c2c392011-12-04 20:30:52 +00005648 rtl8169_hw_reset(tp);
5649
Francois Romieu56de4142011-03-15 17:29:31 +01005650 for (i = 0; i < NUM_RX_DESC; i++)
5651 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5652
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005654 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655
Francois Romieuda78dbf2012-01-26 14:18:23 +01005656 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005657 rtl_hw_start(dev);
5658 netif_wake_queue(dev);
5659 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660}
5661
5662static void rtl8169_tx_timeout(struct net_device *dev)
5663{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005664 struct rtl8169_private *tp = netdev_priv(dev);
5665
5666 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667}
5668
5669static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005670 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671{
5672 struct skb_shared_info *info = skb_shinfo(skb);
5673 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005674 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005675 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
5677 entry = tp->cur_tx;
5678 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005679 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 dma_addr_t mapping;
5681 u32 status, len;
5682 void *addr;
5683
5684 entry = (entry + 1) % NUM_TX_DESC;
5685
5686 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005687 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005688 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005689 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005690 if (unlikely(dma_mapping_error(d, mapping))) {
5691 if (net_ratelimit())
5692 netif_err(tp, drv, tp->dev,
5693 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005694 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696
Francois Romieucecb5fd2011-04-01 10:21:07 +02005697 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005698 status = opts[0] | len |
5699 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
5701 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005702 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 txd->addr = cpu_to_le64(mapping);
5704
5705 tp->tx_skb[entry].len = len;
5706 }
5707
5708 if (cur_frag) {
5709 tp->tx_skb[entry].skb = skb;
5710 txd->opts1 |= cpu_to_le32(LastFrag);
5711 }
5712
5713 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005714
5715err_out:
5716 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5717 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718}
5719
Francois Romieu2b7b4312011-04-18 22:53:24 -07005720static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5721 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005723 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005724 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005725 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
Francois Romieu2b7b4312011-04-18 22:53:24 -07005727 if (mss) {
5728 opts[0] |= TD_LSO;
5729 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5730 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005731 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
5733 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005734 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005736 opts[offset] |= info->checksum.udp;
5737 else
5738 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740}
5741
Stephen Hemminger613573252009-08-31 19:50:58 +00005742static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5743 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744{
5745 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005746 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747 struct TxDesc *txd = tp->TxDescArray + entry;
5748 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005749 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 dma_addr_t mapping;
5751 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005752 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005753 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005754
Julien Ducourthial477206a2012-05-09 00:00:06 +02005755 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005756 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005757 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758 }
5759
5760 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005761 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005763 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005764 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005765 if (unlikely(dma_mapping_error(d, mapping))) {
5766 if (net_ratelimit())
5767 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005768 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770
5771 tp->tx_skb[entry].len = len;
5772 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Kirill Smelkov810f4892012-11-10 21:11:02 +04005774 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb));
Francois Romieu2b7b4312011-04-18 22:53:24 -07005775 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005776
Francois Romieu2b7b4312011-04-18 22:53:24 -07005777 rtl8169_tso_csum(tp, skb, opts);
5778
5779 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005780 if (frags < 0)
5781 goto err_dma_1;
5782 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005783 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005784 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005785 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005786 tp->tx_skb[entry].skb = skb;
5787 }
5788
Francois Romieu2b7b4312011-04-18 22:53:24 -07005789 txd->opts2 = cpu_to_le32(opts[1]);
5790
Richard Cochran5047fb52012-03-10 07:29:42 +00005791 skb_tx_timestamp(skb);
5792
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 wmb();
5794
Francois Romieucecb5fd2011-04-01 10:21:07 +02005795 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005796 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797 txd->opts1 = cpu_to_le32(status);
5798
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799 tp->cur_tx += frags + 1;
5800
David Dillow4c020a92010-03-03 16:33:10 +00005801 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Francois Romieucecb5fd2011-04-01 10:21:07 +02005803 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
Francois Romieuda78dbf2012-01-26 14:18:23 +01005805 mmiowb();
5806
Julien Ducourthial477206a2012-05-09 00:00:06 +02005807 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005808 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5809 * not miss a ring update when it notices a stopped queue.
5810 */
5811 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005813 /* Sync with rtl_tx:
5814 * - publish queue status and cur_tx ring index (write barrier)
5815 * - refresh dirty_tx ring index (read barrier).
5816 * May the current thread have a pessimistic view of the ring
5817 * status and forget to wake up queue, a racing rtl_tx thread
5818 * can't.
5819 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005820 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005821 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 netif_wake_queue(dev);
5823 }
5824
Stephen Hemminger613573252009-08-31 19:50:58 +00005825 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005827err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005828 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005829err_dma_0:
5830 dev_kfree_skb(skb);
5831 dev->stats.tx_dropped++;
5832 return NETDEV_TX_OK;
5833
5834err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005836 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005837 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838}
5839
5840static void rtl8169_pcierr_interrupt(struct net_device *dev)
5841{
5842 struct rtl8169_private *tp = netdev_priv(dev);
5843 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 u16 pci_status, pci_cmd;
5845
5846 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5847 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5848
Joe Perchesbf82c182010-02-09 11:49:50 +00005849 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5850 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
5852 /*
5853 * The recovery sequence below admits a very elaborated explanation:
5854 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005855 * - I did not see what else could be done;
5856 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 *
5858 * Feel free to adjust to your needs.
5859 */
Francois Romieua27993f2006-12-18 00:04:19 +01005860 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005861 pci_cmd &= ~PCI_COMMAND_PARITY;
5862 else
5863 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5864
5865 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866
5867 pci_write_config_word(pdev, PCI_STATUS,
5868 pci_status & (PCI_STATUS_DETECTED_PARITY |
5869 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5870 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5871
5872 /* The infamous DAC f*ckup only happens at boot time */
5873 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005874 void __iomem *ioaddr = tp->mmio_addr;
5875
Joe Perchesbf82c182010-02-09 11:49:50 +00005876 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 tp->cp_cmd &= ~PCIDAC;
5878 RTL_W16(CPlusCmd, tp->cp_cmd);
5879 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 }
5881
françois romieue6de30d2011-01-03 15:08:37 +00005882 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005883
Francois Romieu98ddf982012-01-31 10:47:34 +01005884 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885}
5886
Francois Romieuda78dbf2012-01-26 14:18:23 +01005887static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888{
5889 unsigned int dirty_tx, tx_left;
5890
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 dirty_tx = tp->dirty_tx;
5892 smp_rmb();
5893 tx_left = tp->cur_tx - dirty_tx;
5894
5895 while (tx_left > 0) {
5896 unsigned int entry = dirty_tx % NUM_TX_DESC;
5897 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898 u32 status;
5899
5900 rmb();
5901 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5902 if (status & DescOwn)
5903 break;
5904
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005905 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5906 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005908 u64_stats_update_begin(&tp->tx_stats.syncp);
5909 tp->tx_stats.packets++;
5910 tp->tx_stats.bytes += tx_skb->skb->len;
5911 u64_stats_update_end(&tp->tx_stats.syncp);
5912 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 tx_skb->skb = NULL;
5914 }
5915 dirty_tx++;
5916 tx_left--;
5917 }
5918
5919 if (tp->dirty_tx != dirty_tx) {
5920 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005921 /* Sync with rtl8169_start_xmit:
5922 * - publish dirty_tx ring index (write barrier)
5923 * - refresh cur_tx ring index and queue status (read barrier)
5924 * May the current thread miss the stopped queue condition,
5925 * a racing xmit thread can only have a right view of the
5926 * ring status.
5927 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005928 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005930 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 netif_wake_queue(dev);
5932 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005933 /*
5934 * 8168 hack: TxPoll requests are lost when the Tx packets are
5935 * too close. Let's kick an extra TxPoll request when a burst
5936 * of start_xmit activity is detected (if it is not detected,
5937 * it is slow enough). -- FR
5938 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005939 if (tp->cur_tx != dirty_tx) {
5940 void __iomem *ioaddr = tp->mmio_addr;
5941
Francois Romieud78ae2d2007-08-26 20:08:19 +02005942 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 }
5945}
5946
Francois Romieu126fa4b2005-05-12 20:09:17 -04005947static inline int rtl8169_fragmented_frame(u32 status)
5948{
5949 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5950}
5951
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005952static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 u32 status = opts1 & RxProtoMask;
5955
5956 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005957 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 skb->ip_summed = CHECKSUM_UNNECESSARY;
5959 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005960 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961}
5962
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005963static struct sk_buff *rtl8169_try_rx_copy(void *data,
5964 struct rtl8169_private *tp,
5965 int pkt_size,
5966 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02005968 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005969 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005971 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005972 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005973 prefetch(data);
5974 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
5975 if (skb)
5976 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005977 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
5978
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005979 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980}
5981
Francois Romieuda78dbf2012-01-26 14:18:23 +01005982static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983{
5984 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005985 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 cur_rx = tp->cur_rx;
5988 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02005989 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
Richard Dawe4dcb7d32005-05-27 21:12:00 +02005991 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04005993 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 u32 status;
5995
5996 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04005997 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998
5999 if (status & DescOwn)
6000 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006001 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00006002 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
6003 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006004 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006006 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006008 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006009 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006010 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006011 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006012 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006013 if ((status & (RxRUNT | RxCRC)) &&
6014 !(status & (RxRWT | RxFOVF)) &&
6015 (dev->features & NETIF_F_RXALL))
6016 goto process_pkt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006018 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006019 dma_addr_t addr;
6020 int pkt_size;
6021
6022process_pkt:
6023 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006024 if (likely(!(dev->features & NETIF_F_RXFCS)))
6025 pkt_size = (status & 0x00003fff) - 4;
6026 else
6027 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028
Francois Romieu126fa4b2005-05-12 20:09:17 -04006029 /*
6030 * The driver does not support incoming fragmented
6031 * frames. They are seen as a symptom of over-mtu
6032 * sized frames.
6033 */
6034 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006035 dev->stats.rx_dropped++;
6036 dev->stats.rx_length_errors++;
françois romieuce11ff52013-01-24 13:30:06 +00006037 goto release_descriptor;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006038 }
6039
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006040 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6041 tp, pkt_size, addr);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006042 if (!skb) {
6043 dev->stats.rx_dropped++;
françois romieuce11ff52013-01-24 13:30:06 +00006044 goto release_descriptor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 }
6046
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006047 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 skb_put(skb, pkt_size);
6049 skb->protocol = eth_type_trans(skb, dev);
6050
Francois Romieu7a8fc772011-03-01 17:18:33 +01006051 rtl8169_rx_vlan_tag(desc, skb);
6052
Francois Romieu56de4142011-03-15 17:29:31 +01006053 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Junchang Wang8027aa22012-03-04 23:30:32 +01006055 u64_stats_update_begin(&tp->rx_stats.syncp);
6056 tp->rx_stats.packets++;
6057 tp->rx_stats.bytes += pkt_size;
6058 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 }
françois romieuce11ff52013-01-24 13:30:06 +00006060release_descriptor:
6061 desc->opts2 = 0;
6062 wmb();
6063 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 }
6065
6066 count = cur_rx - tp->cur_rx;
6067 tp->cur_rx = cur_rx;
6068
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006069 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
6071 return count;
6072}
6073
Francois Romieu07d3f512007-02-21 22:40:46 +01006074static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075{
Francois Romieu07d3f512007-02-21 22:40:46 +01006076 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006079 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006081 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006082 if (status && status != 0xffff) {
6083 status &= RTL_EVENT_NAPI | tp->event_slow;
6084 if (status) {
6085 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006086
Francois Romieuda78dbf2012-01-26 14:18:23 +01006087 rtl_irq_disable(tp);
6088 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 return IRQ_RETVAL(handled);
6092}
6093
Francois Romieuda78dbf2012-01-26 14:18:23 +01006094/*
6095 * Workqueue context.
6096 */
6097static void rtl_slow_event_work(struct rtl8169_private *tp)
6098{
6099 struct net_device *dev = tp->dev;
6100 u16 status;
6101
6102 status = rtl_get_events(tp) & tp->event_slow;
6103 rtl_ack_events(tp, status);
6104
6105 if (unlikely(status & RxFIFOOver)) {
6106 switch (tp->mac_version) {
6107 /* Work around for rx fifo overflow */
6108 case RTL_GIGA_MAC_VER_11:
6109 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006110 /* XXX - Hack alert. See rtl_task(). */
6111 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006112 default:
6113 break;
6114 }
6115 }
6116
6117 if (unlikely(status & SYSErr))
6118 rtl8169_pcierr_interrupt(dev);
6119
6120 if (status & LinkChg)
6121 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6122
françois romieu7dbb4912012-06-09 10:53:16 +00006123 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006124}
6125
Francois Romieu4422bcd2012-01-26 11:23:32 +01006126static void rtl_task(struct work_struct *work)
6127{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006128 static const struct {
6129 int bitnr;
6130 void (*action)(struct rtl8169_private *);
6131 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006132 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006133 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6134 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6135 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6136 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006137 struct rtl8169_private *tp =
6138 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006139 struct net_device *dev = tp->dev;
6140 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006141
Francois Romieuda78dbf2012-01-26 14:18:23 +01006142 rtl_lock_work(tp);
6143
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006144 if (!netif_running(dev) ||
6145 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006146 goto out_unlock;
6147
6148 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6149 bool pending;
6150
Francois Romieuda78dbf2012-01-26 14:18:23 +01006151 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006152 if (pending)
6153 rtl_work[i].action(tp);
6154 }
6155
6156out_unlock:
6157 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006158}
6159
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006160static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006162 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6163 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006164 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6165 int work_done= 0;
6166 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006167
Francois Romieuda78dbf2012-01-26 14:18:23 +01006168 status = rtl_get_events(tp);
6169 rtl_ack_events(tp, status & ~tp->event_slow);
6170
6171 if (status & RTL_EVENT_NAPI_RX)
6172 work_done = rtl_rx(dev, tp, (u32) budget);
6173
6174 if (status & RTL_EVENT_NAPI_TX)
6175 rtl_tx(dev, tp);
6176
6177 if (status & tp->event_slow) {
6178 enable_mask &= ~tp->event_slow;
6179
6180 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006183 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006184 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006185
Francois Romieuda78dbf2012-01-26 14:18:23 +01006186 rtl_irq_enable(tp, enable_mask);
6187 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188 }
6189
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006190 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192
Francois Romieu523a6092008-09-10 22:28:56 +02006193static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6194{
6195 struct rtl8169_private *tp = netdev_priv(dev);
6196
6197 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6198 return;
6199
6200 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6201 RTL_W32(RxMissed, 0);
6202}
6203
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204static void rtl8169_down(struct net_device *dev)
6205{
6206 struct rtl8169_private *tp = netdev_priv(dev);
6207 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Francois Romieu4876cc12011-03-11 21:07:11 +01006209 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006211 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006212 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
Hayes Wang92fc43b2011-07-06 15:58:03 +08006214 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006215 /*
6216 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006217 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6218 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006219 */
Francois Romieu523a6092008-09-10 22:28:56 +02006220 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006223 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225 rtl8169_tx_clear(tp);
6226
6227 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006228
6229 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230}
6231
6232static int rtl8169_close(struct net_device *dev)
6233{
6234 struct rtl8169_private *tp = netdev_priv(dev);
6235 struct pci_dev *pdev = tp->pci_dev;
6236
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006237 pm_runtime_get_sync(&pdev->dev);
6238
Francois Romieucecb5fd2011-04-01 10:21:07 +02006239 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006240 rtl8169_update_counters(dev);
6241
Francois Romieuda78dbf2012-01-26 14:18:23 +01006242 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006243 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006244
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006246 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006248 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006250 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6251 tp->RxPhyAddr);
6252 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6253 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 tp->TxDescArray = NULL;
6255 tp->RxDescArray = NULL;
6256
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006257 pm_runtime_put_sync(&pdev->dev);
6258
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 return 0;
6260}
6261
Francois Romieudc1c00c2012-03-08 10:06:18 +01006262#ifdef CONFIG_NET_POLL_CONTROLLER
6263static void rtl8169_netpoll(struct net_device *dev)
6264{
6265 struct rtl8169_private *tp = netdev_priv(dev);
6266
6267 rtl8169_interrupt(tp->pci_dev->irq, dev);
6268}
6269#endif
6270
Francois Romieudf43ac72012-03-08 09:48:40 +01006271static int rtl_open(struct net_device *dev)
6272{
6273 struct rtl8169_private *tp = netdev_priv(dev);
6274 void __iomem *ioaddr = tp->mmio_addr;
6275 struct pci_dev *pdev = tp->pci_dev;
6276 int retval = -ENOMEM;
6277
6278 pm_runtime_get_sync(&pdev->dev);
6279
6280 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006281 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006282 * dma_alloc_coherent provides more.
6283 */
6284 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6285 &tp->TxPhyAddr, GFP_KERNEL);
6286 if (!tp->TxDescArray)
6287 goto err_pm_runtime_put;
6288
6289 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6290 &tp->RxPhyAddr, GFP_KERNEL);
6291 if (!tp->RxDescArray)
6292 goto err_free_tx_0;
6293
6294 retval = rtl8169_init_ring(dev);
6295 if (retval < 0)
6296 goto err_free_rx_1;
6297
6298 INIT_WORK(&tp->wk.work, rtl_task);
6299
6300 smp_mb();
6301
6302 rtl_request_firmware(tp);
6303
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006304 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006305 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6306 dev->name, dev);
6307 if (retval < 0)
6308 goto err_release_fw_2;
6309
6310 rtl_lock_work(tp);
6311
6312 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6313
6314 napi_enable(&tp->napi);
6315
6316 rtl8169_init_phy(dev, tp);
6317
6318 __rtl8169_set_features(dev, dev->features);
6319
6320 rtl_pll_power_up(tp);
6321
6322 rtl_hw_start(dev);
6323
6324 netif_start_queue(dev);
6325
6326 rtl_unlock_work(tp);
6327
6328 tp->saved_wolopts = 0;
6329 pm_runtime_put_noidle(&pdev->dev);
6330
6331 rtl8169_check_link_status(dev, tp, ioaddr);
6332out:
6333 return retval;
6334
6335err_release_fw_2:
6336 rtl_release_firmware(tp);
6337 rtl8169_rx_clear(tp);
6338err_free_rx_1:
6339 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6340 tp->RxPhyAddr);
6341 tp->RxDescArray = NULL;
6342err_free_tx_0:
6343 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6344 tp->TxPhyAddr);
6345 tp->TxDescArray = NULL;
6346err_pm_runtime_put:
6347 pm_runtime_put_noidle(&pdev->dev);
6348 goto out;
6349}
6350
Junchang Wang8027aa22012-03-04 23:30:32 +01006351static struct rtnl_link_stats64 *
6352rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353{
6354 struct rtl8169_private *tp = netdev_priv(dev);
6355 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006356 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357
Francois Romieuda78dbf2012-01-26 14:18:23 +01006358 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006359 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006360
Junchang Wang8027aa22012-03-04 23:30:32 +01006361 do {
6362 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6363 stats->rx_packets = tp->rx_stats.packets;
6364 stats->rx_bytes = tp->rx_stats.bytes;
6365 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6366
6367
6368 do {
6369 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6370 stats->tx_packets = tp->tx_stats.packets;
6371 stats->tx_bytes = tp->tx_stats.bytes;
6372 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6373
6374 stats->rx_dropped = dev->stats.rx_dropped;
6375 stats->tx_dropped = dev->stats.tx_dropped;
6376 stats->rx_length_errors = dev->stats.rx_length_errors;
6377 stats->rx_errors = dev->stats.rx_errors;
6378 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6379 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6380 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6381
6382 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383}
6384
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006385static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006386{
françois romieu065c27c2011-01-03 15:08:12 +00006387 struct rtl8169_private *tp = netdev_priv(dev);
6388
Francois Romieu5d06a992006-02-23 00:47:58 +01006389 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006390 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006391
6392 netif_device_detach(dev);
6393 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006394
6395 rtl_lock_work(tp);
6396 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006397 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006398 rtl_unlock_work(tp);
6399
6400 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006401}
Francois Romieu5d06a992006-02-23 00:47:58 +01006402
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006403#ifdef CONFIG_PM
6404
6405static int rtl8169_suspend(struct device *device)
6406{
6407 struct pci_dev *pdev = to_pci_dev(device);
6408 struct net_device *dev = pci_get_drvdata(pdev);
6409
6410 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006411
Francois Romieu5d06a992006-02-23 00:47:58 +01006412 return 0;
6413}
6414
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006415static void __rtl8169_resume(struct net_device *dev)
6416{
françois romieu065c27c2011-01-03 15:08:12 +00006417 struct rtl8169_private *tp = netdev_priv(dev);
6418
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006419 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006420
6421 rtl_pll_power_up(tp);
6422
Artem Savkovcff4c162012-04-03 10:29:11 +00006423 rtl_lock_work(tp);
6424 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006425 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006426 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006427
Francois Romieu98ddf982012-01-31 10:47:34 +01006428 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006429}
6430
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006431static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006432{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006433 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006434 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006435 struct rtl8169_private *tp = netdev_priv(dev);
6436
6437 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006438
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006439 if (netif_running(dev))
6440 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006441
Francois Romieu5d06a992006-02-23 00:47:58 +01006442 return 0;
6443}
6444
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006445static int rtl8169_runtime_suspend(struct device *device)
6446{
6447 struct pci_dev *pdev = to_pci_dev(device);
6448 struct net_device *dev = pci_get_drvdata(pdev);
6449 struct rtl8169_private *tp = netdev_priv(dev);
6450
6451 if (!tp->TxDescArray)
6452 return 0;
6453
Francois Romieuda78dbf2012-01-26 14:18:23 +01006454 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006455 tp->saved_wolopts = __rtl8169_get_wol(tp);
6456 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006457 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006458
6459 rtl8169_net_suspend(dev);
6460
6461 return 0;
6462}
6463
6464static int rtl8169_runtime_resume(struct device *device)
6465{
6466 struct pci_dev *pdev = to_pci_dev(device);
6467 struct net_device *dev = pci_get_drvdata(pdev);
6468 struct rtl8169_private *tp = netdev_priv(dev);
6469
6470 if (!tp->TxDescArray)
6471 return 0;
6472
Francois Romieuda78dbf2012-01-26 14:18:23 +01006473 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006474 __rtl8169_set_wol(tp, tp->saved_wolopts);
6475 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006476 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006477
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006478 rtl8169_init_phy(dev, tp);
6479
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006480 __rtl8169_resume(dev);
6481
6482 return 0;
6483}
6484
6485static int rtl8169_runtime_idle(struct device *device)
6486{
6487 struct pci_dev *pdev = to_pci_dev(device);
6488 struct net_device *dev = pci_get_drvdata(pdev);
6489 struct rtl8169_private *tp = netdev_priv(dev);
6490
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006491 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006492}
6493
Alexey Dobriyan47145212009-12-14 18:00:08 -08006494static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006495 .suspend = rtl8169_suspend,
6496 .resume = rtl8169_resume,
6497 .freeze = rtl8169_suspend,
6498 .thaw = rtl8169_resume,
6499 .poweroff = rtl8169_suspend,
6500 .restore = rtl8169_resume,
6501 .runtime_suspend = rtl8169_runtime_suspend,
6502 .runtime_resume = rtl8169_runtime_resume,
6503 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006504};
6505
6506#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6507
6508#else /* !CONFIG_PM */
6509
6510#define RTL8169_PM_OPS NULL
6511
6512#endif /* !CONFIG_PM */
6513
David S. Miller1805b2f2011-10-24 18:18:09 -04006514static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6515{
6516 void __iomem *ioaddr = tp->mmio_addr;
6517
6518 /* WoL fails with 8168b when the receiver is disabled. */
6519 switch (tp->mac_version) {
6520 case RTL_GIGA_MAC_VER_11:
6521 case RTL_GIGA_MAC_VER_12:
6522 case RTL_GIGA_MAC_VER_17:
6523 pci_clear_master(tp->pci_dev);
6524
6525 RTL_W8(ChipCmd, CmdRxEnb);
6526 /* PCI commit */
6527 RTL_R8(ChipCmd);
6528 break;
6529 default:
6530 break;
6531 }
6532}
6533
Francois Romieu1765f952008-09-13 17:21:40 +02006534static void rtl_shutdown(struct pci_dev *pdev)
6535{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006536 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006537 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006538 struct device *d = &pdev->dev;
6539
6540 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006541
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006542 rtl8169_net_suspend(dev);
6543
Francois Romieucecb5fd2011-04-01 10:21:07 +02006544 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006545 rtl_rar_set(tp, dev->perm_addr);
6546
Hayes Wang92fc43b2011-07-06 15:58:03 +08006547 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006548
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006549 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006550 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6551 rtl_wol_suspend_quirk(tp);
6552 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006553 }
6554
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006555 pci_wake_from_d3(pdev, true);
6556 pci_set_power_state(pdev, PCI_D3hot);
6557 }
françois romieu2a15cd22012-03-06 01:14:12 +00006558
6559 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006560}
Francois Romieu5d06a992006-02-23 00:47:58 +01006561
Bill Pembertonbaf63292012-12-03 09:23:28 -05006562static void rtl_remove_one(struct pci_dev *pdev)
Francois Romieue27566e2012-03-08 09:54:01 +01006563{
6564 struct net_device *dev = pci_get_drvdata(pdev);
6565 struct rtl8169_private *tp = netdev_priv(dev);
6566
6567 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6568 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6569 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6570 rtl8168_driver_stop(tp);
6571 }
6572
6573 cancel_work_sync(&tp->wk.work);
6574
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006575 netif_napi_del(&tp->napi);
6576
Francois Romieue27566e2012-03-08 09:54:01 +01006577 unregister_netdev(dev);
6578
6579 rtl_release_firmware(tp);
6580
6581 if (pci_dev_run_wake(pdev))
6582 pm_runtime_get_noresume(&pdev->dev);
6583
6584 /* restore original MAC address */
6585 rtl_rar_set(tp, dev->perm_addr);
6586
6587 rtl_disable_msi(pdev, tp);
6588 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6589 pci_set_drvdata(pdev, NULL);
6590}
6591
Francois Romieufa9c3852012-03-08 10:01:50 +01006592static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006593 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006594 .ndo_stop = rtl8169_close,
6595 .ndo_get_stats64 = rtl8169_get_stats64,
6596 .ndo_start_xmit = rtl8169_start_xmit,
6597 .ndo_tx_timeout = rtl8169_tx_timeout,
6598 .ndo_validate_addr = eth_validate_addr,
6599 .ndo_change_mtu = rtl8169_change_mtu,
6600 .ndo_fix_features = rtl8169_fix_features,
6601 .ndo_set_features = rtl8169_set_features,
6602 .ndo_set_mac_address = rtl_set_mac_address,
6603 .ndo_do_ioctl = rtl8169_ioctl,
6604 .ndo_set_rx_mode = rtl_set_rx_mode,
6605#ifdef CONFIG_NET_POLL_CONTROLLER
6606 .ndo_poll_controller = rtl8169_netpoll,
6607#endif
6608
6609};
6610
Francois Romieu31fa8b12012-03-08 10:09:40 +01006611static const struct rtl_cfg_info {
6612 void (*hw_start)(struct net_device *);
6613 unsigned int region;
6614 unsigned int align;
6615 u16 event_slow;
6616 unsigned features;
6617 u8 default_ver;
6618} rtl_cfg_infos [] = {
6619 [RTL_CFG_0] = {
6620 .hw_start = rtl_hw_start_8169,
6621 .region = 1,
6622 .align = 0,
6623 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6624 .features = RTL_FEATURE_GMII,
6625 .default_ver = RTL_GIGA_MAC_VER_01,
6626 },
6627 [RTL_CFG_1] = {
6628 .hw_start = rtl_hw_start_8168,
6629 .region = 2,
6630 .align = 8,
6631 .event_slow = SYSErr | LinkChg | RxOverflow,
6632 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6633 .default_ver = RTL_GIGA_MAC_VER_11,
6634 },
6635 [RTL_CFG_2] = {
6636 .hw_start = rtl_hw_start_8101,
6637 .region = 2,
6638 .align = 8,
6639 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6640 PCSTimeout,
6641 .features = RTL_FEATURE_MSI,
6642 .default_ver = RTL_GIGA_MAC_VER_13,
6643 }
6644};
6645
6646/* Cfg9346_Unlock assumed. */
6647static unsigned rtl_try_msi(struct rtl8169_private *tp,
6648 const struct rtl_cfg_info *cfg)
6649{
6650 void __iomem *ioaddr = tp->mmio_addr;
6651 unsigned msi = 0;
6652 u8 cfg2;
6653
6654 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6655 if (cfg->features & RTL_FEATURE_MSI) {
6656 if (pci_enable_msi(tp->pci_dev)) {
6657 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6658 } else {
6659 cfg2 |= MSIEnable;
6660 msi = RTL_FEATURE_MSI;
6661 }
6662 }
6663 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6664 RTL_W8(Config2, cfg2);
6665 return msi;
6666}
6667
Hayes Wangc5583862012-07-02 17:23:22 +08006668DECLARE_RTL_COND(rtl_link_list_ready_cond)
6669{
6670 void __iomem *ioaddr = tp->mmio_addr;
6671
6672 return RTL_R8(MCU) & LINK_LIST_RDY;
6673}
6674
6675DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6676{
6677 void __iomem *ioaddr = tp->mmio_addr;
6678
6679 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6680}
6681
Bill Pembertonbaf63292012-12-03 09:23:28 -05006682static void rtl_hw_init_8168g(struct rtl8169_private *tp)
Hayes Wangc5583862012-07-02 17:23:22 +08006683{
6684 void __iomem *ioaddr = tp->mmio_addr;
6685 u32 data;
6686
6687 tp->ocp_base = OCP_STD_PHY_BASE;
6688
6689 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6690
6691 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6692 return;
6693
6694 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6695 return;
6696
6697 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6698 msleep(1);
6699 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6700
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006701 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006702 data &= ~(1 << 14);
6703 r8168_mac_ocp_write(tp, 0xe8de, data);
6704
6705 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6706 return;
6707
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006708 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006709 data |= (1 << 15);
6710 r8168_mac_ocp_write(tp, 0xe8de, data);
6711
6712 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6713 return;
6714}
6715
Bill Pembertonbaf63292012-12-03 09:23:28 -05006716static void rtl_hw_initialize(struct rtl8169_private *tp)
Hayes Wangc5583862012-07-02 17:23:22 +08006717{
6718 switch (tp->mac_version) {
6719 case RTL_GIGA_MAC_VER_40:
6720 case RTL_GIGA_MAC_VER_41:
6721 rtl_hw_init_8168g(tp);
6722 break;
6723
6724 default:
6725 break;
6726 }
6727}
6728
Bill Pembertonbaf63292012-12-03 09:23:28 -05006729static int
Francois Romieu3b6cf252012-03-08 09:59:04 +01006730rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6731{
6732 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6733 const unsigned int region = cfg->region;
6734 struct rtl8169_private *tp;
6735 struct mii_if_info *mii;
6736 struct net_device *dev;
6737 void __iomem *ioaddr;
6738 int chipset, i;
6739 int rc;
6740
6741 if (netif_msg_drv(&debug)) {
6742 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6743 MODULENAME, RTL8169_VERSION);
6744 }
6745
6746 dev = alloc_etherdev(sizeof (*tp));
6747 if (!dev) {
6748 rc = -ENOMEM;
6749 goto out;
6750 }
6751
6752 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006753 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006754 tp = netdev_priv(dev);
6755 tp->dev = dev;
6756 tp->pci_dev = pdev;
6757 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6758
6759 mii = &tp->mii;
6760 mii->dev = dev;
6761 mii->mdio_read = rtl_mdio_read;
6762 mii->mdio_write = rtl_mdio_write;
6763 mii->phy_id_mask = 0x1f;
6764 mii->reg_num_mask = 0x1f;
6765 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6766
6767 /* disable ASPM completely as that cause random device stop working
6768 * problems as well as full system hangs for some PCIe devices users */
6769 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6770 PCIE_LINK_STATE_CLKPM);
6771
6772 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6773 rc = pci_enable_device(pdev);
6774 if (rc < 0) {
6775 netif_err(tp, probe, dev, "enable failure\n");
6776 goto err_out_free_dev_1;
6777 }
6778
6779 if (pci_set_mwi(pdev) < 0)
6780 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6781
6782 /* make sure PCI base addr 1 is MMIO */
6783 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6784 netif_err(tp, probe, dev,
6785 "region #%d not an MMIO resource, aborting\n",
6786 region);
6787 rc = -ENODEV;
6788 goto err_out_mwi_2;
6789 }
6790
6791 /* check for weird/broken PCI region reporting */
6792 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6793 netif_err(tp, probe, dev,
6794 "Invalid PCI region size(s), aborting\n");
6795 rc = -ENODEV;
6796 goto err_out_mwi_2;
6797 }
6798
6799 rc = pci_request_regions(pdev, MODULENAME);
6800 if (rc < 0) {
6801 netif_err(tp, probe, dev, "could not request regions\n");
6802 goto err_out_mwi_2;
6803 }
6804
6805 tp->cp_cmd = RxChkSum;
6806
6807 if ((sizeof(dma_addr_t) > 4) &&
6808 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6809 tp->cp_cmd |= PCIDAC;
6810 dev->features |= NETIF_F_HIGHDMA;
6811 } else {
6812 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6813 if (rc < 0) {
6814 netif_err(tp, probe, dev, "DMA configuration failed\n");
6815 goto err_out_free_res_3;
6816 }
6817 }
6818
6819 /* ioremap MMIO region */
6820 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6821 if (!ioaddr) {
6822 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6823 rc = -EIO;
6824 goto err_out_free_res_3;
6825 }
6826 tp->mmio_addr = ioaddr;
6827
6828 if (!pci_is_pcie(pdev))
6829 netif_info(tp, probe, dev, "not PCI Express\n");
6830
6831 /* Identify chip attached to board */
6832 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6833
6834 rtl_init_rxcfg(tp);
6835
6836 rtl_irq_disable(tp);
6837
Hayes Wangc5583862012-07-02 17:23:22 +08006838 rtl_hw_initialize(tp);
6839
Francois Romieu3b6cf252012-03-08 09:59:04 +01006840 rtl_hw_reset(tp);
6841
6842 rtl_ack_events(tp, 0xffff);
6843
6844 pci_set_master(pdev);
6845
6846 /*
6847 * Pretend we are using VLANs; This bypasses a nasty bug where
6848 * Interrupts stop flowing on high load on 8110SCd controllers.
6849 */
6850 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6851 tp->cp_cmd |= RxVlan;
6852
6853 rtl_init_mdio_ops(tp);
6854 rtl_init_pll_power_ops(tp);
6855 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006856 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006857
6858 rtl8169_print_mac_version(tp);
6859
6860 chipset = tp->mac_version;
6861 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6862
6863 RTL_W8(Cfg9346, Cfg9346_Unlock);
6864 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6865 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6866 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6867 tp->features |= RTL_FEATURE_WOL;
6868 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6869 tp->features |= RTL_FEATURE_WOL;
6870 tp->features |= rtl_try_msi(tp, cfg);
6871 RTL_W8(Cfg9346, Cfg9346_Lock);
6872
6873 if (rtl_tbi_enabled(tp)) {
6874 tp->set_speed = rtl8169_set_speed_tbi;
6875 tp->get_settings = rtl8169_gset_tbi;
6876 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6877 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6878 tp->link_ok = rtl8169_tbi_link_ok;
6879 tp->do_ioctl = rtl_tbi_ioctl;
6880 } else {
6881 tp->set_speed = rtl8169_set_speed_xmii;
6882 tp->get_settings = rtl8169_gset_xmii;
6883 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6884 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6885 tp->link_ok = rtl8169_xmii_link_ok;
6886 tp->do_ioctl = rtl_xmii_ioctl;
6887 }
6888
6889 mutex_init(&tp->wk.mutex);
6890
6891 /* Get MAC address */
6892 for (i = 0; i < ETH_ALEN; i++)
6893 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6894 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6895
6896 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6897 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006898
6899 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6900
6901 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6902 * properly for all devices */
6903 dev->features |= NETIF_F_RXCSUM |
6904 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6905
6906 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6907 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6908 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6909 NETIF_F_HIGHDMA;
6910
6911 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6912 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6913 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6914
6915 dev->hw_features |= NETIF_F_RXALL;
6916 dev->hw_features |= NETIF_F_RXFCS;
6917
6918 tp->hw_start = cfg->hw_start;
6919 tp->event_slow = cfg->event_slow;
6920
6921 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6922 ~(RxBOVF | RxFOVF) : ~0;
6923
6924 init_timer(&tp->timer);
6925 tp->timer.data = (unsigned long) dev;
6926 tp->timer.function = rtl8169_phy_timer;
6927
6928 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6929
6930 rc = register_netdev(dev);
6931 if (rc < 0)
6932 goto err_out_msi_4;
6933
6934 pci_set_drvdata(pdev, dev);
6935
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006936 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6937 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6938 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006939 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6940 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6941 "tx checksumming: %s]\n",
6942 rtl_chip_infos[chipset].jumbo_max,
6943 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6944 }
6945
6946 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6947 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6948 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6949 rtl8168_driver_start(tp);
6950 }
6951
6952 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6953
6954 if (pci_dev_run_wake(pdev))
6955 pm_runtime_put_noidle(&pdev->dev);
6956
6957 netif_carrier_off(dev);
6958
6959out:
6960 return rc;
6961
6962err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006963 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006964 rtl_disable_msi(pdev, tp);
6965 iounmap(ioaddr);
6966err_out_free_res_3:
6967 pci_release_regions(pdev);
6968err_out_mwi_2:
6969 pci_clear_mwi(pdev);
6970 pci_disable_device(pdev);
6971err_out_free_dev_1:
6972 free_netdev(dev);
6973 goto out;
6974}
6975
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976static struct pci_driver rtl8169_pci_driver = {
6977 .name = MODULENAME,
6978 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01006979 .probe = rtl_init_one,
Bill Pembertonbaf63292012-12-03 09:23:28 -05006980 .remove = rtl_remove_one,
Francois Romieu1765f952008-09-13 17:21:40 +02006981 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006982 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006983};
6984
Devendra Naga3eeb7da2012-10-26 09:27:42 +00006985module_pci_driver(rtl8169_pci_driver);