blob: 927aa33d43497eae636a6d3b4a0e93e15fc93b27 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Francois Romieu07d3f512007-02-21 22:40:46 +01002 * r8169.c: RealTek 8169/8168/8101 ethernet driver.
3 *
4 * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
5 * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
6 * Copyright (c) a lot of people too. Please respect their work.
7 *
8 * See MAINTAINERS file for support contact information.
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/pci.h>
14#include <linux/netdevice.h>
15#include <linux/etherdevice.h>
16#include <linux/delay.h>
17#include <linux/ethtool.h>
18#include <linux/mii.h>
19#include <linux/if_vlan.h>
20#include <linux/crc32.h>
21#include <linux/in.h>
22#include <linux/ip.h>
23#include <linux/tcp.h>
24#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000025#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/dma-mapping.h>
Rafael J. Wysockie1759442010-03-14 14:33:51 +000027#include <linux/pm_runtime.h>
françois romieubca03d52011-01-03 15:07:31 +000028#include <linux/firmware.h>
Stanislaw Gruszkaba04c7c2011-02-22 02:00:11 +000029#include <linux/pci-aspm.h>
Paul Gortmaker70c71602011-05-22 16:47:17 -040030#include <linux/prefetch.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include <asm/io.h>
33#include <asm/irq.h>
34
Francois Romieu865c6522008-05-11 14:51:00 +020035#define RTL8169_VERSION "2.3LK-NAPI"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#define MODULENAME "r8169"
37#define PFX MODULENAME ": "
38
françois romieubca03d52011-01-03 15:07:31 +000039#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
40#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
hayeswang01dc7fe2011-03-21 01:50:28 +000041#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
42#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
Hayes Wang70090422011-07-06 15:58:06 +080043#define FIRMWARE_8168E_3 "rtl_nic/rtl8168e-3.fw"
Hayes Wangc2218922011-09-06 16:55:18 +080044#define FIRMWARE_8168F_1 "rtl_nic/rtl8168f-1.fw"
45#define FIRMWARE_8168F_2 "rtl_nic/rtl8168f-2.fw"
Hayes Wang5a5e4442011-02-22 17:26:21 +080046#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
Hayes Wang7e18dca2012-03-30 14:33:02 +080047#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
Hayes Wangb3d7b2f2012-03-30 14:48:06 +080048#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
Hayes Wang5598bfe2012-07-02 17:23:21 +080049#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
Hayes Wangc5583862012-07-02 17:23:22 +080050#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
françois romieubca03d52011-01-03 15:07:31 +000051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#ifdef RTL8169_DEBUG
53#define assert(expr) \
Francois Romieu5b0384f2006-08-16 16:00:01 +020054 if (!(expr)) { \
55 printk( "Assertion failed! %s,%s,%s,line=%d\n", \
Harvey Harrisonb39d66a2008-08-20 16:52:04 -070056 #expr,__FILE__,__func__,__LINE__); \
Francois Romieu5b0384f2006-08-16 16:00:01 +020057 }
Joe Perches06fa7352007-10-18 21:15:00 +020058#define dprintk(fmt, args...) \
59 do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#else
61#define assert(expr) do {} while (0)
62#define dprintk(fmt, args...) do {} while (0)
63#endif /* RTL8169_DEBUG */
64
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020065#define R8169_MSG_DEFAULT \
Francois Romieuf0e837d2005-09-30 16:54:02 -070066 (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +020067
Julien Ducourthial477206a2012-05-09 00:00:06 +020068#define TX_SLOTS_AVAIL(tp) \
69 (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
70
71/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
72#define TX_FRAGS_READY_FOR(tp,nr_frags) \
73 (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
76 The RTL chips use a 64 element hash table based on the Ethernet CRC. */
Arjan van de Venf71e1302006-03-03 21:33:57 -050077static const int multicast_filter_limit = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Francois Romieu9c14cea2008-07-05 00:21:15 +020079#define MAX_READ_REQUEST_SHIFT 12
Michal Schmidtaee77e42012-09-09 13:55:26 +000080#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
82#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
83
84#define R8169_REGS_SIZE 256
85#define R8169_NAPI_WEIGHT 64
86#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */
87#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */
88#define RX_BUF_SIZE 1536 /* Rx Buffer size */
89#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
90#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
91
92#define RTL8169_TX_TIMEOUT (6*HZ)
93#define RTL8169_PHY_TIMEOUT (10*HZ)
94
françois romieuea8dbdd2009-03-15 01:10:50 +000095#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
96#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
Francois Romieue1564ec2008-10-16 22:46:13 +020097#define RTL_EEPROM_SIG_ADDR 0x0000
98
Linus Torvalds1da177e2005-04-16 15:20:36 -070099/* write/read MMIO register */
100#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
101#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
102#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
103#define RTL_R8(reg) readb (ioaddr + (reg))
104#define RTL_R16(reg) readw (ioaddr + (reg))
Junchang Wang06f555f2010-05-30 02:26:07 +0000105#define RTL_R32(reg) readl (ioaddr + (reg))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107enum mac_version {
Francois Romieu85bffe62011-04-27 08:22:39 +0200108 RTL_GIGA_MAC_VER_01 = 0,
109 RTL_GIGA_MAC_VER_02,
110 RTL_GIGA_MAC_VER_03,
111 RTL_GIGA_MAC_VER_04,
112 RTL_GIGA_MAC_VER_05,
113 RTL_GIGA_MAC_VER_06,
114 RTL_GIGA_MAC_VER_07,
115 RTL_GIGA_MAC_VER_08,
116 RTL_GIGA_MAC_VER_09,
117 RTL_GIGA_MAC_VER_10,
118 RTL_GIGA_MAC_VER_11,
119 RTL_GIGA_MAC_VER_12,
120 RTL_GIGA_MAC_VER_13,
121 RTL_GIGA_MAC_VER_14,
122 RTL_GIGA_MAC_VER_15,
123 RTL_GIGA_MAC_VER_16,
124 RTL_GIGA_MAC_VER_17,
125 RTL_GIGA_MAC_VER_18,
126 RTL_GIGA_MAC_VER_19,
127 RTL_GIGA_MAC_VER_20,
128 RTL_GIGA_MAC_VER_21,
129 RTL_GIGA_MAC_VER_22,
130 RTL_GIGA_MAC_VER_23,
131 RTL_GIGA_MAC_VER_24,
132 RTL_GIGA_MAC_VER_25,
133 RTL_GIGA_MAC_VER_26,
134 RTL_GIGA_MAC_VER_27,
135 RTL_GIGA_MAC_VER_28,
136 RTL_GIGA_MAC_VER_29,
137 RTL_GIGA_MAC_VER_30,
138 RTL_GIGA_MAC_VER_31,
139 RTL_GIGA_MAC_VER_32,
140 RTL_GIGA_MAC_VER_33,
Hayes Wang70090422011-07-06 15:58:06 +0800141 RTL_GIGA_MAC_VER_34,
Hayes Wangc2218922011-09-06 16:55:18 +0800142 RTL_GIGA_MAC_VER_35,
143 RTL_GIGA_MAC_VER_36,
Hayes Wang7e18dca2012-03-30 14:33:02 +0800144 RTL_GIGA_MAC_VER_37,
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800145 RTL_GIGA_MAC_VER_38,
Hayes Wang5598bfe2012-07-02 17:23:21 +0800146 RTL_GIGA_MAC_VER_39,
Hayes Wangc5583862012-07-02 17:23:22 +0800147 RTL_GIGA_MAC_VER_40,
148 RTL_GIGA_MAC_VER_41,
Francois Romieu85bffe62011-04-27 08:22:39 +0200149 RTL_GIGA_MAC_NONE = 0xff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150};
151
Francois Romieu2b7b4312011-04-18 22:53:24 -0700152enum rtl_tx_desc_version {
153 RTL_TD_0 = 0,
154 RTL_TD_1 = 1,
155};
156
Francois Romieud58d46b2011-05-03 16:38:29 +0200157#define JUMBO_1K ETH_DATA_LEN
158#define JUMBO_4K (4*1024 - ETH_HLEN - 2)
159#define JUMBO_6K (6*1024 - ETH_HLEN - 2)
160#define JUMBO_7K (7*1024 - ETH_HLEN - 2)
161#define JUMBO_9K (9*1024 - ETH_HLEN - 2)
162
163#define _R(NAME,TD,FW,SZ,B) { \
164 .name = NAME, \
165 .txd_version = TD, \
166 .fw_name = FW, \
167 .jumbo_max = SZ, \
168 .jumbo_tx_csum = B \
169}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Jesper Juhl3c6bee12006-01-09 20:54:01 -0800171static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 const char *name;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700173 enum rtl_tx_desc_version txd_version;
Francois Romieu85bffe62011-04-27 08:22:39 +0200174 const char *fw_name;
Francois Romieud58d46b2011-05-03 16:38:29 +0200175 u16 jumbo_max;
176 bool jumbo_tx_csum;
Francois Romieu85bffe62011-04-27 08:22:39 +0200177} rtl_chip_infos[] = {
178 /* PCI devices. */
179 [RTL_GIGA_MAC_VER_01] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200180 _R("RTL8169", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200181 [RTL_GIGA_MAC_VER_02] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200182 _R("RTL8169s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200183 [RTL_GIGA_MAC_VER_03] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200184 _R("RTL8110s", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200185 [RTL_GIGA_MAC_VER_04] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200186 _R("RTL8169sb/8110sb", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200187 [RTL_GIGA_MAC_VER_05] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200188 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200189 [RTL_GIGA_MAC_VER_06] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200190 _R("RTL8169sc/8110sc", RTL_TD_0, NULL, JUMBO_7K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200191 /* PCI-E devices. */
192 [RTL_GIGA_MAC_VER_07] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200193 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200194 [RTL_GIGA_MAC_VER_08] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200195 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200196 [RTL_GIGA_MAC_VER_09] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200197 _R("RTL8102e", RTL_TD_1, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200198 [RTL_GIGA_MAC_VER_10] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200199 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200200 [RTL_GIGA_MAC_VER_11] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200201 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200202 [RTL_GIGA_MAC_VER_12] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200203 _R("RTL8168b/8111b", RTL_TD_0, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200204 [RTL_GIGA_MAC_VER_13] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200205 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200206 [RTL_GIGA_MAC_VER_14] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200207 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200208 [RTL_GIGA_MAC_VER_15] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200209 _R("RTL8100e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200210 [RTL_GIGA_MAC_VER_16] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200211 _R("RTL8101e", RTL_TD_0, NULL, JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200212 [RTL_GIGA_MAC_VER_17] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200213 _R("RTL8168b/8111b", RTL_TD_1, NULL, JUMBO_4K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200214 [RTL_GIGA_MAC_VER_18] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200215 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200216 [RTL_GIGA_MAC_VER_19] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200217 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200218 [RTL_GIGA_MAC_VER_20] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200219 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200220 [RTL_GIGA_MAC_VER_21] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200221 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200222 [RTL_GIGA_MAC_VER_22] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200223 _R("RTL8168c/8111c", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200224 [RTL_GIGA_MAC_VER_23] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200225 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200226 [RTL_GIGA_MAC_VER_24] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200227 _R("RTL8168cp/8111cp", RTL_TD_1, NULL, JUMBO_6K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200228 [RTL_GIGA_MAC_VER_25] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200229 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1,
230 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200231 [RTL_GIGA_MAC_VER_26] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200232 _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2,
233 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200234 [RTL_GIGA_MAC_VER_27] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200235 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200236 [RTL_GIGA_MAC_VER_28] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200237 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200238 [RTL_GIGA_MAC_VER_29] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200239 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
240 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200241 [RTL_GIGA_MAC_VER_30] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200242 _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1,
243 JUMBO_1K, true),
Francois Romieu85bffe62011-04-27 08:22:39 +0200244 [RTL_GIGA_MAC_VER_31] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200245 _R("RTL8168dp/8111dp", RTL_TD_1, NULL, JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200246 [RTL_GIGA_MAC_VER_32] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200247 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1,
248 JUMBO_9K, false),
Francois Romieu85bffe62011-04-27 08:22:39 +0200249 [RTL_GIGA_MAC_VER_33] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200250 _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2,
251 JUMBO_9K, false),
Hayes Wang70090422011-07-06 15:58:06 +0800252 [RTL_GIGA_MAC_VER_34] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200253 _R("RTL8168evl/8111evl",RTL_TD_1, FIRMWARE_8168E_3,
254 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800255 [RTL_GIGA_MAC_VER_35] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200256 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_1,
257 JUMBO_9K, false),
Hayes Wangc2218922011-09-06 16:55:18 +0800258 [RTL_GIGA_MAC_VER_36] =
Francois Romieud58d46b2011-05-03 16:38:29 +0200259 _R("RTL8168f/8111f", RTL_TD_1, FIRMWARE_8168F_2,
260 JUMBO_9K, false),
Hayes Wang7e18dca2012-03-30 14:33:02 +0800261 [RTL_GIGA_MAC_VER_37] =
262 _R("RTL8402", RTL_TD_1, FIRMWARE_8402_1,
263 JUMBO_1K, true),
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800264 [RTL_GIGA_MAC_VER_38] =
265 _R("RTL8411", RTL_TD_1, FIRMWARE_8411_1,
266 JUMBO_9K, false),
Hayes Wang5598bfe2012-07-02 17:23:21 +0800267 [RTL_GIGA_MAC_VER_39] =
268 _R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_1,
269 JUMBO_1K, true),
Hayes Wangc5583862012-07-02 17:23:22 +0800270 [RTL_GIGA_MAC_VER_40] =
271 _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_1,
272 JUMBO_9K, false),
273 [RTL_GIGA_MAC_VER_41] =
274 _R("RTL8168g/8111g", RTL_TD_1, NULL, JUMBO_9K, false),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275};
276#undef _R
277
Francois Romieubcf0bf92006-07-26 23:14:13 +0200278enum cfg_version {
279 RTL_CFG_0 = 0x00,
280 RTL_CFG_1,
281 RTL_CFG_2
282};
283
Alexey Dobriyana3aa1882010-01-07 11:58:11 +0000284static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = {
Francois Romieubcf0bf92006-07-26 23:14:13 +0200285 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
Francois Romieud2eed8c2006-08-31 22:01:07 +0200286 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
Francois Romieud81bf552006-09-20 21:31:20 +0200287 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
Francois Romieu07ce4062007-02-23 23:36:39 +0100288 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200289 { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
Francois Romieu2a35cfa2012-08-31 23:06:17 +0200290 { PCI_VENDOR_ID_DLINK, 0x4300,
291 PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0, RTL_CFG_1 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200292 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
Lennart Sorensen93a3aa22011-07-28 13:18:11 +0000293 { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 },
Francois Romieubc1660b2007-10-12 23:58:09 +0200294 { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
Francois Romieubcf0bf92006-07-26 23:14:13 +0200295 { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
296 { PCI_VENDOR_ID_LINKSYS, 0x1032,
297 PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
Ciaran McCreesh11d2e282007-11-01 22:48:15 +0100298 { 0x0001, 0x8168,
299 PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 {0,},
301};
302
303MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
304
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000305static int rx_buf_sz = 16383;
David S. Miller4300e8c2010-03-26 10:23:30 -0700306static int use_dac;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200307static struct {
308 u32 msg_enable;
309} debug = { -1 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Francois Romieu07d3f512007-02-21 22:40:46 +0100311enum rtl_registers {
312 MAC0 = 0, /* Ethernet hardware address. */
Francois Romieu773d2022007-01-31 23:47:43 +0100313 MAC4 = 4,
Francois Romieu07d3f512007-02-21 22:40:46 +0100314 MAR0 = 8, /* Multicast filter. */
315 CounterAddrLow = 0x10,
316 CounterAddrHigh = 0x14,
317 TxDescStartAddrLow = 0x20,
318 TxDescStartAddrHigh = 0x24,
319 TxHDescStartAddrLow = 0x28,
320 TxHDescStartAddrHigh = 0x2c,
321 FLASH = 0x30,
322 ERSR = 0x36,
323 ChipCmd = 0x37,
324 TxPoll = 0x38,
325 IntrMask = 0x3c,
326 IntrStatus = 0x3e,
Francois Romieu2b7b4312011-04-18 22:53:24 -0700327
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800328 TxConfig = 0x40,
329#define TXCFG_AUTO_FIFO (1 << 7) /* 8111e-vl */
330#define TXCFG_EMPTY (1 << 11) /* 8111e-vl */
331
332 RxConfig = 0x44,
333#define RX128_INT_EN (1 << 15) /* 8111c and later */
334#define RX_MULTI_EN (1 << 14) /* 8111c only */
335#define RXCFG_FIFO_SHIFT 13
336 /* No threshold before first PCI xfer */
337#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
338#define RXCFG_DMA_SHIFT 8
339 /* Unlimited maximum PCI burst. */
340#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
Francois Romieu2b7b4312011-04-18 22:53:24 -0700341
Francois Romieu07d3f512007-02-21 22:40:46 +0100342 RxMissed = 0x4c,
343 Cfg9346 = 0x50,
344 Config0 = 0x51,
345 Config1 = 0x52,
346 Config2 = 0x53,
Francois Romieud387b422012-04-17 11:12:01 +0200347#define PME_SIGNAL (1 << 5) /* 8168c and later */
348
Francois Romieu07d3f512007-02-21 22:40:46 +0100349 Config3 = 0x54,
350 Config4 = 0x55,
351 Config5 = 0x56,
352 MultiIntr = 0x5c,
353 PHYAR = 0x60,
Francois Romieu07d3f512007-02-21 22:40:46 +0100354 PHYstatus = 0x6c,
355 RxMaxSize = 0xda,
356 CPlusCmd = 0xe0,
357 IntrMitigate = 0xe2,
358 RxDescAddrLow = 0xe4,
359 RxDescAddrHigh = 0xe8,
françois romieuf0298f82011-01-03 15:07:42 +0000360 EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
361
362#define NoEarlyTx 0x3f /* Max value : no early transmit. */
363
364 MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
365
366#define TxPacketMax (8064 >> 7)
Hayes Wang3090bd92011-09-06 16:55:15 +0800367#define EarlySize 0x27
françois romieuf0298f82011-01-03 15:07:42 +0000368
Francois Romieu07d3f512007-02-21 22:40:46 +0100369 FuncEvent = 0xf0,
370 FuncEventMask = 0xf4,
371 FuncPresetState = 0xf8,
372 FuncForceEvent = 0xfc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373};
374
Francois Romieuf162a5d2008-06-01 22:37:49 +0200375enum rtl8110_registers {
376 TBICSR = 0x64,
377 TBI_ANAR = 0x68,
378 TBI_LPAR = 0x6a,
379};
380
381enum rtl8168_8101_registers {
382 CSIDR = 0x64,
383 CSIAR = 0x68,
384#define CSIAR_FLAG 0x80000000
385#define CSIAR_WRITE_CMD 0x80000000
386#define CSIAR_BYTE_ENABLE 0x0f
387#define CSIAR_BYTE_ENABLE_SHIFT 12
388#define CSIAR_ADDR_MASK 0x0fff
Hayes Wang7e18dca2012-03-30 14:33:02 +0800389#define CSIAR_FUNC_CARD 0x00000000
390#define CSIAR_FUNC_SDIO 0x00010000
391#define CSIAR_FUNC_NIC 0x00020000
françois romieu065c27c2011-01-03 15:08:12 +0000392 PMCH = 0x6f,
Francois Romieuf162a5d2008-06-01 22:37:49 +0200393 EPHYAR = 0x80,
394#define EPHYAR_FLAG 0x80000000
395#define EPHYAR_WRITE_CMD 0x80000000
396#define EPHYAR_REG_MASK 0x1f
397#define EPHYAR_REG_SHIFT 16
398#define EPHYAR_DATA_MASK 0xffff
Hayes Wang5a5e4442011-02-22 17:26:21 +0800399 DLLPR = 0xd0,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800400#define PFM_EN (1 << 6)
Francois Romieuf162a5d2008-06-01 22:37:49 +0200401 DBG_REG = 0xd1,
402#define FIX_NAK_1 (1 << 4)
403#define FIX_NAK_2 (1 << 3)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800404 TWSI = 0xd2,
405 MCU = 0xd3,
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800406#define NOW_IS_OOB (1 << 7)
Hayes Wangc5583862012-07-02 17:23:22 +0800407#define TX_EMPTY (1 << 5)
408#define RX_EMPTY (1 << 4)
409#define RXTX_EMPTY (TX_EMPTY | RX_EMPTY)
Hayes Wang5a5e4442011-02-22 17:26:21 +0800410#define EN_NDP (1 << 3)
411#define EN_OOB_RESET (1 << 2)
Hayes Wangc5583862012-07-02 17:23:22 +0800412#define LINK_LIST_RDY (1 << 1)
françois romieudaf9df62009-10-07 12:44:20 +0000413 EFUSEAR = 0xdc,
414#define EFUSEAR_FLAG 0x80000000
415#define EFUSEAR_WRITE_CMD 0x80000000
416#define EFUSEAR_READ_CMD 0x00000000
417#define EFUSEAR_REG_MASK 0x03ff
418#define EFUSEAR_REG_SHIFT 8
419#define EFUSEAR_DATA_MASK 0xff
Francois Romieuf162a5d2008-06-01 22:37:49 +0200420};
421
françois romieuc0e45c12011-01-03 15:08:04 +0000422enum rtl8168_registers {
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800423 LED_FREQ = 0x1a,
424 EEE_LED = 0x1b,
françois romieub646d902011-01-03 15:08:21 +0000425 ERIDR = 0x70,
426 ERIAR = 0x74,
427#define ERIAR_FLAG 0x80000000
428#define ERIAR_WRITE_CMD 0x80000000
429#define ERIAR_READ_CMD 0x00000000
430#define ERIAR_ADDR_BYTE_ALIGN 4
françois romieub646d902011-01-03 15:08:21 +0000431#define ERIAR_TYPE_SHIFT 16
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800432#define ERIAR_EXGMAC (0x00 << ERIAR_TYPE_SHIFT)
433#define ERIAR_MSIX (0x01 << ERIAR_TYPE_SHIFT)
434#define ERIAR_ASF (0x02 << ERIAR_TYPE_SHIFT)
435#define ERIAR_MASK_SHIFT 12
436#define ERIAR_MASK_0001 (0x1 << ERIAR_MASK_SHIFT)
437#define ERIAR_MASK_0011 (0x3 << ERIAR_MASK_SHIFT)
Hayes Wangc5583862012-07-02 17:23:22 +0800438#define ERIAR_MASK_0101 (0x5 << ERIAR_MASK_SHIFT)
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800439#define ERIAR_MASK_1111 (0xf << ERIAR_MASK_SHIFT)
françois romieuc0e45c12011-01-03 15:08:04 +0000440 EPHY_RXER_NUM = 0x7c,
441 OCPDR = 0xb0, /* OCP GPHY access */
442#define OCPDR_WRITE_CMD 0x80000000
443#define OCPDR_READ_CMD 0x00000000
444#define OCPDR_REG_MASK 0x7f
445#define OCPDR_GPHY_REG_SHIFT 16
446#define OCPDR_DATA_MASK 0xffff
447 OCPAR = 0xb4,
448#define OCPAR_FLAG 0x80000000
449#define OCPAR_GPHY_WRITE_CMD 0x8000f060
450#define OCPAR_GPHY_READ_CMD 0x0000f060
Hayes Wangc5583862012-07-02 17:23:22 +0800451 GPHY_OCP = 0xb8,
hayeswang01dc7fe2011-03-21 01:50:28 +0000452 RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */
453 MISC = 0xf0, /* 8168e only. */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200454#define TXPLA_RST (1 << 29)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800455#define DISABLE_LAN_EN (1 << 23) /* Enable GPIO pin */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800456#define PWM_EN (1 << 22)
Hayes Wangc5583862012-07-02 17:23:22 +0800457#define RXDV_GATED_EN (1 << 19)
Hayes Wang5598bfe2012-07-02 17:23:21 +0800458#define EARLY_TALLY_EN (1 << 16)
françois romieuc0e45c12011-01-03 15:08:04 +0000459};
460
Francois Romieu07d3f512007-02-21 22:40:46 +0100461enum rtl_register_content {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /* InterruptStatusBits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100463 SYSErr = 0x8000,
464 PCSTimeout = 0x4000,
465 SWInt = 0x0100,
466 TxDescUnavail = 0x0080,
467 RxFIFOOver = 0x0040,
468 LinkChg = 0x0020,
469 RxOverflow = 0x0010,
470 TxErr = 0x0008,
471 TxOK = 0x0004,
472 RxErr = 0x0002,
473 RxOK = 0x0001,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475 /* RxStatusDesc */
David S. Miller8decf862011-09-22 03:23:13 -0400476 RxBOVF = (1 << 24),
Francois Romieu9dccf612006-05-14 12:31:17 +0200477 RxFOVF = (1 << 23),
478 RxRWT = (1 << 22),
479 RxRES = (1 << 21),
480 RxRUNT = (1 << 20),
481 RxCRC = (1 << 19),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 /* ChipCmdBits */
Hayes Wang4f6b00e2011-07-06 15:58:02 +0800484 StopReq = 0x80,
Francois Romieu07d3f512007-02-21 22:40:46 +0100485 CmdReset = 0x10,
486 CmdRxEnb = 0x08,
487 CmdTxEnb = 0x04,
488 RxBufEmpty = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Francois Romieu275391a2007-02-23 23:50:28 +0100490 /* TXPoll register p.5 */
491 HPQ = 0x80, /* Poll cmd on the high prio queue */
492 NPQ = 0x40, /* Poll cmd on the low prio queue */
493 FSWInt = 0x01, /* Forced software interrupt */
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 /* Cfg9346Bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100496 Cfg9346_Lock = 0x00,
497 Cfg9346_Unlock = 0xc0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 /* rx_mode_bits */
Francois Romieu07d3f512007-02-21 22:40:46 +0100500 AcceptErr = 0x20,
501 AcceptRunt = 0x10,
502 AcceptBroadcast = 0x08,
503 AcceptMulticast = 0x04,
504 AcceptMyPhys = 0x02,
505 AcceptAllPhys = 0x01,
Francois Romieu1687b562011-07-19 17:21:29 +0200506#define RX_CONFIG_ACCEPT_MASK 0x3f
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /* TxConfigBits */
509 TxInterFrameGapShift = 24,
510 TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
511
Francois Romieu5d06a992006-02-23 00:47:58 +0100512 /* Config1 register p.24 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200513 LEDS1 = (1 << 7),
514 LEDS0 = (1 << 6),
Francois Romieuf162a5d2008-06-01 22:37:49 +0200515 Speed_down = (1 << 4),
516 MEMMAP = (1 << 3),
517 IOMAP = (1 << 2),
518 VPD = (1 << 1),
Francois Romieu5d06a992006-02-23 00:47:58 +0100519 PMEnable = (1 << 0), /* Power Management Enable */
520
Francois Romieu6dccd162007-02-13 23:38:05 +0100521 /* Config2 register p. 25 */
françois romieu2ca6cf02011-12-15 08:37:43 +0000522 MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
Francois Romieu6dccd162007-02-13 23:38:05 +0100523 PCI_Clock_66MHz = 0x01,
524 PCI_Clock_33MHz = 0x00,
525
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100526 /* Config3 register p.25 */
527 MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
528 LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
Francois Romieud58d46b2011-05-03 16:38:29 +0200529 Jumbo_En0 = (1 << 2), /* 8168 only. Reserved in the 8168b */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200530 Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100531
Francois Romieud58d46b2011-05-03 16:38:29 +0200532 /* Config4 register */
533 Jumbo_En1 = (1 << 1), /* 8168 only. Reserved in the 8168b */
534
Francois Romieu5d06a992006-02-23 00:47:58 +0100535 /* Config5 register p.27 */
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100536 BWF = (1 << 6), /* Accept Broadcast wakeup frame */
537 MWF = (1 << 5), /* Accept Multicast wakeup frame */
538 UWF = (1 << 4), /* Accept Unicast wakeup frame */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200539 Spi_en = (1 << 3),
Francois Romieu61a4dcc2006-02-23 00:55:25 +0100540 LanWake = (1 << 1), /* LanWake enable/disable */
Francois Romieu5d06a992006-02-23 00:47:58 +0100541 PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 /* TBICSR p.28 */
544 TBIReset = 0x80000000,
545 TBILoopback = 0x40000000,
546 TBINwEnable = 0x20000000,
547 TBINwRestart = 0x10000000,
548 TBILinkOk = 0x02000000,
549 TBINwComplete = 0x01000000,
550
551 /* CPlusCmd p.31 */
Francois Romieuf162a5d2008-06-01 22:37:49 +0200552 EnableBist = (1 << 15), // 8168 8101
553 Mac_dbgo_oe = (1 << 14), // 8168 8101
554 Normal_mode = (1 << 13), // unused
555 Force_half_dup = (1 << 12), // 8168 8101
556 Force_rxflow_en = (1 << 11), // 8168 8101
557 Force_txflow_en = (1 << 10), // 8168 8101
558 Cxpl_dbg_sel = (1 << 9), // 8168 8101
559 ASF = (1 << 8), // 8168 8101
560 PktCntrDisable = (1 << 7), // 8168 8101
561 Mac_dbgo_sel = 0x001c, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 RxVlan = (1 << 6),
563 RxChkSum = (1 << 5),
564 PCIDAC = (1 << 4),
565 PCIMulRW = (1 << 3),
Francois Romieu0e485152007-02-20 00:00:26 +0100566 INTT_0 = 0x0000, // 8168
567 INTT_1 = 0x0001, // 8168
568 INTT_2 = 0x0002, // 8168
569 INTT_3 = 0x0003, // 8168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* rtl8169_PHYstatus */
Francois Romieu07d3f512007-02-21 22:40:46 +0100572 TBI_Enable = 0x80,
573 TxFlowCtrl = 0x40,
574 RxFlowCtrl = 0x20,
575 _1000bpsF = 0x10,
576 _100bps = 0x08,
577 _10bps = 0x04,
578 LinkStatus = 0x02,
579 FullDup = 0x01,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 /* _TBICSRBit */
Francois Romieu07d3f512007-02-21 22:40:46 +0100582 TBILinkOK = 0x02000000,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +0200583
584 /* DumpCounterCommand */
Francois Romieu07d3f512007-02-21 22:40:46 +0100585 CounterDump = 0x8,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586};
587
Francois Romieu2b7b4312011-04-18 22:53:24 -0700588enum rtl_desc_bit {
589 /* First doubleword. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 DescOwn = (1 << 31), /* Descriptor is owned by NIC */
591 RingEnd = (1 << 30), /* End of descriptor ring */
592 FirstFrag = (1 << 29), /* First segment of a packet */
593 LastFrag = (1 << 28), /* Final segment of a packet */
Francois Romieu2b7b4312011-04-18 22:53:24 -0700594};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Francois Romieu2b7b4312011-04-18 22:53:24 -0700596/* Generic case. */
597enum rtl_tx_desc_bit {
598 /* First doubleword. */
599 TD_LSO = (1 << 27), /* Large Send Offload */
600#define TD_MSS_MAX 0x07ffu /* MSS value */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Francois Romieu2b7b4312011-04-18 22:53:24 -0700602 /* Second doubleword. */
603 TxVlanTag = (1 << 17), /* Add VLAN tag */
604};
605
606/* 8169, 8168b and 810x except 8102e. */
607enum rtl_tx_desc_bit_0 {
608 /* First doubleword. */
609#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */
610 TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */
611 TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */
612 TD0_IP_CS = (1 << 18), /* Calculate IP checksum */
613};
614
615/* 8102e, 8168c and beyond. */
616enum rtl_tx_desc_bit_1 {
617 /* Second doubleword. */
618#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */
619 TD1_IP_CS = (1 << 29), /* Calculate IP checksum */
620 TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */
621 TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */
622};
623
624static const struct rtl_tx_desc_info {
625 struct {
626 u32 udp;
627 u32 tcp;
628 } checksum;
629 u16 mss_shift;
630 u16 opts_offset;
631} tx_desc_info [] = {
632 [RTL_TD_0] = {
633 .checksum = {
634 .udp = TD0_IP_CS | TD0_UDP_CS,
635 .tcp = TD0_IP_CS | TD0_TCP_CS
636 },
637 .mss_shift = TD0_MSS_SHIFT,
638 .opts_offset = 0
639 },
640 [RTL_TD_1] = {
641 .checksum = {
642 .udp = TD1_IP_CS | TD1_UDP_CS,
643 .tcp = TD1_IP_CS | TD1_TCP_CS
644 },
645 .mss_shift = TD1_MSS_SHIFT,
646 .opts_offset = 1
647 }
648};
649
650enum rtl_rx_desc_bit {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 /* Rx private */
652 PID1 = (1 << 18), /* Protocol ID bit 1/2 */
653 PID0 = (1 << 17), /* Protocol ID bit 2/2 */
654
655#define RxProtoUDP (PID1)
656#define RxProtoTCP (PID0)
657#define RxProtoIP (PID1 | PID0)
658#define RxProtoMask RxProtoIP
659
660 IPFail = (1 << 16), /* IP checksum failed */
661 UDPFail = (1 << 15), /* UDP/IP checksum failed */
662 TCPFail = (1 << 14), /* TCP/IP checksum failed */
663 RxVlanTag = (1 << 16), /* VLAN tag available */
664};
665
666#define RsvdMask 0x3fffc000
667
668struct TxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200669 __le32 opts1;
670 __le32 opts2;
671 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672};
673
674struct RxDesc {
Rolf Eike Beer6cccd6e2007-05-21 22:11:04 +0200675 __le32 opts1;
676 __le32 opts2;
677 __le64 addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678};
679
680struct ring_info {
681 struct sk_buff *skb;
682 u32 len;
683 u8 __pad[sizeof(void *) - sizeof(u32)];
684};
685
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200686enum features {
Francois Romieuccdffb92008-07-26 14:26:06 +0200687 RTL_FEATURE_WOL = (1 << 0),
688 RTL_FEATURE_MSI = (1 << 1),
689 RTL_FEATURE_GMII = (1 << 2),
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200690};
691
Ivan Vecera355423d2009-02-06 21:49:57 -0800692struct rtl8169_counters {
693 __le64 tx_packets;
694 __le64 rx_packets;
695 __le64 tx_errors;
696 __le32 rx_errors;
697 __le16 rx_missed;
698 __le16 align_errors;
699 __le32 tx_one_collision;
700 __le32 tx_multi_collision;
701 __le64 rx_unicast;
702 __le64 rx_broadcast;
703 __le32 rx_multicast;
704 __le16 tx_aborted;
705 __le16 tx_underun;
706};
707
Francois Romieuda78dbf2012-01-26 14:18:23 +0100708enum rtl_flag {
Francois Romieu6c4a70c2012-01-31 10:56:44 +0100709 RTL_FLAG_TASK_ENABLED,
Francois Romieuda78dbf2012-01-26 14:18:23 +0100710 RTL_FLAG_TASK_SLOW_PENDING,
711 RTL_FLAG_TASK_RESET_PENDING,
712 RTL_FLAG_TASK_PHY_PENDING,
713 RTL_FLAG_MAX
714};
715
Junchang Wang8027aa22012-03-04 23:30:32 +0100716struct rtl8169_stats {
717 u64 packets;
718 u64 bytes;
719 struct u64_stats_sync syncp;
720};
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722struct rtl8169_private {
723 void __iomem *mmio_addr; /* memory map physical address */
Francois Romieucecb5fd2011-04-01 10:21:07 +0200724 struct pci_dev *pci_dev;
David Howellsc4028952006-11-22 14:57:56 +0000725 struct net_device *dev;
Stephen Hemmingerbea33482007-10-03 16:41:36 -0700726 struct napi_struct napi;
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200727 u32 msg_enable;
Francois Romieu2b7b4312011-04-18 22:53:24 -0700728 u16 txd_version;
729 u16 mac_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
731 u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
732 u32 dirty_rx;
733 u32 dirty_tx;
Junchang Wang8027aa22012-03-04 23:30:32 +0100734 struct rtl8169_stats rx_stats;
735 struct rtl8169_stats tx_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */
737 struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */
738 dma_addr_t TxPhyAddr;
739 dma_addr_t RxPhyAddr;
Eric Dumazet6f0333b2010-10-11 11:17:47 +0000740 void *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 struct timer_list timer;
743 u16 cp_cmd;
Francois Romieuda78dbf2012-01-26 14:18:23 +0100744
745 u16 event_slow;
françois romieuc0e45c12011-01-03 15:08:04 +0000746
747 struct mdio_ops {
Francois Romieu24192212012-07-06 20:19:42 +0200748 void (*write)(struct rtl8169_private *, int, int);
749 int (*read)(struct rtl8169_private *, int);
françois romieuc0e45c12011-01-03 15:08:04 +0000750 } mdio_ops;
751
françois romieu065c27c2011-01-03 15:08:12 +0000752 struct pll_power_ops {
753 void (*down)(struct rtl8169_private *);
754 void (*up)(struct rtl8169_private *);
755 } pll_power_ops;
756
Francois Romieud58d46b2011-05-03 16:38:29 +0200757 struct jumbo_ops {
758 void (*enable)(struct rtl8169_private *);
759 void (*disable)(struct rtl8169_private *);
760 } jumbo_ops;
761
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800762 struct csi_ops {
Francois Romieu52989f02012-07-06 13:37:00 +0200763 void (*write)(struct rtl8169_private *, int, int);
764 u32 (*read)(struct rtl8169_private *, int);
Hayes Wangbeb1fe12012-03-30 14:33:01 +0800765 } csi_ops;
766
Oliver Neukum54405cd2011-01-06 21:55:13 +0100767 int (*set_speed)(struct net_device *, u8 aneg, u16 sp, u8 dpx, u32 adv);
Francois Romieuccdffb92008-07-26 14:26:06 +0200768 int (*get_settings)(struct net_device *, struct ethtool_cmd *);
françois romieu4da19632011-01-03 15:07:55 +0000769 void (*phy_reset_enable)(struct rtl8169_private *tp);
Francois Romieu07ce4062007-02-23 23:36:39 +0100770 void (*hw_start)(struct net_device *);
françois romieu4da19632011-01-03 15:07:55 +0000771 unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 unsigned int (*link_ok)(void __iomem *);
Francois Romieu8b4ab282008-11-19 22:05:25 -0800773 int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
Francois Romieu4422bcd2012-01-26 11:23:32 +0100774
775 struct {
Francois Romieuda78dbf2012-01-26 14:18:23 +0100776 DECLARE_BITMAP(flags, RTL_FLAG_MAX);
777 struct mutex mutex;
Francois Romieu4422bcd2012-01-26 11:23:32 +0100778 struct work_struct work;
779 } wk;
780
Francois Romieuf23e7fd2007-10-04 22:36:14 +0200781 unsigned features;
Francois Romieuccdffb92008-07-26 14:26:06 +0200782
783 struct mii_if_info mii;
Ivan Vecera355423d2009-02-06 21:49:57 -0800784 struct rtl8169_counters counters;
Rafael J. Wysockie1759442010-03-14 14:33:51 +0000785 u32 saved_wolopts;
David S. Miller8decf862011-09-22 03:23:13 -0400786 u32 opts1_mask;
françois romieuf1e02ed2011-01-13 13:07:53 +0000787
Francois Romieub6ffd972011-06-17 17:00:05 +0200788 struct rtl_fw {
789 const struct firmware *fw;
Francois Romieu1c361ef2011-06-17 17:16:24 +0200790
791#define RTL_VER_SIZE 32
792
793 char version[RTL_VER_SIZE];
794
795 struct rtl_fw_phy_action {
796 __le32 *code;
797 size_t size;
798 } phy_action;
Francois Romieub6ffd972011-06-17 17:00:05 +0200799 } *rtl_fw;
Phil Carmody497888c2011-07-14 15:07:13 +0300800#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN)
Hayes Wangc5583862012-07-02 17:23:22 +0800801
802 u32 ocp_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803};
804
Ralf Baechle979b6c12005-06-13 14:30:40 -0700805MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807module_param(use_dac, int, 0);
David S. Miller4300e8c2010-03-26 10:23:30 -0700808MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +0200809module_param_named(debug, debug.msg_enable, int, 0);
810MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811MODULE_LICENSE("GPL");
812MODULE_VERSION(RTL8169_VERSION);
françois romieubca03d52011-01-03 15:07:31 +0000813MODULE_FIRMWARE(FIRMWARE_8168D_1);
814MODULE_FIRMWARE(FIRMWARE_8168D_2);
hayeswang01dc7fe2011-03-21 01:50:28 +0000815MODULE_FIRMWARE(FIRMWARE_8168E_1);
816MODULE_FIRMWARE(FIRMWARE_8168E_2);
David S. Miller8decf862011-09-22 03:23:13 -0400817MODULE_FIRMWARE(FIRMWARE_8168E_3);
Hayes Wang5a5e4442011-02-22 17:26:21 +0800818MODULE_FIRMWARE(FIRMWARE_8105E_1);
Hayes Wangc2218922011-09-06 16:55:18 +0800819MODULE_FIRMWARE(FIRMWARE_8168F_1);
820MODULE_FIRMWARE(FIRMWARE_8168F_2);
Hayes Wang7e18dca2012-03-30 14:33:02 +0800821MODULE_FIRMWARE(FIRMWARE_8402_1);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +0800822MODULE_FIRMWARE(FIRMWARE_8411_1);
Hayes Wang5598bfe2012-07-02 17:23:21 +0800823MODULE_FIRMWARE(FIRMWARE_8106E_1);
Hayes Wangc5583862012-07-02 17:23:22 +0800824MODULE_FIRMWARE(FIRMWARE_8168G_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Francois Romieuda78dbf2012-01-26 14:18:23 +0100826static void rtl_lock_work(struct rtl8169_private *tp)
827{
828 mutex_lock(&tp->wk.mutex);
829}
830
831static void rtl_unlock_work(struct rtl8169_private *tp)
832{
833 mutex_unlock(&tp->wk.mutex);
834}
835
Francois Romieud58d46b2011-05-03 16:38:29 +0200836static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
837{
Jiang Liu7d7903b2012-07-24 17:20:16 +0800838 pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
839 PCI_EXP_DEVCTL_READRQ, force);
Francois Romieud58d46b2011-05-03 16:38:29 +0200840}
841
Francois Romieuffc46952012-07-06 14:19:23 +0200842struct rtl_cond {
843 bool (*check)(struct rtl8169_private *);
844 const char *msg;
845};
846
847static void rtl_udelay(unsigned int d)
848{
849 udelay(d);
850}
851
852static bool rtl_loop_wait(struct rtl8169_private *tp, const struct rtl_cond *c,
853 void (*delay)(unsigned int), unsigned int d, int n,
854 bool high)
855{
856 int i;
857
858 for (i = 0; i < n; i++) {
859 delay(d);
860 if (c->check(tp) == high)
861 return true;
862 }
Francois Romieu82e316e2012-07-11 23:39:51 +0200863 netif_err(tp, drv, tp->dev, "%s == %d (loop: %d, delay: %d).\n",
864 c->msg, !high, n, d);
Francois Romieuffc46952012-07-06 14:19:23 +0200865 return false;
866}
867
868static bool rtl_udelay_loop_wait_high(struct rtl8169_private *tp,
869 const struct rtl_cond *c,
870 unsigned int d, int n)
871{
872 return rtl_loop_wait(tp, c, rtl_udelay, d, n, true);
873}
874
875static bool rtl_udelay_loop_wait_low(struct rtl8169_private *tp,
876 const struct rtl_cond *c,
877 unsigned int d, int n)
878{
879 return rtl_loop_wait(tp, c, rtl_udelay, d, n, false);
880}
881
882static bool rtl_msleep_loop_wait_high(struct rtl8169_private *tp,
883 const struct rtl_cond *c,
884 unsigned int d, int n)
885{
886 return rtl_loop_wait(tp, c, msleep, d, n, true);
887}
888
889static bool rtl_msleep_loop_wait_low(struct rtl8169_private *tp,
890 const struct rtl_cond *c,
891 unsigned int d, int n)
892{
893 return rtl_loop_wait(tp, c, msleep, d, n, false);
894}
895
896#define DECLARE_RTL_COND(name) \
897static bool name ## _check(struct rtl8169_private *); \
898 \
899static const struct rtl_cond name = { \
900 .check = name ## _check, \
901 .msg = #name \
902}; \
903 \
904static bool name ## _check(struct rtl8169_private *tp)
905
906DECLARE_RTL_COND(rtl_ocpar_cond)
907{
908 void __iomem *ioaddr = tp->mmio_addr;
909
910 return RTL_R32(OCPAR) & OCPAR_FLAG;
911}
912
françois romieub646d902011-01-03 15:08:21 +0000913static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
914{
915 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000916
917 RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200918
919 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 100, 20) ?
920 RTL_R32(OCPDR) : ~0;
françois romieub646d902011-01-03 15:08:21 +0000921}
922
923static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
924{
925 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000926
927 RTL_W32(OCPDR, data);
928 RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
Francois Romieuffc46952012-07-06 14:19:23 +0200929
930 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 100, 20);
931}
932
933DECLARE_RTL_COND(rtl_eriar_cond)
934{
935 void __iomem *ioaddr = tp->mmio_addr;
936
937 return RTL_R32(ERIAR) & ERIAR_FLAG;
françois romieub646d902011-01-03 15:08:21 +0000938}
939
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800940static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
françois romieub646d902011-01-03 15:08:21 +0000941{
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800942 void __iomem *ioaddr = tp->mmio_addr;
françois romieub646d902011-01-03 15:08:21 +0000943
944 RTL_W8(ERIDR, cmd);
945 RTL_W32(ERIAR, 0x800010e8);
946 msleep(2);
Francois Romieuffc46952012-07-06 14:19:23 +0200947
948 if (!rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 5))
949 return;
françois romieub646d902011-01-03 15:08:21 +0000950
Hayes Wangfac5b3c2011-02-22 17:26:20 +0800951 ocp_write(tp, 0x1, 0x30, 0x00000001);
françois romieub646d902011-01-03 15:08:21 +0000952}
953
954#define OOB_CMD_RESET 0x00
955#define OOB_CMD_DRIVER_START 0x05
956#define OOB_CMD_DRIVER_STOP 0x06
957
Francois Romieucecb5fd2011-04-01 10:21:07 +0200958static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
959{
960 return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
961}
962
Francois Romieuffc46952012-07-06 14:19:23 +0200963DECLARE_RTL_COND(rtl_ocp_read_cond)
françois romieub646d902011-01-03 15:08:21 +0000964{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200965 u16 reg;
françois romieub646d902011-01-03 15:08:21 +0000966
Francois Romieucecb5fd2011-04-01 10:21:07 +0200967 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000968
Francois Romieuffc46952012-07-06 14:19:23 +0200969 return ocp_read(tp, 0x0f, reg) & 0x00000800;
970}
971
972static void rtl8168_driver_start(struct rtl8169_private *tp)
973{
974 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
975
976 rtl_msleep_loop_wait_high(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000977}
978
979static void rtl8168_driver_stop(struct rtl8169_private *tp)
980{
françois romieub646d902011-01-03 15:08:21 +0000981 rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
982
Francois Romieuffc46952012-07-06 14:19:23 +0200983 rtl_msleep_loop_wait_low(tp, &rtl_ocp_read_cond, 10, 10);
françois romieub646d902011-01-03 15:08:21 +0000984}
985
hayeswang4804b3b2011-03-21 01:50:29 +0000986static int r8168dp_check_dash(struct rtl8169_private *tp)
987{
Francois Romieucecb5fd2011-04-01 10:21:07 +0200988 u16 reg = rtl8168_get_ocp_reg(tp);
hayeswang4804b3b2011-03-21 01:50:29 +0000989
Francois Romieucecb5fd2011-04-01 10:21:07 +0200990 return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
hayeswang4804b3b2011-03-21 01:50:29 +0000991}
françois romieub646d902011-01-03 15:08:21 +0000992
Hayes Wangc5583862012-07-02 17:23:22 +0800993static bool rtl_ocp_reg_failure(struct rtl8169_private *tp, u32 reg)
994{
995 if (reg & 0xffff0001) {
996 netif_err(tp, drv, tp->dev, "Invalid ocp reg %x!\n", reg);
997 return true;
998 }
999 return false;
1000}
1001
1002DECLARE_RTL_COND(rtl_ocp_gphy_cond)
1003{
1004 void __iomem *ioaddr = tp->mmio_addr;
1005
1006 return RTL_R32(GPHY_OCP) & OCPAR_FLAG;
1007}
1008
1009static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1010{
1011 void __iomem *ioaddr = tp->mmio_addr;
1012
1013 if (rtl_ocp_reg_failure(tp, reg))
1014 return;
1015
1016 RTL_W32(GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);
1017
1018 rtl_udelay_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
1019}
1020
1021static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
1022{
1023 void __iomem *ioaddr = tp->mmio_addr;
1024
1025 if (rtl_ocp_reg_failure(tp, reg))
1026 return 0;
1027
1028 RTL_W32(GPHY_OCP, reg << 15);
1029
1030 return rtl_udelay_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
1031 (RTL_R32(GPHY_OCP) & 0xffff) : ~0;
1032}
1033
1034static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
1035{
1036 int val;
1037
1038 val = r8168_phy_ocp_read(tp, reg);
1039 r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
1040}
1041
Hayes Wangc5583862012-07-02 17:23:22 +08001042static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
1043{
1044 void __iomem *ioaddr = tp->mmio_addr;
1045
1046 if (rtl_ocp_reg_failure(tp, reg))
1047 return;
1048
1049 RTL_W32(OCPDR, OCPAR_FLAG | (reg << 15) | data);
Hayes Wangc5583862012-07-02 17:23:22 +08001050}
1051
1052static u16 r8168_mac_ocp_read(struct rtl8169_private *tp, u32 reg)
1053{
1054 void __iomem *ioaddr = tp->mmio_addr;
1055
1056 if (rtl_ocp_reg_failure(tp, reg))
1057 return 0;
1058
1059 RTL_W32(OCPDR, reg << 15);
1060
Hayes Wang3a83ad12012-07-11 20:31:56 +08001061 return RTL_R32(OCPDR);
Hayes Wangc5583862012-07-02 17:23:22 +08001062}
1063
1064#define OCP_STD_PHY_BASE 0xa400
1065
1066static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
1067{
1068 if (reg == 0x1f) {
1069 tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
1070 return;
1071 }
1072
1073 if (tp->ocp_base != OCP_STD_PHY_BASE)
1074 reg -= 0x10;
1075
1076 r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
1077}
1078
1079static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
1080{
1081 if (tp->ocp_base != OCP_STD_PHY_BASE)
1082 reg -= 0x10;
1083
1084 return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
1085}
1086
Francois Romieuffc46952012-07-06 14:19:23 +02001087DECLARE_RTL_COND(rtl_phyar_cond)
1088{
1089 void __iomem *ioaddr = tp->mmio_addr;
1090
1091 return RTL_R32(PHYAR) & 0x80000000;
1092}
1093
Francois Romieu24192212012-07-06 20:19:42 +02001094static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Francois Romieu24192212012-07-06 20:19:42 +02001096 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Francois Romieu24192212012-07-06 20:19:42 +02001098 RTL_W32(PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Francois Romieuffc46952012-07-06 14:19:23 +02001100 rtl_udelay_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
Timo Teräs024a07b2010-06-06 15:38:47 -07001101 /*
Timo Teräs81a95f02010-06-09 17:31:48 -07001102 * According to hardware specs a 20us delay is required after write
1103 * complete indication, but before sending next command.
Timo Teräs024a07b2010-06-06 15:38:47 -07001104 */
Timo Teräs81a95f02010-06-09 17:31:48 -07001105 udelay(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
Francois Romieu24192212012-07-06 20:19:42 +02001108static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
Francois Romieu24192212012-07-06 20:19:42 +02001110 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieuffc46952012-07-06 14:19:23 +02001111 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
Francois Romieu24192212012-07-06 20:19:42 +02001113 RTL_W32(PHYAR, 0x0 | (reg & 0x1f) << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Francois Romieuffc46952012-07-06 14:19:23 +02001115 value = rtl_udelay_loop_wait_high(tp, &rtl_phyar_cond, 25, 20) ?
1116 RTL_R32(PHYAR) & 0xffff : ~0;
1117
Timo Teräs81a95f02010-06-09 17:31:48 -07001118 /*
1119 * According to hardware specs a 20us delay is required after read
1120 * complete indication, but before sending next command.
1121 */
1122 udelay(20);
1123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return value;
1125}
1126
Francois Romieu24192212012-07-06 20:19:42 +02001127static void r8168dp_1_mdio_access(struct rtl8169_private *tp, int reg, u32 data)
françois romieuc0e45c12011-01-03 15:08:04 +00001128{
Francois Romieu24192212012-07-06 20:19:42 +02001129 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001130
Francois Romieu24192212012-07-06 20:19:42 +02001131 RTL_W32(OCPDR, data | ((reg & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
françois romieuc0e45c12011-01-03 15:08:04 +00001132 RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
1133 RTL_W32(EPHY_RXER_NUM, 0);
1134
Francois Romieuffc46952012-07-06 14:19:23 +02001135 rtl_udelay_loop_wait_low(tp, &rtl_ocpar_cond, 1000, 100);
françois romieuc0e45c12011-01-03 15:08:04 +00001136}
1137
Francois Romieu24192212012-07-06 20:19:42 +02001138static void r8168dp_1_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieuc0e45c12011-01-03 15:08:04 +00001139{
Francois Romieu24192212012-07-06 20:19:42 +02001140 r8168dp_1_mdio_access(tp, reg,
1141 OCPDR_WRITE_CMD | (value & OCPDR_DATA_MASK));
françois romieuc0e45c12011-01-03 15:08:04 +00001142}
1143
Francois Romieu24192212012-07-06 20:19:42 +02001144static int r8168dp_1_mdio_read(struct rtl8169_private *tp, int reg)
françois romieuc0e45c12011-01-03 15:08:04 +00001145{
Francois Romieu24192212012-07-06 20:19:42 +02001146 void __iomem *ioaddr = tp->mmio_addr;
françois romieuc0e45c12011-01-03 15:08:04 +00001147
Francois Romieu24192212012-07-06 20:19:42 +02001148 r8168dp_1_mdio_access(tp, reg, OCPDR_READ_CMD);
françois romieuc0e45c12011-01-03 15:08:04 +00001149
1150 mdelay(1);
1151 RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
1152 RTL_W32(EPHY_RXER_NUM, 0);
1153
Francois Romieuffc46952012-07-06 14:19:23 +02001154 return rtl_udelay_loop_wait_high(tp, &rtl_ocpar_cond, 1000, 100) ?
1155 RTL_R32(OCPDR) & OCPDR_DATA_MASK : ~0;
françois romieuc0e45c12011-01-03 15:08:04 +00001156}
1157
françois romieue6de30d2011-01-03 15:08:37 +00001158#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
1159
1160static void r8168dp_2_mdio_start(void __iomem *ioaddr)
1161{
1162 RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
1163}
1164
1165static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
1166{
1167 RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
1168}
1169
Francois Romieu24192212012-07-06 20:19:42 +02001170static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
françois romieue6de30d2011-01-03 15:08:37 +00001171{
Francois Romieu24192212012-07-06 20:19:42 +02001172 void __iomem *ioaddr = tp->mmio_addr;
1173
françois romieue6de30d2011-01-03 15:08:37 +00001174 r8168dp_2_mdio_start(ioaddr);
1175
Francois Romieu24192212012-07-06 20:19:42 +02001176 r8169_mdio_write(tp, reg, value);
françois romieue6de30d2011-01-03 15:08:37 +00001177
1178 r8168dp_2_mdio_stop(ioaddr);
1179}
1180
Francois Romieu24192212012-07-06 20:19:42 +02001181static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
françois romieue6de30d2011-01-03 15:08:37 +00001182{
Francois Romieu24192212012-07-06 20:19:42 +02001183 void __iomem *ioaddr = tp->mmio_addr;
françois romieue6de30d2011-01-03 15:08:37 +00001184 int value;
1185
1186 r8168dp_2_mdio_start(ioaddr);
1187
Francois Romieu24192212012-07-06 20:19:42 +02001188 value = r8169_mdio_read(tp, reg);
françois romieue6de30d2011-01-03 15:08:37 +00001189
1190 r8168dp_2_mdio_stop(ioaddr);
1191
1192 return value;
1193}
1194
françois romieu4da19632011-01-03 15:07:55 +00001195static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
Francois Romieudacf8152008-08-02 20:44:13 +02001196{
Francois Romieu24192212012-07-06 20:19:42 +02001197 tp->mdio_ops.write(tp, location, val);
Francois Romieudacf8152008-08-02 20:44:13 +02001198}
1199
françois romieu4da19632011-01-03 15:07:55 +00001200static int rtl_readphy(struct rtl8169_private *tp, int location)
1201{
Francois Romieu24192212012-07-06 20:19:42 +02001202 return tp->mdio_ops.read(tp, location);
françois romieu4da19632011-01-03 15:07:55 +00001203}
1204
1205static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
1206{
1207 rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
1208}
1209
1210static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
françois romieudaf9df62009-10-07 12:44:20 +00001211{
1212 int val;
1213
françois romieu4da19632011-01-03 15:07:55 +00001214 val = rtl_readphy(tp, reg_addr);
1215 rtl_writephy(tp, reg_addr, (val | p) & ~m);
françois romieudaf9df62009-10-07 12:44:20 +00001216}
1217
Francois Romieuccdffb92008-07-26 14:26:06 +02001218static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
1219 int val)
1220{
1221 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001222
françois romieu4da19632011-01-03 15:07:55 +00001223 rtl_writephy(tp, location, val);
Francois Romieuccdffb92008-07-26 14:26:06 +02001224}
1225
1226static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
1227{
1228 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001229
françois romieu4da19632011-01-03 15:07:55 +00001230 return rtl_readphy(tp, location);
Francois Romieuccdffb92008-07-26 14:26:06 +02001231}
1232
Francois Romieuffc46952012-07-06 14:19:23 +02001233DECLARE_RTL_COND(rtl_ephyar_cond)
1234{
1235 void __iomem *ioaddr = tp->mmio_addr;
1236
1237 return RTL_R32(EPHYAR) & EPHYAR_FLAG;
1238}
1239
Francois Romieufdf6fc02012-07-06 22:40:38 +02001240static void rtl_ephy_write(struct rtl8169_private *tp, int reg_addr, int value)
Francois Romieudacf8152008-08-02 20:44:13 +02001241{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001242 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001243
1244 RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
1245 (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1246
Francois Romieuffc46952012-07-06 14:19:23 +02001247 rtl_udelay_loop_wait_low(tp, &rtl_ephyar_cond, 10, 100);
1248
1249 udelay(10);
Francois Romieudacf8152008-08-02 20:44:13 +02001250}
1251
Francois Romieufdf6fc02012-07-06 22:40:38 +02001252static u16 rtl_ephy_read(struct rtl8169_private *tp, int reg_addr)
Francois Romieudacf8152008-08-02 20:44:13 +02001253{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001254 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieudacf8152008-08-02 20:44:13 +02001255
1256 RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
1257
Francois Romieuffc46952012-07-06 14:19:23 +02001258 return rtl_udelay_loop_wait_high(tp, &rtl_ephyar_cond, 10, 100) ?
1259 RTL_R32(EPHYAR) & EPHYAR_DATA_MASK : ~0;
Francois Romieudacf8152008-08-02 20:44:13 +02001260}
1261
Francois Romieufdf6fc02012-07-06 22:40:38 +02001262static void rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
1263 u32 val, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001264{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001265 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001266
1267 BUG_ON((addr & 3) || (mask == 0));
1268 RTL_W32(ERIDR, val);
1269 RTL_W32(ERIAR, ERIAR_WRITE_CMD | type | mask | addr);
1270
Francois Romieuffc46952012-07-06 14:19:23 +02001271 rtl_udelay_loop_wait_low(tp, &rtl_eriar_cond, 100, 100);
Hayes Wang133ac402011-07-06 15:58:05 +08001272}
1273
Francois Romieufdf6fc02012-07-06 22:40:38 +02001274static u32 rtl_eri_read(struct rtl8169_private *tp, int addr, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001275{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001276 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang133ac402011-07-06 15:58:05 +08001277
1278 RTL_W32(ERIAR, ERIAR_READ_CMD | type | ERIAR_MASK_1111 | addr);
1279
Francois Romieuffc46952012-07-06 14:19:23 +02001280 return rtl_udelay_loop_wait_high(tp, &rtl_eriar_cond, 100, 100) ?
1281 RTL_R32(ERIDR) : ~0;
Hayes Wang133ac402011-07-06 15:58:05 +08001282}
1283
Francois Romieufdf6fc02012-07-06 22:40:38 +02001284static void rtl_w1w0_eri(struct rtl8169_private *tp, int addr, u32 mask, u32 p,
1285 u32 m, int type)
Hayes Wang133ac402011-07-06 15:58:05 +08001286{
1287 u32 val;
1288
Francois Romieufdf6fc02012-07-06 22:40:38 +02001289 val = rtl_eri_read(tp, addr, type);
1290 rtl_eri_write(tp, addr, mask, (val & ~m) | p, type);
Hayes Wang133ac402011-07-06 15:58:05 +08001291}
1292
françois romieuc28aa382011-08-02 03:53:43 +00001293struct exgmac_reg {
1294 u16 addr;
1295 u16 mask;
1296 u32 val;
1297};
1298
Francois Romieufdf6fc02012-07-06 22:40:38 +02001299static void rtl_write_exgmac_batch(struct rtl8169_private *tp,
françois romieuc28aa382011-08-02 03:53:43 +00001300 const struct exgmac_reg *r, int len)
1301{
1302 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001303 rtl_eri_write(tp, r->addr, r->mask, r->val, ERIAR_EXGMAC);
françois romieuc28aa382011-08-02 03:53:43 +00001304 r++;
1305 }
1306}
1307
Francois Romieuffc46952012-07-06 14:19:23 +02001308DECLARE_RTL_COND(rtl_efusear_cond)
1309{
1310 void __iomem *ioaddr = tp->mmio_addr;
1311
1312 return RTL_R32(EFUSEAR) & EFUSEAR_FLAG;
1313}
1314
Francois Romieufdf6fc02012-07-06 22:40:38 +02001315static u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr)
françois romieudaf9df62009-10-07 12:44:20 +00001316{
Francois Romieufdf6fc02012-07-06 22:40:38 +02001317 void __iomem *ioaddr = tp->mmio_addr;
françois romieudaf9df62009-10-07 12:44:20 +00001318
1319 RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
1320
Francois Romieuffc46952012-07-06 14:19:23 +02001321 return rtl_udelay_loop_wait_high(tp, &rtl_efusear_cond, 100, 300) ?
1322 RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK : ~0;
françois romieudaf9df62009-10-07 12:44:20 +00001323}
1324
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001325static u16 rtl_get_events(struct rtl8169_private *tp)
1326{
1327 void __iomem *ioaddr = tp->mmio_addr;
1328
1329 return RTL_R16(IntrStatus);
1330}
1331
1332static void rtl_ack_events(struct rtl8169_private *tp, u16 bits)
1333{
1334 void __iomem *ioaddr = tp->mmio_addr;
1335
1336 RTL_W16(IntrStatus, bits);
1337 mmiowb();
1338}
1339
1340static void rtl_irq_disable(struct rtl8169_private *tp)
1341{
1342 void __iomem *ioaddr = tp->mmio_addr;
1343
1344 RTL_W16(IntrMask, 0);
1345 mmiowb();
1346}
1347
Francois Romieu3e990ff2012-01-26 12:50:01 +01001348static void rtl_irq_enable(struct rtl8169_private *tp, u16 bits)
1349{
1350 void __iomem *ioaddr = tp->mmio_addr;
1351
1352 RTL_W16(IntrMask, bits);
1353}
1354
Francois Romieuda78dbf2012-01-26 14:18:23 +01001355#define RTL_EVENT_NAPI_RX (RxOK | RxErr)
1356#define RTL_EVENT_NAPI_TX (TxOK | TxErr)
1357#define RTL_EVENT_NAPI (RTL_EVENT_NAPI_RX | RTL_EVENT_NAPI_TX)
1358
1359static void rtl_irq_enable_all(struct rtl8169_private *tp)
1360{
1361 rtl_irq_enable(tp, RTL_EVENT_NAPI | tp->event_slow);
1362}
1363
françois romieu811fd302011-12-04 20:30:45 +00001364static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
françois romieu811fd302011-12-04 20:30:45 +00001366 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Francois Romieu9085cdfa2012-01-26 12:59:08 +01001368 rtl_irq_disable(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001369 rtl_ack_events(tp, RTL_EVENT_NAPI | tp->event_slow);
françois romieu811fd302011-12-04 20:30:45 +00001370 RTL_R8(ChipCmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371}
1372
françois romieu4da19632011-01-03 15:07:55 +00001373static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
françois romieu4da19632011-01-03 15:07:55 +00001375 void __iomem *ioaddr = tp->mmio_addr;
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 return RTL_R32(TBICSR) & TBIReset;
1378}
1379
françois romieu4da19632011-01-03 15:07:55 +00001380static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
françois romieu4da19632011-01-03 15:07:55 +00001382 return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383}
1384
1385static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
1386{
1387 return RTL_R32(TBICSR) & TBILinkOk;
1388}
1389
1390static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
1391{
1392 return RTL_R8(PHYstatus) & LinkStatus;
1393}
1394
françois romieu4da19632011-01-03 15:07:55 +00001395static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396{
françois romieu4da19632011-01-03 15:07:55 +00001397 void __iomem *ioaddr = tp->mmio_addr;
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
1400}
1401
françois romieu4da19632011-01-03 15:07:55 +00001402static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
1404 unsigned int val;
1405
françois romieu4da19632011-01-03 15:07:55 +00001406 val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
1407 rtl_writephy(tp, MII_BMCR, val & 0xffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408}
1409
Hayes Wang70090422011-07-06 15:58:06 +08001410static void rtl_link_chg_patch(struct rtl8169_private *tp)
1411{
1412 void __iomem *ioaddr = tp->mmio_addr;
1413 struct net_device *dev = tp->dev;
1414
1415 if (!netif_running(dev))
1416 return;
1417
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08001418 if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
1419 tp->mac_version == RTL_GIGA_MAC_VER_38) {
Hayes Wang70090422011-07-06 15:58:06 +08001420 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001421 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1422 ERIAR_EXGMAC);
1423 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1424 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001425 } else if (RTL_R8(PHYstatus) & _100bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001426 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1427 ERIAR_EXGMAC);
1428 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1429 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001430 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001431 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1432 ERIAR_EXGMAC);
1433 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1434 ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08001435 }
1436 /* Reset packet filter */
Francois Romieufdf6fc02012-07-06 22:40:38 +02001437 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01,
Hayes Wang70090422011-07-06 15:58:06 +08001438 ERIAR_EXGMAC);
Francois Romieufdf6fc02012-07-06 22:40:38 +02001439 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00,
Hayes Wang70090422011-07-06 15:58:06 +08001440 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001441 } else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
1442 tp->mac_version == RTL_GIGA_MAC_VER_36) {
1443 if (RTL_R8(PHYstatus) & _1000bpsF) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001444 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011,
1445 ERIAR_EXGMAC);
1446 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005,
1447 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001448 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001449 rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f,
1450 ERIAR_EXGMAC);
1451 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f,
1452 ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08001453 }
Hayes Wang7e18dca2012-03-30 14:33:02 +08001454 } else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
1455 if (RTL_R8(PHYstatus) & _10bps) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001456 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02,
1457 ERIAR_EXGMAC);
1458 rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060,
1459 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001460 } else {
Francois Romieufdf6fc02012-07-06 22:40:38 +02001461 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000,
1462 ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08001463 }
Hayes Wang70090422011-07-06 15:58:06 +08001464 }
1465}
1466
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001467static void __rtl8169_check_link_status(struct net_device *dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02001468 struct rtl8169_private *tp,
1469 void __iomem *ioaddr, bool pm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 if (tp->link_ok(ioaddr)) {
Hayes Wang70090422011-07-06 15:58:06 +08001472 rtl_link_chg_patch(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001473 /* This is to cancel a scheduled suspend if there's one. */
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001474 if (pm)
1475 pm_request_resume(&tp->pci_dev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 netif_carrier_on(dev);
Francois Romieu1519e572011-02-03 12:02:36 +01001477 if (net_ratelimit())
1478 netif_info(tp, ifup, dev, "link up\n");
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001479 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 netif_carrier_off(dev);
Joe Perchesbf82c182010-02-09 11:49:50 +00001481 netif_info(tp, ifdown, dev, "link down\n");
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001482 if (pm)
hayeswang10953db2011-11-07 20:44:37 +00001483 pm_schedule_suspend(&tp->pci_dev->dev, 5000);
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485}
1486
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00001487static void rtl8169_check_link_status(struct net_device *dev,
1488 struct rtl8169_private *tp,
1489 void __iomem *ioaddr)
1490{
1491 __rtl8169_check_link_status(dev, tp, ioaddr, false);
1492}
1493
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001494#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
1495
1496static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
1497{
1498 void __iomem *ioaddr = tp->mmio_addr;
1499 u8 options;
1500 u32 wolopts = 0;
1501
1502 options = RTL_R8(Config1);
1503 if (!(options & PMEnable))
1504 return 0;
1505
1506 options = RTL_R8(Config3);
1507 if (options & LinkUp)
1508 wolopts |= WAKE_PHY;
1509 if (options & MagicPacket)
1510 wolopts |= WAKE_MAGIC;
1511
1512 options = RTL_R8(Config5);
1513 if (options & UWF)
1514 wolopts |= WAKE_UCAST;
1515 if (options & BWF)
1516 wolopts |= WAKE_BCAST;
1517 if (options & MWF)
1518 wolopts |= WAKE_MCAST;
1519
1520 return wolopts;
1521}
1522
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001523static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1524{
1525 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001526
Francois Romieuda78dbf2012-01-26 14:18:23 +01001527 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001528
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001529 wol->supported = WAKE_ANY;
1530 wol->wolopts = __rtl8169_get_wol(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001531
Francois Romieuda78dbf2012-01-26 14:18:23 +01001532 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001533}
1534
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001535static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001536{
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001537 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu07d3f512007-02-21 22:40:46 +01001538 unsigned int i;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08001539 static const struct {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001540 u32 opt;
1541 u16 reg;
1542 u8 mask;
1543 } cfg[] = {
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001544 { WAKE_PHY, Config3, LinkUp },
1545 { WAKE_MAGIC, Config3, MagicPacket },
1546 { WAKE_UCAST, Config5, UWF },
1547 { WAKE_BCAST, Config5, BWF },
1548 { WAKE_MCAST, Config5, MWF },
1549 { WAKE_ANY, Config5, LanWake }
1550 };
Francois Romieu851e6022012-04-17 11:10:11 +02001551 u8 options;
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001552
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001553 RTL_W8(Cfg9346, Cfg9346_Unlock);
1554
1555 for (i = 0; i < ARRAY_SIZE(cfg); i++) {
Francois Romieu851e6022012-04-17 11:10:11 +02001556 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001557 if (wolopts & cfg[i].opt)
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001558 options |= cfg[i].mask;
1559 RTL_W8(cfg[i].reg, options);
1560 }
1561
Francois Romieu851e6022012-04-17 11:10:11 +02001562 switch (tp->mac_version) {
1563 case RTL_GIGA_MAC_VER_01 ... RTL_GIGA_MAC_VER_17:
1564 options = RTL_R8(Config1) & ~PMEnable;
1565 if (wolopts)
1566 options |= PMEnable;
1567 RTL_W8(Config1, options);
1568 break;
1569 default:
Francois Romieud387b422012-04-17 11:12:01 +02001570 options = RTL_R8(Config2) & ~PME_SIGNAL;
1571 if (wolopts)
1572 options |= PME_SIGNAL;
1573 RTL_W8(Config2, options);
Francois Romieu851e6022012-04-17 11:10:11 +02001574 break;
1575 }
1576
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001577 RTL_W8(Cfg9346, Cfg9346_Lock);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001578}
1579
1580static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
1581{
1582 struct rtl8169_private *tp = netdev_priv(dev);
1583
Francois Romieuda78dbf2012-01-26 14:18:23 +01001584 rtl_lock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001585
Francois Romieuf23e7fd2007-10-04 22:36:14 +02001586 if (wol->wolopts)
1587 tp->features |= RTL_FEATURE_WOL;
1588 else
1589 tp->features &= ~RTL_FEATURE_WOL;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00001590 __rtl8169_set_wol(tp, wol->wolopts);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001591
1592 rtl_unlock_work(tp);
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001593
françois romieuea809072010-11-08 13:23:58 +00001594 device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
1595
Francois Romieu61a4dcc2006-02-23 00:55:25 +01001596 return 0;
1597}
1598
Francois Romieu31bd2042011-04-26 18:58:59 +02001599static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
1600{
Francois Romieu85bffe62011-04-27 08:22:39 +02001601 return rtl_chip_infos[tp->mac_version].fw_name;
Francois Romieu31bd2042011-04-26 18:58:59 +02001602}
1603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604static void rtl8169_get_drvinfo(struct net_device *dev,
1605 struct ethtool_drvinfo *info)
1606{
1607 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieub6ffd972011-06-17 17:00:05 +02001608 struct rtl_fw *rtl_fw = tp->rtl_fw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Rick Jones68aad782011-11-07 13:29:27 +00001610 strlcpy(info->driver, MODULENAME, sizeof(info->driver));
1611 strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
1612 strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
Francois Romieu1c361ef2011-06-17 17:16:24 +02001613 BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
Rick Jones8ac72d12011-11-22 14:06:26 +00001614 if (!IS_ERR_OR_NULL(rtl_fw))
1615 strlcpy(info->fw_version, rtl_fw->version,
1616 sizeof(info->fw_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617}
1618
1619static int rtl8169_get_regs_len(struct net_device *dev)
1620{
1621 return R8169_REGS_SIZE;
1622}
1623
1624static int rtl8169_set_speed_tbi(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001625 u8 autoneg, u16 speed, u8 duplex, u32 ignored)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
1627 struct rtl8169_private *tp = netdev_priv(dev);
1628 void __iomem *ioaddr = tp->mmio_addr;
1629 int ret = 0;
1630 u32 reg;
1631
1632 reg = RTL_R32(TBICSR);
1633 if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
1634 (duplex == DUPLEX_FULL)) {
1635 RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
1636 } else if (autoneg == AUTONEG_ENABLE)
1637 RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
1638 else {
Joe Perchesbf82c182010-02-09 11:49:50 +00001639 netif_warn(tp, link, dev,
1640 "incorrect speed setting refused in TBI mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 ret = -EOPNOTSUPP;
1642 }
1643
1644 return ret;
1645}
1646
1647static int rtl8169_set_speed_xmii(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001648 u8 autoneg, u16 speed, u8 duplex, u32 adv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649{
1650 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu3577aa12009-05-19 10:46:48 +00001651 int giga_ctrl, bmcr;
Oliver Neukum54405cd2011-01-06 21:55:13 +01001652 int rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
Hayes Wang716b50a2011-02-22 17:26:18 +08001654 rtl_writephy(tp, 0x1f, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if (autoneg == AUTONEG_ENABLE) {
françois romieu3577aa12009-05-19 10:46:48 +00001657 int auto_nego;
1658
françois romieu4da19632011-01-03 15:07:55 +00001659 auto_nego = rtl_readphy(tp, MII_ADVERTISE);
Oliver Neukum54405cd2011-01-06 21:55:13 +01001660 auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
1661 ADVERTISE_100HALF | ADVERTISE_100FULL);
1662
1663 if (adv & ADVERTISED_10baseT_Half)
1664 auto_nego |= ADVERTISE_10HALF;
1665 if (adv & ADVERTISED_10baseT_Full)
1666 auto_nego |= ADVERTISE_10FULL;
1667 if (adv & ADVERTISED_100baseT_Half)
1668 auto_nego |= ADVERTISE_100HALF;
1669 if (adv & ADVERTISED_100baseT_Full)
1670 auto_nego |= ADVERTISE_100FULL;
1671
françois romieu3577aa12009-05-19 10:46:48 +00001672 auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1673
françois romieu4da19632011-01-03 15:07:55 +00001674 giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
françois romieu3577aa12009-05-19 10:46:48 +00001675 giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
1676
1677 /* The 8100e/8101e/8102e do Fast Ethernet only. */
Francois Romieu826e6cb2011-03-11 20:30:24 +01001678 if (tp->mii.supports_gmii) {
Oliver Neukum54405cd2011-01-06 21:55:13 +01001679 if (adv & ADVERTISED_1000baseT_Half)
1680 giga_ctrl |= ADVERTISE_1000HALF;
1681 if (adv & ADVERTISED_1000baseT_Full)
1682 giga_ctrl |= ADVERTISE_1000FULL;
1683 } else if (adv & (ADVERTISED_1000baseT_Half |
1684 ADVERTISED_1000baseT_Full)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00001685 netif_info(tp, link, dev,
1686 "PHY does not support 1000Mbps\n");
Oliver Neukum54405cd2011-01-06 21:55:13 +01001687 goto out;
Francois Romieubcf0bf92006-07-26 23:14:13 +02001688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
françois romieu3577aa12009-05-19 10:46:48 +00001690 bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
Francois Romieu623a1592006-05-14 12:42:14 +02001691
françois romieu4da19632011-01-03 15:07:55 +00001692 rtl_writephy(tp, MII_ADVERTISE, auto_nego);
1693 rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
françois romieu3577aa12009-05-19 10:46:48 +00001694 } else {
1695 giga_ctrl = 0;
1696
1697 if (speed == SPEED_10)
1698 bmcr = 0;
1699 else if (speed == SPEED_100)
1700 bmcr = BMCR_SPEED100;
1701 else
Oliver Neukum54405cd2011-01-06 21:55:13 +01001702 goto out;
françois romieu3577aa12009-05-19 10:46:48 +00001703
1704 if (duplex == DUPLEX_FULL)
1705 bmcr |= BMCR_FULLDPLX;
Roger So2584fbc2007-07-31 23:52:42 +02001706 }
1707
françois romieu4da19632011-01-03 15:07:55 +00001708 rtl_writephy(tp, MII_BMCR, bmcr);
françois romieu3577aa12009-05-19 10:46:48 +00001709
Francois Romieucecb5fd2011-04-01 10:21:07 +02001710 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
1711 tp->mac_version == RTL_GIGA_MAC_VER_03) {
françois romieu3577aa12009-05-19 10:46:48 +00001712 if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
françois romieu4da19632011-01-03 15:07:55 +00001713 rtl_writephy(tp, 0x17, 0x2138);
1714 rtl_writephy(tp, 0x0e, 0x0260);
françois romieu3577aa12009-05-19 10:46:48 +00001715 } else {
françois romieu4da19632011-01-03 15:07:55 +00001716 rtl_writephy(tp, 0x17, 0x2108);
1717 rtl_writephy(tp, 0x0e, 0x0000);
françois romieu3577aa12009-05-19 10:46:48 +00001718 }
1719 }
1720
Oliver Neukum54405cd2011-01-06 21:55:13 +01001721 rc = 0;
1722out:
1723 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724}
1725
1726static int rtl8169_set_speed(struct net_device *dev,
Oliver Neukum54405cd2011-01-06 21:55:13 +01001727 u8 autoneg, u16 speed, u8 duplex, u32 advertising)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
1729 struct rtl8169_private *tp = netdev_priv(dev);
1730 int ret;
1731
Oliver Neukum54405cd2011-01-06 21:55:13 +01001732 ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
Francois Romieu4876cc12011-03-11 21:07:11 +01001733 if (ret < 0)
1734 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Francois Romieu4876cc12011-03-11 21:07:11 +01001736 if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
1737 (advertising & ADVERTISED_1000baseT_Full)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
Francois Romieu4876cc12011-03-11 21:07:11 +01001739 }
1740out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 return ret;
1742}
1743
1744static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1745{
1746 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 int ret;
1748
Francois Romieu4876cc12011-03-11 21:07:11 +01001749 del_timer_sync(&tp->timer);
1750
Francois Romieuda78dbf2012-01-26 14:18:23 +01001751 rtl_lock_work(tp);
Francois Romieucecb5fd2011-04-01 10:21:07 +02001752 ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
David Decotigny25db0332011-04-27 18:32:39 +00001753 cmd->duplex, cmd->advertising);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001754 rtl_unlock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 return ret;
1757}
1758
Michał Mirosławc8f44af2011-11-15 15:29:55 +00001759static netdev_features_t rtl8169_fix_features(struct net_device *dev,
1760 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761{
Francois Romieud58d46b2011-05-03 16:38:29 +02001762 struct rtl8169_private *tp = netdev_priv(dev);
1763
Francois Romieu2b7b4312011-04-18 22:53:24 -07001764 if (dev->mtu > TD_MSS_MAX)
Michał Mirosław350fb322011-04-08 06:35:56 +00001765 features &= ~NETIF_F_ALL_TSO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Francois Romieud58d46b2011-05-03 16:38:29 +02001767 if (dev->mtu > JUMBO_1K &&
1768 !rtl_chip_infos[tp->mac_version].jumbo_tx_csum)
1769 features &= ~NETIF_F_IP_CSUM;
1770
Michał Mirosław350fb322011-04-08 06:35:56 +00001771 return features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772}
1773
Francois Romieuda78dbf2012-01-26 14:18:23 +01001774static void __rtl8169_set_features(struct net_device *dev,
1775 netdev_features_t features)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776{
1777 struct rtl8169_private *tp = netdev_priv(dev);
Ben Greear6bbe0212012-02-10 15:04:33 +00001778 netdev_features_t changed = features ^ dev->features;
Francois Romieuda78dbf2012-01-26 14:18:23 +01001779 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Ben Greear6bbe0212012-02-10 15:04:33 +00001781 if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
1782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
Ben Greear6bbe0212012-02-10 15:04:33 +00001784 if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
1785 if (features & NETIF_F_RXCSUM)
1786 tp->cp_cmd |= RxChkSum;
1787 else
1788 tp->cp_cmd &= ~RxChkSum;
Michał Mirosław350fb322011-04-08 06:35:56 +00001789
Ben Greear6bbe0212012-02-10 15:04:33 +00001790 if (dev->features & NETIF_F_HW_VLAN_RX)
1791 tp->cp_cmd |= RxVlan;
1792 else
1793 tp->cp_cmd &= ~RxVlan;
1794
1795 RTL_W16(CPlusCmd, tp->cp_cmd);
1796 RTL_R16(CPlusCmd);
1797 }
1798 if (changed & NETIF_F_RXALL) {
1799 int tmp = (RTL_R32(RxConfig) & ~(AcceptErr | AcceptRunt));
1800 if (features & NETIF_F_RXALL)
1801 tmp |= (AcceptErr | AcceptRunt);
1802 RTL_W32(RxConfig, tmp);
1803 }
Francois Romieuda78dbf2012-01-26 14:18:23 +01001804}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805
Francois Romieuda78dbf2012-01-26 14:18:23 +01001806static int rtl8169_set_features(struct net_device *dev,
1807 netdev_features_t features)
1808{
1809 struct rtl8169_private *tp = netdev_priv(dev);
1810
1811 rtl_lock_work(tp);
1812 __rtl8169_set_features(dev, features);
1813 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814
1815 return 0;
1816}
1817
Francois Romieuda78dbf2012-01-26 14:18:23 +01001818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
1820 struct sk_buff *skb)
1821{
Jesse Grosseab6d182010-10-20 13:56:03 +00001822 return (vlan_tx_tag_present(skb)) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
1824}
1825
Francois Romieu7a8fc772011-03-01 17:18:33 +01001826static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827{
1828 u32 opts2 = le32_to_cpu(desc->opts2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Francois Romieu7a8fc772011-03-01 17:18:33 +01001830 if (opts2 & RxVlanTag)
1831 __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
Eric Dumazet2edae082010-09-06 18:46:39 +00001832
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 desc->opts2 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834}
1835
Francois Romieuccdffb92008-07-26 14:26:06 +02001836static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837{
1838 struct rtl8169_private *tp = netdev_priv(dev);
1839 void __iomem *ioaddr = tp->mmio_addr;
1840 u32 status;
1841
1842 cmd->supported =
1843 SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
1844 cmd->port = PORT_FIBRE;
1845 cmd->transceiver = XCVR_INTERNAL;
1846
1847 status = RTL_R32(TBICSR);
1848 cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
1849 cmd->autoneg = !!(status & TBINwEnable);
1850
David Decotigny70739492011-04-27 18:32:40 +00001851 ethtool_cmd_speed_set(cmd, SPEED_1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 cmd->duplex = DUPLEX_FULL; /* Always set */
Francois Romieuccdffb92008-07-26 14:26:06 +02001853
1854 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855}
1856
Francois Romieuccdffb92008-07-26 14:26:06 +02001857static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
1859 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Francois Romieuccdffb92008-07-26 14:26:06 +02001861 return mii_ethtool_gset(&tp->mii, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
1864static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
1865{
1866 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieuccdffb92008-07-26 14:26:06 +02001867 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
Francois Romieuda78dbf2012-01-26 14:18:23 +01001869 rtl_lock_work(tp);
Francois Romieuccdffb92008-07-26 14:26:06 +02001870 rc = tp->get_settings(dev, cmd);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001871 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
Francois Romieuccdffb92008-07-26 14:26:06 +02001873 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874}
1875
1876static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
1877 void *p)
1878{
Francois Romieu5b0384f2006-08-16 16:00:01 +02001879 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
Francois Romieu5b0384f2006-08-16 16:00:01 +02001881 if (regs->len > R8169_REGS_SIZE)
1882 regs->len = R8169_REGS_SIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
Francois Romieuda78dbf2012-01-26 14:18:23 +01001884 rtl_lock_work(tp);
Francois Romieu5b0384f2006-08-16 16:00:01 +02001885 memcpy_fromio(p, tp->mmio_addr, regs->len);
Francois Romieuda78dbf2012-01-26 14:18:23 +01001886 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887}
1888
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02001889static u32 rtl8169_get_msglevel(struct net_device *dev)
1890{
1891 struct rtl8169_private *tp = netdev_priv(dev);
1892
1893 return tp->msg_enable;
1894}
1895
1896static void rtl8169_set_msglevel(struct net_device *dev, u32 value)
1897{
1898 struct rtl8169_private *tp = netdev_priv(dev);
1899
1900 tp->msg_enable = value;
1901}
1902
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001903static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
1904 "tx_packets",
1905 "rx_packets",
1906 "tx_errors",
1907 "rx_errors",
1908 "rx_missed",
1909 "align_errors",
1910 "tx_single_collisions",
1911 "tx_multi_collisions",
1912 "unicast",
1913 "broadcast",
1914 "multicast",
1915 "tx_aborted",
1916 "tx_underrun",
1917};
1918
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001919static int rtl8169_get_sset_count(struct net_device *dev, int sset)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001920{
Jeff Garzikb9f2c042007-10-03 18:07:32 -07001921 switch (sset) {
1922 case ETH_SS_STATS:
1923 return ARRAY_SIZE(rtl8169_gstrings);
1924 default:
1925 return -EOPNOTSUPP;
1926 }
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001927}
1928
Francois Romieuffc46952012-07-06 14:19:23 +02001929DECLARE_RTL_COND(rtl_counters_cond)
1930{
1931 void __iomem *ioaddr = tp->mmio_addr;
1932
1933 return RTL_R32(CounterAddrLow) & CounterDump;
1934}
1935
Ivan Vecera355423d2009-02-06 21:49:57 -08001936static void rtl8169_update_counters(struct net_device *dev)
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001937{
1938 struct rtl8169_private *tp = netdev_priv(dev);
1939 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieucecb5fd2011-04-01 10:21:07 +02001940 struct device *d = &tp->pci_dev->dev;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001941 struct rtl8169_counters *counters;
1942 dma_addr_t paddr;
1943 u32 cmd;
1944
Ivan Vecera355423d2009-02-06 21:49:57 -08001945 /*
1946 * Some chips are unable to dump tally counters when the receiver
1947 * is disabled.
1948 */
1949 if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
1950 return;
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001951
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001952 counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001953 if (!counters)
1954 return;
1955
1956 RTL_W32(CounterAddrHigh, (u64)paddr >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07001957 cmd = (u64)paddr & DMA_BIT_MASK(32);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001958 RTL_W32(CounterAddrLow, cmd);
1959 RTL_W32(CounterAddrLow, cmd | CounterDump);
1960
Francois Romieuffc46952012-07-06 14:19:23 +02001961 if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000))
1962 memcpy(&tp->counters, counters, sizeof(*counters));
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001963
1964 RTL_W32(CounterAddrLow, 0);
1965 RTL_W32(CounterAddrHigh, 0);
1966
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00001967 dma_free_coherent(d, sizeof(*counters), counters, paddr);
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001968}
1969
Ivan Vecera355423d2009-02-06 21:49:57 -08001970static void rtl8169_get_ethtool_stats(struct net_device *dev,
1971 struct ethtool_stats *stats, u64 *data)
1972{
1973 struct rtl8169_private *tp = netdev_priv(dev);
1974
1975 ASSERT_RTNL();
1976
1977 rtl8169_update_counters(dev);
1978
1979 data[0] = le64_to_cpu(tp->counters.tx_packets);
1980 data[1] = le64_to_cpu(tp->counters.rx_packets);
1981 data[2] = le64_to_cpu(tp->counters.tx_errors);
1982 data[3] = le32_to_cpu(tp->counters.rx_errors);
1983 data[4] = le16_to_cpu(tp->counters.rx_missed);
1984 data[5] = le16_to_cpu(tp->counters.align_errors);
1985 data[6] = le32_to_cpu(tp->counters.tx_one_collision);
1986 data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
1987 data[8] = le64_to_cpu(tp->counters.rx_unicast);
1988 data[9] = le64_to_cpu(tp->counters.rx_broadcast);
1989 data[10] = le32_to_cpu(tp->counters.rx_multicast);
1990 data[11] = le16_to_cpu(tp->counters.tx_aborted);
1991 data[12] = le16_to_cpu(tp->counters.tx_underun);
1992}
1993
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02001994static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
1995{
1996 switch(stringset) {
1997 case ETH_SS_STATS:
1998 memcpy(data, *rtl8169_gstrings, sizeof(rtl8169_gstrings));
1999 break;
2000 }
2001}
2002
Jeff Garzik7282d492006-09-13 14:30:00 -04002003static const struct ethtool_ops rtl8169_ethtool_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 .get_drvinfo = rtl8169_get_drvinfo,
2005 .get_regs_len = rtl8169_get_regs_len,
2006 .get_link = ethtool_op_get_link,
2007 .get_settings = rtl8169_get_settings,
2008 .set_settings = rtl8169_set_settings,
Stephen Hemmingerb57b7e52005-05-27 21:11:52 +02002009 .get_msglevel = rtl8169_get_msglevel,
2010 .set_msglevel = rtl8169_set_msglevel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 .get_regs = rtl8169_get_regs,
Francois Romieu61a4dcc2006-02-23 00:55:25 +01002012 .get_wol = rtl8169_get_wol,
2013 .set_wol = rtl8169_set_wol,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002014 .get_strings = rtl8169_get_strings,
Jeff Garzikb9f2c042007-10-03 18:07:32 -07002015 .get_sset_count = rtl8169_get_sset_count,
Stephen Hemmingerd4a3a0f2005-05-27 21:11:56 +02002016 .get_ethtool_stats = rtl8169_get_ethtool_stats,
Richard Cochrane1593bb2012-04-03 22:59:35 +00002017 .get_ts_info = ethtool_op_get_ts_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018};
2019
Francois Romieu07d3f512007-02-21 22:40:46 +01002020static void rtl8169_get_mac_version(struct rtl8169_private *tp,
Francois Romieu5d320a22011-05-08 17:47:36 +02002021 struct net_device *dev, u8 default_version)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
Francois Romieu5d320a22011-05-08 17:47:36 +02002023 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu0e485152007-02-20 00:00:26 +01002024 /*
2025 * The driver currently handles the 8168Bf and the 8168Be identically
2026 * but they can be identified more specifically through the test below
2027 * if needed:
2028 *
2029 * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
Francois Romieu01272152007-02-20 22:58:51 +01002030 *
2031 * Same thing for the 8101Eb and the 8101Ec:
2032 *
2033 * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
Francois Romieu0e485152007-02-20 00:00:26 +01002034 */
Francois Romieu37441002011-06-17 22:58:54 +02002035 static const struct rtl_mac_info {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 u32 mask;
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002037 u32 val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 int mac_version;
2039 } mac_info[] = {
Hayes Wangc5583862012-07-02 17:23:22 +08002040 /* 8168G family. */
2041 { 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
2042 { 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
2043
Hayes Wangc2218922011-09-06 16:55:18 +08002044 /* 8168F family. */
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08002045 { 0x7c800000, 0x48800000, RTL_GIGA_MAC_VER_38 },
Hayes Wangc2218922011-09-06 16:55:18 +08002046 { 0x7cf00000, 0x48100000, RTL_GIGA_MAC_VER_36 },
2047 { 0x7cf00000, 0x48000000, RTL_GIGA_MAC_VER_35 },
2048
hayeswang01dc7fe2011-03-21 01:50:28 +00002049 /* 8168E family. */
Hayes Wang70090422011-07-06 15:58:06 +08002050 { 0x7c800000, 0x2c800000, RTL_GIGA_MAC_VER_34 },
hayeswang01dc7fe2011-03-21 01:50:28 +00002051 { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
2052 { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
2053 { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
2054
Francois Romieu5b538df2008-07-20 16:22:45 +02002055 /* 8168D family. */
françois romieudaf9df62009-10-07 12:44:20 +00002056 { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
2057 { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
françois romieudaf9df62009-10-07 12:44:20 +00002058 { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002059
françois romieue6de30d2011-01-03 15:08:37 +00002060 /* 8168DP family. */
2061 { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
2062 { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
hayeswang4804b3b2011-03-21 01:50:29 +00002063 { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
françois romieue6de30d2011-01-03 15:08:37 +00002064
Francois Romieuef808d52008-06-29 13:10:54 +02002065 /* 8168C family. */
Francois Romieu17c99292010-07-11 17:10:09 -07002066 { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
Francois Romieuef3386f2008-06-29 12:24:30 +02002067 { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
Francois Romieuef808d52008-06-29 13:10:54 +02002068 { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
Francois Romieu7f3e3d32008-07-20 18:53:20 +02002069 { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002070 { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
2071 { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
Francois Romieu197ff762008-06-28 13:16:02 +02002072 { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
Francois Romieu6fb07052008-06-29 11:54:28 +02002073 { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
Francois Romieuef808d52008-06-29 13:10:54 +02002074 { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002075
2076 /* 8168B family. */
2077 { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
2078 { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
2079 { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
2080 { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
2081
2082 /* 8101 family. */
Hayes Wang5598bfe2012-07-02 17:23:21 +08002083 { 0x7cf00000, 0x44900000, RTL_GIGA_MAC_VER_39 },
2084 { 0x7c800000, 0x44800000, RTL_GIGA_MAC_VER_39 },
Hayes Wang7e18dca2012-03-30 14:33:02 +08002085 { 0x7c800000, 0x44000000, RTL_GIGA_MAC_VER_37 },
hayeswang36a0e6c2011-03-21 01:50:30 +00002086 { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
Hayes Wang5a5e4442011-02-22 17:26:21 +08002087 { 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
2088 { 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
2089 { 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002090 { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
2091 { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
2092 { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
2093 { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
2094 { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
2095 { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002096 { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002097 { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002098 { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
Francois Romieu2857ffb2008-08-02 21:08:49 +02002099 { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
2100 { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002101 { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
2102 /* FIXME: where did these entries come from ? -- FR */
2103 { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
2104 { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
2105
2106 /* 8110 family. */
2107 { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
2108 { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
2109 { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
2110 { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
2111 { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
2112 { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
2113
Jean Delvaref21b75e2009-05-26 20:54:48 -07002114 /* Catch-all */
2115 { 0x00000000, 0x00000000, RTL_GIGA_MAC_NONE }
Francois Romieu37441002011-06-17 22:58:54 +02002116 };
2117 const struct rtl_mac_info *p = mac_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 u32 reg;
2119
Francois Romieue3cf0cc2007-08-17 14:55:46 +02002120 reg = RTL_R32(TxConfig);
2121 while ((reg & p->mask) != p->val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 p++;
2123 tp->mac_version = p->mac_version;
Francois Romieu5d320a22011-05-08 17:47:36 +02002124
2125 if (tp->mac_version == RTL_GIGA_MAC_NONE) {
2126 netif_notice(tp, probe, dev,
2127 "unknown MAC, using family default\n");
2128 tp->mac_version = default_version;
2129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130}
2131
2132static void rtl8169_print_mac_version(struct rtl8169_private *tp)
2133{
Francois Romieubcf0bf92006-07-26 23:14:13 +02002134 dprintk("mac_version = 0x%02x\n", tp->mac_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135}
2136
Francois Romieu867763c2007-08-17 18:21:58 +02002137struct phy_reg {
2138 u16 reg;
2139 u16 val;
2140};
2141
françois romieu4da19632011-01-03 15:07:55 +00002142static void rtl_writephy_batch(struct rtl8169_private *tp,
2143 const struct phy_reg *regs, int len)
Francois Romieu867763c2007-08-17 18:21:58 +02002144{
2145 while (len-- > 0) {
françois romieu4da19632011-01-03 15:07:55 +00002146 rtl_writephy(tp, regs->reg, regs->val);
Francois Romieu867763c2007-08-17 18:21:58 +02002147 regs++;
2148 }
2149}
2150
françois romieubca03d52011-01-03 15:07:31 +00002151#define PHY_READ 0x00000000
2152#define PHY_DATA_OR 0x10000000
2153#define PHY_DATA_AND 0x20000000
2154#define PHY_BJMPN 0x30000000
2155#define PHY_READ_EFUSE 0x40000000
2156#define PHY_READ_MAC_BYTE 0x50000000
2157#define PHY_WRITE_MAC_BYTE 0x60000000
2158#define PHY_CLEAR_READCOUNT 0x70000000
2159#define PHY_WRITE 0x80000000
2160#define PHY_READCOUNT_EQ_SKIP 0x90000000
2161#define PHY_COMP_EQ_SKIPN 0xa0000000
2162#define PHY_COMP_NEQ_SKIPN 0xb0000000
2163#define PHY_WRITE_PREVIOUS 0xc0000000
2164#define PHY_SKIPN 0xd0000000
2165#define PHY_DELAY_MS 0xe0000000
2166#define PHY_WRITE_ERI_WORD 0xf0000000
2167
Hayes Wang960aee62011-06-18 11:37:48 +02002168struct fw_info {
2169 u32 magic;
2170 char version[RTL_VER_SIZE];
2171 __le32 fw_start;
2172 __le32 fw_len;
2173 u8 chksum;
2174} __packed;
2175
Francois Romieu1c361ef2011-06-17 17:16:24 +02002176#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code))
2177
2178static bool rtl_fw_format_ok(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
françois romieubca03d52011-01-03 15:07:31 +00002179{
Francois Romieub6ffd972011-06-17 17:00:05 +02002180 const struct firmware *fw = rtl_fw->fw;
Hayes Wang960aee62011-06-18 11:37:48 +02002181 struct fw_info *fw_info = (struct fw_info *)fw->data;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002182 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2183 char *version = rtl_fw->version;
2184 bool rc = false;
françois romieubca03d52011-01-03 15:07:31 +00002185
Francois Romieu1c361ef2011-06-17 17:16:24 +02002186 if (fw->size < FW_OPCODE_SIZE)
2187 goto out;
Hayes Wang960aee62011-06-18 11:37:48 +02002188
2189 if (!fw_info->magic) {
2190 size_t i, size, start;
2191 u8 checksum = 0;
2192
2193 if (fw->size < sizeof(*fw_info))
2194 goto out;
2195
2196 for (i = 0; i < fw->size; i++)
2197 checksum += fw->data[i];
2198 if (checksum != 0)
2199 goto out;
2200
2201 start = le32_to_cpu(fw_info->fw_start);
2202 if (start > fw->size)
2203 goto out;
2204
2205 size = le32_to_cpu(fw_info->fw_len);
2206 if (size > (fw->size - start) / FW_OPCODE_SIZE)
2207 goto out;
2208
2209 memcpy(version, fw_info->version, RTL_VER_SIZE);
2210
2211 pa->code = (__le32 *)(fw->data + start);
2212 pa->size = size;
2213 } else {
Francois Romieu1c361ef2011-06-17 17:16:24 +02002214 if (fw->size % FW_OPCODE_SIZE)
2215 goto out;
2216
2217 strlcpy(version, rtl_lookup_firmware_name(tp), RTL_VER_SIZE);
2218
2219 pa->code = (__le32 *)fw->data;
2220 pa->size = fw->size / FW_OPCODE_SIZE;
2221 }
2222 version[RTL_VER_SIZE - 1] = 0;
2223
2224 rc = true;
2225out:
2226 return rc;
2227}
2228
Francois Romieufd112f22011-06-18 00:10:29 +02002229static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
2230 struct rtl_fw_phy_action *pa)
Francois Romieu1c361ef2011-06-17 17:16:24 +02002231{
Francois Romieufd112f22011-06-18 00:10:29 +02002232 bool rc = false;
Francois Romieu1c361ef2011-06-17 17:16:24 +02002233 size_t index;
2234
Francois Romieu1c361ef2011-06-17 17:16:24 +02002235 for (index = 0; index < pa->size; index++) {
2236 u32 action = le32_to_cpu(pa->code[index]);
hayeswang42b82dc2011-01-10 02:07:25 +00002237 u32 regno = (action & 0x0fff0000) >> 16;
françois romieubca03d52011-01-03 15:07:31 +00002238
hayeswang42b82dc2011-01-10 02:07:25 +00002239 switch(action & 0xf0000000) {
2240 case PHY_READ:
2241 case PHY_DATA_OR:
2242 case PHY_DATA_AND:
2243 case PHY_READ_EFUSE:
2244 case PHY_CLEAR_READCOUNT:
2245 case PHY_WRITE:
2246 case PHY_WRITE_PREVIOUS:
2247 case PHY_DELAY_MS:
françois romieubca03d52011-01-03 15:07:31 +00002248 break;
2249
hayeswang42b82dc2011-01-10 02:07:25 +00002250 case PHY_BJMPN:
2251 if (regno > index) {
Francois Romieufd112f22011-06-18 00:10:29 +02002252 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002253 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002254 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002255 }
2256 break;
2257 case PHY_READCOUNT_EQ_SKIP:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002258 if (index + 2 >= 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 case PHY_COMP_EQ_SKIPN:
2265 case PHY_COMP_NEQ_SKIPN:
2266 case PHY_SKIPN:
Francois Romieu1c361ef2011-06-17 17:16:24 +02002267 if (index + 1 + regno >= pa->size) {
Francois Romieufd112f22011-06-18 00:10:29 +02002268 netif_err(tp, ifup, tp->dev,
Francois Romieucecb5fd2011-04-01 10:21:07 +02002269 "Out of range of firmware\n");
Francois Romieufd112f22011-06-18 00:10:29 +02002270 goto out;
hayeswang42b82dc2011-01-10 02:07:25 +00002271 }
2272 break;
2273
2274 case PHY_READ_MAC_BYTE:
2275 case PHY_WRITE_MAC_BYTE:
2276 case PHY_WRITE_ERI_WORD:
2277 default:
Francois Romieufd112f22011-06-18 00:10:29 +02002278 netif_err(tp, ifup, tp->dev,
hayeswang42b82dc2011-01-10 02:07:25 +00002279 "Invalid action 0x%08x\n", action);
Francois Romieufd112f22011-06-18 00:10:29 +02002280 goto out;
françois romieubca03d52011-01-03 15:07:31 +00002281 }
2282 }
Francois Romieufd112f22011-06-18 00:10:29 +02002283 rc = true;
2284out:
2285 return rc;
2286}
françois romieubca03d52011-01-03 15:07:31 +00002287
Francois Romieufd112f22011-06-18 00:10:29 +02002288static int rtl_check_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2289{
2290 struct net_device *dev = tp->dev;
2291 int rc = -EINVAL;
2292
2293 if (!rtl_fw_format_ok(tp, rtl_fw)) {
2294 netif_err(tp, ifup, dev, "invalid firwmare\n");
2295 goto out;
2296 }
2297
2298 if (rtl_fw_data_ok(tp, dev, &rtl_fw->phy_action))
2299 rc = 0;
2300out:
2301 return rc;
2302}
2303
2304static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
2305{
2306 struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
2307 u32 predata, count;
2308 size_t index;
2309
2310 predata = count = 0;
hayeswang42b82dc2011-01-10 02:07:25 +00002311
Francois Romieu1c361ef2011-06-17 17:16:24 +02002312 for (index = 0; index < pa->size; ) {
2313 u32 action = le32_to_cpu(pa->code[index]);
françois romieubca03d52011-01-03 15:07:31 +00002314 u32 data = action & 0x0000ffff;
hayeswang42b82dc2011-01-10 02:07:25 +00002315 u32 regno = (action & 0x0fff0000) >> 16;
2316
2317 if (!action)
2318 break;
françois romieubca03d52011-01-03 15:07:31 +00002319
2320 switch(action & 0xf0000000) {
hayeswang42b82dc2011-01-10 02:07:25 +00002321 case PHY_READ:
2322 predata = rtl_readphy(tp, regno);
2323 count++;
2324 index++;
françois romieubca03d52011-01-03 15:07:31 +00002325 break;
hayeswang42b82dc2011-01-10 02:07:25 +00002326 case PHY_DATA_OR:
2327 predata |= data;
2328 index++;
2329 break;
2330 case PHY_DATA_AND:
2331 predata &= data;
2332 index++;
2333 break;
2334 case PHY_BJMPN:
2335 index -= regno;
2336 break;
2337 case PHY_READ_EFUSE:
Francois Romieufdf6fc02012-07-06 22:40:38 +02002338 predata = rtl8168d_efuse_read(tp, regno);
hayeswang42b82dc2011-01-10 02:07:25 +00002339 index++;
2340 break;
2341 case PHY_CLEAR_READCOUNT:
2342 count = 0;
2343 index++;
2344 break;
2345 case PHY_WRITE:
2346 rtl_writephy(tp, regno, data);
2347 index++;
2348 break;
2349 case PHY_READCOUNT_EQ_SKIP:
Francois Romieucecb5fd2011-04-01 10:21:07 +02002350 index += (count == data) ? 2 : 1;
hayeswang42b82dc2011-01-10 02:07:25 +00002351 break;
2352 case PHY_COMP_EQ_SKIPN:
2353 if (predata == data)
2354 index += regno;
2355 index++;
2356 break;
2357 case PHY_COMP_NEQ_SKIPN:
2358 if (predata != data)
2359 index += regno;
2360 index++;
2361 break;
2362 case PHY_WRITE_PREVIOUS:
2363 rtl_writephy(tp, regno, predata);
2364 index++;
2365 break;
2366 case PHY_SKIPN:
2367 index += regno + 1;
2368 break;
2369 case PHY_DELAY_MS:
2370 mdelay(data);
2371 index++;
2372 break;
2373
2374 case PHY_READ_MAC_BYTE:
2375 case PHY_WRITE_MAC_BYTE:
2376 case PHY_WRITE_ERI_WORD:
françois romieubca03d52011-01-03 15:07:31 +00002377 default:
2378 BUG();
2379 }
2380 }
2381}
2382
françois romieuf1e02ed2011-01-13 13:07:53 +00002383static void rtl_release_firmware(struct rtl8169_private *tp)
2384{
Francois Romieub6ffd972011-06-17 17:00:05 +02002385 if (!IS_ERR_OR_NULL(tp->rtl_fw)) {
2386 release_firmware(tp->rtl_fw->fw);
2387 kfree(tp->rtl_fw);
2388 }
2389 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
françois romieuf1e02ed2011-01-13 13:07:53 +00002390}
2391
François Romieu953a12c2011-04-24 17:38:48 +02002392static void rtl_apply_firmware(struct rtl8169_private *tp)
françois romieuf1e02ed2011-01-13 13:07:53 +00002393{
Francois Romieub6ffd972011-06-17 17:00:05 +02002394 struct rtl_fw *rtl_fw = tp->rtl_fw;
françois romieuf1e02ed2011-01-13 13:07:53 +00002395
2396 /* TODO: release firmware once rtl_phy_write_fw signals failures. */
Francois Romieub6ffd972011-06-17 17:00:05 +02002397 if (!IS_ERR_OR_NULL(rtl_fw))
2398 rtl_phy_write_fw(tp, rtl_fw);
François Romieu953a12c2011-04-24 17:38:48 +02002399}
2400
2401static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
2402{
2403 if (rtl_readphy(tp, reg) != val)
2404 netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n");
2405 else
2406 rtl_apply_firmware(tp);
françois romieuf1e02ed2011-01-13 13:07:53 +00002407}
2408
françois romieu4da19632011-01-03 15:07:55 +00002409static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002411 static const struct phy_reg phy_reg_init[] = {
françois romieu0b9b5712009-08-10 19:44:56 +00002412 { 0x1f, 0x0001 },
2413 { 0x06, 0x006e },
2414 { 0x08, 0x0708 },
2415 { 0x15, 0x4000 },
2416 { 0x18, 0x65c7 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
françois romieu0b9b5712009-08-10 19:44:56 +00002418 { 0x1f, 0x0001 },
2419 { 0x03, 0x00a1 },
2420 { 0x02, 0x0008 },
2421 { 0x01, 0x0120 },
2422 { 0x00, 0x1000 },
2423 { 0x04, 0x0800 },
2424 { 0x04, 0x0000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
françois romieu0b9b5712009-08-10 19:44:56 +00002426 { 0x03, 0xff41 },
2427 { 0x02, 0xdf60 },
2428 { 0x01, 0x0140 },
2429 { 0x00, 0x0077 },
2430 { 0x04, 0x7800 },
2431 { 0x04, 0x7000 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
françois romieu0b9b5712009-08-10 19:44:56 +00002433 { 0x03, 0x802f },
2434 { 0x02, 0x4f02 },
2435 { 0x01, 0x0409 },
2436 { 0x00, 0xf0f9 },
2437 { 0x04, 0x9800 },
2438 { 0x04, 0x9000 },
2439
2440 { 0x03, 0xdf01 },
2441 { 0x02, 0xdf20 },
2442 { 0x01, 0xff95 },
2443 { 0x00, 0xba00 },
2444 { 0x04, 0xa800 },
2445 { 0x04, 0xa000 },
2446
2447 { 0x03, 0xff41 },
2448 { 0x02, 0xdf20 },
2449 { 0x01, 0x0140 },
2450 { 0x00, 0x00bb },
2451 { 0x04, 0xb800 },
2452 { 0x04, 0xb000 },
2453
2454 { 0x03, 0xdf41 },
2455 { 0x02, 0xdc60 },
2456 { 0x01, 0x6340 },
2457 { 0x00, 0x007d },
2458 { 0x04, 0xd800 },
2459 { 0x04, 0xd000 },
2460
2461 { 0x03, 0xdf01 },
2462 { 0x02, 0xdf20 },
2463 { 0x01, 0x100a },
2464 { 0x00, 0xa0ff },
2465 { 0x04, 0xf800 },
2466 { 0x04, 0xf000 },
2467
2468 { 0x1f, 0x0000 },
2469 { 0x0b, 0x0000 },
2470 { 0x00, 0x9200 }
2471 };
2472
françois romieu4da19632011-01-03 15:07:55 +00002473 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474}
2475
françois romieu4da19632011-01-03 15:07:55 +00002476static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5615d9f2007-08-17 17:50:46 +02002477{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002478 static const struct phy_reg phy_reg_init[] = {
Francois Romieua441d7b2007-08-17 18:26:35 +02002479 { 0x1f, 0x0002 },
2480 { 0x01, 0x90d0 },
2481 { 0x1f, 0x0000 }
2482 };
2483
françois romieu4da19632011-01-03 15:07:55 +00002484 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5615d9f2007-08-17 17:50:46 +02002485}
2486
françois romieu4da19632011-01-03 15:07:55 +00002487static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002488{
2489 struct pci_dev *pdev = tp->pci_dev;
françois romieu2e9558562009-08-10 19:44:19 +00002490
Sergei Shtylyovccbae552011-07-22 05:37:24 +00002491 if ((pdev->subsystem_vendor != PCI_VENDOR_ID_GIGABYTE) ||
2492 (pdev->subsystem_device != 0xe000))
françois romieu2e9558562009-08-10 19:44:19 +00002493 return;
2494
françois romieu4da19632011-01-03 15:07:55 +00002495 rtl_writephy(tp, 0x1f, 0x0001);
2496 rtl_writephy(tp, 0x10, 0xf01b);
2497 rtl_writephy(tp, 0x1f, 0x0000);
françois romieu2e9558562009-08-10 19:44:19 +00002498}
2499
françois romieu4da19632011-01-03 15:07:55 +00002500static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
françois romieu2e9558562009-08-10 19:44:19 +00002501{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002502 static const struct phy_reg phy_reg_init[] = {
françois romieu2e9558562009-08-10 19:44:19 +00002503 { 0x1f, 0x0001 },
2504 { 0x04, 0x0000 },
2505 { 0x03, 0x00a1 },
2506 { 0x02, 0x0008 },
2507 { 0x01, 0x0120 },
2508 { 0x00, 0x1000 },
2509 { 0x04, 0x0800 },
2510 { 0x04, 0x9000 },
2511 { 0x03, 0x802f },
2512 { 0x02, 0x4f02 },
2513 { 0x01, 0x0409 },
2514 { 0x00, 0xf099 },
2515 { 0x04, 0x9800 },
2516 { 0x04, 0xa000 },
2517 { 0x03, 0xdf01 },
2518 { 0x02, 0xdf20 },
2519 { 0x01, 0xff95 },
2520 { 0x00, 0xba00 },
2521 { 0x04, 0xa800 },
2522 { 0x04, 0xf000 },
2523 { 0x03, 0xdf01 },
2524 { 0x02, 0xdf20 },
2525 { 0x01, 0x101a },
2526 { 0x00, 0xa0ff },
2527 { 0x04, 0xf800 },
2528 { 0x04, 0x0000 },
2529 { 0x1f, 0x0000 },
2530
2531 { 0x1f, 0x0001 },
2532 { 0x10, 0xf41b },
2533 { 0x14, 0xfb54 },
2534 { 0x18, 0xf5c7 },
2535 { 0x1f, 0x0000 },
2536
2537 { 0x1f, 0x0001 },
2538 { 0x17, 0x0cc0 },
2539 { 0x1f, 0x0000 }
2540 };
2541
françois romieu4da19632011-01-03 15:07:55 +00002542 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu2e9558562009-08-10 19:44:19 +00002543
françois romieu4da19632011-01-03 15:07:55 +00002544 rtl8169scd_hw_phy_config_quirk(tp);
françois romieu2e9558562009-08-10 19:44:19 +00002545}
2546
françois romieu4da19632011-01-03 15:07:55 +00002547static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
françois romieu8c7006a2009-08-10 19:43:29 +00002548{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002549 static const struct phy_reg phy_reg_init[] = {
françois romieu8c7006a2009-08-10 19:43:29 +00002550 { 0x1f, 0x0001 },
2551 { 0x04, 0x0000 },
2552 { 0x03, 0x00a1 },
2553 { 0x02, 0x0008 },
2554 { 0x01, 0x0120 },
2555 { 0x00, 0x1000 },
2556 { 0x04, 0x0800 },
2557 { 0x04, 0x9000 },
2558 { 0x03, 0x802f },
2559 { 0x02, 0x4f02 },
2560 { 0x01, 0x0409 },
2561 { 0x00, 0xf099 },
2562 { 0x04, 0x9800 },
2563 { 0x04, 0xa000 },
2564 { 0x03, 0xdf01 },
2565 { 0x02, 0xdf20 },
2566 { 0x01, 0xff95 },
2567 { 0x00, 0xba00 },
2568 { 0x04, 0xa800 },
2569 { 0x04, 0xf000 },
2570 { 0x03, 0xdf01 },
2571 { 0x02, 0xdf20 },
2572 { 0x01, 0x101a },
2573 { 0x00, 0xa0ff },
2574 { 0x04, 0xf800 },
2575 { 0x04, 0x0000 },
2576 { 0x1f, 0x0000 },
2577
2578 { 0x1f, 0x0001 },
2579 { 0x0b, 0x8480 },
2580 { 0x1f, 0x0000 },
2581
2582 { 0x1f, 0x0001 },
2583 { 0x18, 0x67c7 },
2584 { 0x04, 0x2000 },
2585 { 0x03, 0x002f },
2586 { 0x02, 0x4360 },
2587 { 0x01, 0x0109 },
2588 { 0x00, 0x3022 },
2589 { 0x04, 0x2800 },
2590 { 0x1f, 0x0000 },
2591
2592 { 0x1f, 0x0001 },
2593 { 0x17, 0x0cc0 },
2594 { 0x1f, 0x0000 }
2595 };
2596
françois romieu4da19632011-01-03 15:07:55 +00002597 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieu8c7006a2009-08-10 19:43:29 +00002598}
2599
françois romieu4da19632011-01-03 15:07:55 +00002600static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002601{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002602 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002603 { 0x10, 0xf41b },
2604 { 0x1f, 0x0000 }
2605 };
2606
françois romieu4da19632011-01-03 15:07:55 +00002607 rtl_writephy(tp, 0x1f, 0x0001);
2608 rtl_patchphy(tp, 0x16, 1 << 0);
Francois Romieu236b8082008-05-30 16:11:48 +02002609
françois romieu4da19632011-01-03 15:07:55 +00002610 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002611}
2612
françois romieu4da19632011-01-03 15:07:55 +00002613static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu236b8082008-05-30 16:11:48 +02002614{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002615 static const struct phy_reg phy_reg_init[] = {
Francois Romieu236b8082008-05-30 16:11:48 +02002616 { 0x1f, 0x0001 },
2617 { 0x10, 0xf41b },
2618 { 0x1f, 0x0000 }
2619 };
2620
françois romieu4da19632011-01-03 15:07:55 +00002621 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu236b8082008-05-30 16:11:48 +02002622}
2623
françois romieu4da19632011-01-03 15:07:55 +00002624static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002625{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002626 static const struct phy_reg phy_reg_init[] = {
Francois Romieu867763c2007-08-17 18:21:58 +02002627 { 0x1f, 0x0000 },
2628 { 0x1d, 0x0f00 },
2629 { 0x1f, 0x0002 },
2630 { 0x0c, 0x1ec8 },
2631 { 0x1f, 0x0000 }
2632 };
2633
françois romieu4da19632011-01-03 15:07:55 +00002634 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu867763c2007-08-17 18:21:58 +02002635}
2636
françois romieu4da19632011-01-03 15:07:55 +00002637static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02002638{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002639 static const struct phy_reg phy_reg_init[] = {
Francois Romieuef3386f2008-06-29 12:24:30 +02002640 { 0x1f, 0x0001 },
2641 { 0x1d, 0x3d98 },
2642 { 0x1f, 0x0000 }
2643 };
2644
françois romieu4da19632011-01-03 15:07:55 +00002645 rtl_writephy(tp, 0x1f, 0x0000);
2646 rtl_patchphy(tp, 0x14, 1 << 5);
2647 rtl_patchphy(tp, 0x0d, 1 << 5);
Francois Romieuef3386f2008-06-29 12:24:30 +02002648
françois romieu4da19632011-01-03 15:07:55 +00002649 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuef3386f2008-06-29 12:24:30 +02002650}
2651
françois romieu4da19632011-01-03 15:07:55 +00002652static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu867763c2007-08-17 18:21:58 +02002653{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002654 static const struct phy_reg phy_reg_init[] = {
Francois Romieua3f80672007-10-18 14:35:11 +02002655 { 0x1f, 0x0001 },
2656 { 0x12, 0x2300 },
Francois Romieu867763c2007-08-17 18:21:58 +02002657 { 0x1f, 0x0002 },
2658 { 0x00, 0x88d4 },
2659 { 0x01, 0x82b1 },
2660 { 0x03, 0x7002 },
2661 { 0x08, 0x9e30 },
2662 { 0x09, 0x01f0 },
2663 { 0x0a, 0x5500 },
2664 { 0x0c, 0x00c8 },
2665 { 0x1f, 0x0003 },
2666 { 0x12, 0xc096 },
2667 { 0x16, 0x000a },
Francois Romieuf50d4272008-05-30 16:07:07 +02002668 { 0x1f, 0x0000 },
2669 { 0x1f, 0x0000 },
2670 { 0x09, 0x2000 },
2671 { 0x09, 0x0000 }
Francois Romieu867763c2007-08-17 18:21:58 +02002672 };
2673
françois romieu4da19632011-01-03 15:07:55 +00002674 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002675
françois romieu4da19632011-01-03 15:07:55 +00002676 rtl_patchphy(tp, 0x14, 1 << 5);
2677 rtl_patchphy(tp, 0x0d, 1 << 5);
2678 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu867763c2007-08-17 18:21:58 +02002679}
2680
françois romieu4da19632011-01-03 15:07:55 +00002681static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu7da97ec2007-10-18 15:20:43 +02002682{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002683 static const struct phy_reg phy_reg_init[] = {
Francois Romieuf50d4272008-05-30 16:07:07 +02002684 { 0x1f, 0x0001 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002685 { 0x12, 0x2300 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002686 { 0x03, 0x802f },
2687 { 0x02, 0x4f02 },
2688 { 0x01, 0x0409 },
2689 { 0x00, 0xf099 },
2690 { 0x04, 0x9800 },
2691 { 0x04, 0x9000 },
2692 { 0x1d, 0x3d98 },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002693 { 0x1f, 0x0002 },
2694 { 0x0c, 0x7eb8 },
Francois Romieuf50d4272008-05-30 16:07:07 +02002695 { 0x06, 0x0761 },
2696 { 0x1f, 0x0003 },
2697 { 0x16, 0x0f0a },
Francois Romieu7da97ec2007-10-18 15:20:43 +02002698 { 0x1f, 0x0000 }
2699 };
2700
françois romieu4da19632011-01-03 15:07:55 +00002701 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieuf50d4272008-05-30 16:07:07 +02002702
françois romieu4da19632011-01-03 15:07:55 +00002703 rtl_patchphy(tp, 0x16, 1 << 0);
2704 rtl_patchphy(tp, 0x14, 1 << 5);
2705 rtl_patchphy(tp, 0x0d, 1 << 5);
2706 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu7da97ec2007-10-18 15:20:43 +02002707}
2708
françois romieu4da19632011-01-03 15:07:55 +00002709static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02002710{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002711 static const struct phy_reg phy_reg_init[] = {
Francois Romieu197ff762008-06-28 13:16:02 +02002712 { 0x1f, 0x0001 },
2713 { 0x12, 0x2300 },
2714 { 0x1d, 0x3d98 },
2715 { 0x1f, 0x0002 },
2716 { 0x0c, 0x7eb8 },
2717 { 0x06, 0x5461 },
2718 { 0x1f, 0x0003 },
2719 { 0x16, 0x0f0a },
2720 { 0x1f, 0x0000 }
2721 };
2722
françois romieu4da19632011-01-03 15:07:55 +00002723 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu197ff762008-06-28 13:16:02 +02002724
françois romieu4da19632011-01-03 15:07:55 +00002725 rtl_patchphy(tp, 0x16, 1 << 0);
2726 rtl_patchphy(tp, 0x14, 1 << 5);
2727 rtl_patchphy(tp, 0x0d, 1 << 5);
2728 rtl_writephy(tp, 0x1f, 0x0000);
Francois Romieu197ff762008-06-28 13:16:02 +02002729}
2730
françois romieu4da19632011-01-03 15:07:55 +00002731static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02002732{
françois romieu4da19632011-01-03 15:07:55 +00002733 rtl8168c_3_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02002734}
2735
françois romieubca03d52011-01-03 15:07:31 +00002736static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02002737{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002738 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002739 /* Channel Estimation */
Francois Romieu5b538df2008-07-20 16:22:45 +02002740 { 0x1f, 0x0001 },
françois romieudaf9df62009-10-07 12:44:20 +00002741 { 0x06, 0x4064 },
2742 { 0x07, 0x2863 },
2743 { 0x08, 0x059c },
2744 { 0x09, 0x26b4 },
2745 { 0x0a, 0x6a19 },
2746 { 0x0b, 0xdcc8 },
2747 { 0x10, 0xf06d },
2748 { 0x14, 0x7f68 },
2749 { 0x18, 0x7fd9 },
2750 { 0x1c, 0xf0ff },
2751 { 0x1d, 0x3d9c },
Francois Romieu5b538df2008-07-20 16:22:45 +02002752 { 0x1f, 0x0003 },
françois romieudaf9df62009-10-07 12:44:20 +00002753 { 0x12, 0xf49f },
2754 { 0x13, 0x070b },
2755 { 0x1a, 0x05ad },
françois romieubca03d52011-01-03 15:07:31 +00002756 { 0x14, 0x94c0 },
2757
2758 /*
2759 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002760 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002761 */
Francois Romieu5b538df2008-07-20 16:22:45 +02002762 { 0x1f, 0x0002 },
françois romieudaf9df62009-10-07 12:44:20 +00002763 { 0x06, 0x5561 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002764 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002765 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002766 { 0x06, 0x5561 },
2767
2768 /*
2769 * Can not link to 1Gbps with bad cable
2770 * Decrease SNR threshold form 21.07dB to 19.04dB
2771 */
2772 { 0x1f, 0x0001 },
2773 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002774
2775 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002776 { 0x0d, 0xf880 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002777 };
2778
françois romieu4da19632011-01-03 15:07:55 +00002779 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
Francois Romieu5b538df2008-07-20 16:22:45 +02002780
françois romieubca03d52011-01-03 15:07:31 +00002781 /*
2782 * Rx Error Issue
2783 * Fine Tune Switching regulator parameter
2784 */
françois romieu4da19632011-01-03 15:07:55 +00002785 rtl_writephy(tp, 0x1f, 0x0002);
2786 rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
2787 rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
françois romieudaf9df62009-10-07 12:44:20 +00002788
Francois Romieufdf6fc02012-07-06 22:40:38 +02002789 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002790 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002791 { 0x1f, 0x0002 },
2792 { 0x05, 0x669a },
Francois Romieu5b538df2008-07-20 16:22:45 +02002793 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002794 { 0x05, 0x8330 },
2795 { 0x06, 0x669a },
2796 { 0x1f, 0x0002 }
2797 };
2798 int val;
2799
françois romieu4da19632011-01-03 15:07:55 +00002800 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002801
françois romieu4da19632011-01-03 15:07:55 +00002802 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002803
2804 if ((val & 0x00ff) != 0x006c) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002805 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002806 0x0065, 0x0066, 0x0067, 0x0068,
2807 0x0069, 0x006a, 0x006b, 0x006c
2808 };
2809 int i;
2810
françois romieu4da19632011-01-03 15:07:55 +00002811 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002812
2813 val &= 0xff00;
2814 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002815 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002816 }
2817 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002818 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002819 { 0x1f, 0x0002 },
2820 { 0x05, 0x6662 },
Francois Romieu5b538df2008-07-20 16:22:45 +02002821 { 0x1f, 0x0005 },
françois romieudaf9df62009-10-07 12:44:20 +00002822 { 0x05, 0x8330 },
2823 { 0x06, 0x6662 }
Francois Romieu5b538df2008-07-20 16:22:45 +02002824 };
2825
françois romieu4da19632011-01-03 15:07:55 +00002826 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02002827 }
2828
françois romieubca03d52011-01-03 15:07:31 +00002829 /* RSET couple improve */
françois romieu4da19632011-01-03 15:07:55 +00002830 rtl_writephy(tp, 0x1f, 0x0002);
2831 rtl_patchphy(tp, 0x0d, 0x0300);
2832 rtl_patchphy(tp, 0x0f, 0x0010);
françois romieudaf9df62009-10-07 12:44:20 +00002833
françois romieubca03d52011-01-03 15:07:31 +00002834 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002835 rtl_writephy(tp, 0x1f, 0x0002);
2836 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2837 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002838
françois romieu4da19632011-01-03 15:07:55 +00002839 rtl_writephy(tp, 0x1f, 0x0005);
2840 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002841
2842 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00);
françois romieubca03d52011-01-03 15:07:31 +00002843
françois romieu4da19632011-01-03 15:07:55 +00002844 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002845}
2846
françois romieubca03d52011-01-03 15:07:31 +00002847static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002848{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002849 static const struct phy_reg phy_reg_init_0[] = {
françois romieubca03d52011-01-03 15:07:31 +00002850 /* Channel Estimation */
françois romieudaf9df62009-10-07 12:44:20 +00002851 { 0x1f, 0x0001 },
2852 { 0x06, 0x4064 },
2853 { 0x07, 0x2863 },
2854 { 0x08, 0x059c },
2855 { 0x09, 0x26b4 },
2856 { 0x0a, 0x6a19 },
2857 { 0x0b, 0xdcc8 },
2858 { 0x10, 0xf06d },
2859 { 0x14, 0x7f68 },
2860 { 0x18, 0x7fd9 },
2861 { 0x1c, 0xf0ff },
2862 { 0x1d, 0x3d9c },
2863 { 0x1f, 0x0003 },
2864 { 0x12, 0xf49f },
2865 { 0x13, 0x070b },
2866 { 0x1a, 0x05ad },
2867 { 0x14, 0x94c0 },
2868
françois romieubca03d52011-01-03 15:07:31 +00002869 /*
2870 * Tx Error Issue
Francois Romieucecb5fd2011-04-01 10:21:07 +02002871 * Enhance line driver power
françois romieubca03d52011-01-03 15:07:31 +00002872 */
françois romieudaf9df62009-10-07 12:44:20 +00002873 { 0x1f, 0x0002 },
2874 { 0x06, 0x5561 },
2875 { 0x1f, 0x0005 },
2876 { 0x05, 0x8332 },
françois romieubca03d52011-01-03 15:07:31 +00002877 { 0x06, 0x5561 },
2878
2879 /*
2880 * Can not link to 1Gbps with bad cable
2881 * Decrease SNR threshold form 21.07dB to 19.04dB
2882 */
2883 { 0x1f, 0x0001 },
2884 { 0x17, 0x0cc0 },
françois romieudaf9df62009-10-07 12:44:20 +00002885
2886 { 0x1f, 0x0000 },
françois romieubca03d52011-01-03 15:07:31 +00002887 { 0x0d, 0xf880 }
françois romieudaf9df62009-10-07 12:44:20 +00002888 };
2889
françois romieu4da19632011-01-03 15:07:55 +00002890 rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
françois romieudaf9df62009-10-07 12:44:20 +00002891
Francois Romieufdf6fc02012-07-06 22:40:38 +02002892 if (rtl8168d_efuse_read(tp, 0x01) == 0xb1) {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002893 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002894 { 0x1f, 0x0002 },
2895 { 0x05, 0x669a },
2896 { 0x1f, 0x0005 },
2897 { 0x05, 0x8330 },
2898 { 0x06, 0x669a },
2899
2900 { 0x1f, 0x0002 }
2901 };
2902 int val;
2903
françois romieu4da19632011-01-03 15:07:55 +00002904 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002905
françois romieu4da19632011-01-03 15:07:55 +00002906 val = rtl_readphy(tp, 0x0d);
françois romieudaf9df62009-10-07 12:44:20 +00002907 if ((val & 0x00ff) != 0x006c) {
Joe Perchesb6bc7652010-12-21 02:16:08 -08002908 static const u32 set[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002909 0x0065, 0x0066, 0x0067, 0x0068,
2910 0x0069, 0x006a, 0x006b, 0x006c
2911 };
2912 int i;
2913
françois romieu4da19632011-01-03 15:07:55 +00002914 rtl_writephy(tp, 0x1f, 0x0002);
françois romieudaf9df62009-10-07 12:44:20 +00002915
2916 val &= 0xff00;
2917 for (i = 0; i < ARRAY_SIZE(set); i++)
françois romieu4da19632011-01-03 15:07:55 +00002918 rtl_writephy(tp, 0x0d, val | set[i]);
françois romieudaf9df62009-10-07 12:44:20 +00002919 }
2920 } else {
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002921 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002922 { 0x1f, 0x0002 },
2923 { 0x05, 0x2642 },
2924 { 0x1f, 0x0005 },
2925 { 0x05, 0x8330 },
2926 { 0x06, 0x2642 }
2927 };
2928
françois romieu4da19632011-01-03 15:07:55 +00002929 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
françois romieudaf9df62009-10-07 12:44:20 +00002930 }
2931
françois romieubca03d52011-01-03 15:07:31 +00002932 /* Fine tune PLL performance */
françois romieu4da19632011-01-03 15:07:55 +00002933 rtl_writephy(tp, 0x1f, 0x0002);
2934 rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
2935 rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
françois romieudaf9df62009-10-07 12:44:20 +00002936
françois romieubca03d52011-01-03 15:07:31 +00002937 /* Switching regulator Slew rate */
françois romieu4da19632011-01-03 15:07:55 +00002938 rtl_writephy(tp, 0x1f, 0x0002);
2939 rtl_patchphy(tp, 0x0f, 0x0017);
françois romieudaf9df62009-10-07 12:44:20 +00002940
françois romieu4da19632011-01-03 15:07:55 +00002941 rtl_writephy(tp, 0x1f, 0x0005);
2942 rtl_writephy(tp, 0x05, 0x001b);
François Romieu953a12c2011-04-24 17:38:48 +02002943
2944 rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300);
françois romieubca03d52011-01-03 15:07:31 +00002945
françois romieu4da19632011-01-03 15:07:55 +00002946 rtl_writephy(tp, 0x1f, 0x0000);
françois romieudaf9df62009-10-07 12:44:20 +00002947}
2948
françois romieu4da19632011-01-03 15:07:55 +00002949static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
françois romieudaf9df62009-10-07 12:44:20 +00002950{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08002951 static const struct phy_reg phy_reg_init[] = {
françois romieudaf9df62009-10-07 12:44:20 +00002952 { 0x1f, 0x0002 },
2953 { 0x10, 0x0008 },
2954 { 0x0d, 0x006c },
2955
2956 { 0x1f, 0x0000 },
2957 { 0x0d, 0xf880 },
2958
2959 { 0x1f, 0x0001 },
2960 { 0x17, 0x0cc0 },
2961
2962 { 0x1f, 0x0001 },
2963 { 0x0b, 0xa4d8 },
2964 { 0x09, 0x281c },
2965 { 0x07, 0x2883 },
2966 { 0x0a, 0x6b35 },
2967 { 0x1d, 0x3da4 },
2968 { 0x1c, 0xeffd },
2969 { 0x14, 0x7f52 },
2970 { 0x18, 0x7fc6 },
2971 { 0x08, 0x0601 },
2972 { 0x06, 0x4063 },
2973 { 0x10, 0xf074 },
2974 { 0x1f, 0x0003 },
2975 { 0x13, 0x0789 },
2976 { 0x12, 0xf4bd },
2977 { 0x1a, 0x04fd },
2978 { 0x14, 0x84b0 },
2979 { 0x1f, 0x0000 },
2980 { 0x00, 0x9200 },
2981
2982 { 0x1f, 0x0005 },
2983 { 0x01, 0x0340 },
2984 { 0x1f, 0x0001 },
2985 { 0x04, 0x4000 },
2986 { 0x03, 0x1d21 },
2987 { 0x02, 0x0c32 },
2988 { 0x01, 0x0200 },
2989 { 0x00, 0x5554 },
2990 { 0x04, 0x4800 },
2991 { 0x04, 0x4000 },
2992 { 0x04, 0xf000 },
2993 { 0x03, 0xdf01 },
2994 { 0x02, 0xdf20 },
2995 { 0x01, 0x101a },
2996 { 0x00, 0xa0ff },
2997 { 0x04, 0xf800 },
2998 { 0x04, 0xf000 },
2999 { 0x1f, 0x0000 },
3000
3001 { 0x1f, 0x0007 },
3002 { 0x1e, 0x0023 },
3003 { 0x16, 0x0000 },
3004 { 0x1f, 0x0000 }
3005 };
3006
françois romieu4da19632011-01-03 15:07:55 +00003007 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu5b538df2008-07-20 16:22:45 +02003008}
3009
françois romieue6de30d2011-01-03 15:08:37 +00003010static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
3011{
3012 static const struct phy_reg phy_reg_init[] = {
3013 { 0x1f, 0x0001 },
3014 { 0x17, 0x0cc0 },
3015
3016 { 0x1f, 0x0007 },
3017 { 0x1e, 0x002d },
3018 { 0x18, 0x0040 },
3019 { 0x1f, 0x0000 }
3020 };
3021
3022 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3023 rtl_patchphy(tp, 0x0d, 1 << 5);
3024}
3025
Hayes Wang70090422011-07-06 15:58:06 +08003026static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00003027{
3028 static const struct phy_reg phy_reg_init[] = {
3029 /* Enable Delay cap */
3030 { 0x1f, 0x0005 },
3031 { 0x05, 0x8b80 },
3032 { 0x06, 0xc896 },
3033 { 0x1f, 0x0000 },
3034
3035 /* Channel estimation fine tune */
3036 { 0x1f, 0x0001 },
3037 { 0x0b, 0x6c20 },
3038 { 0x07, 0x2872 },
3039 { 0x1c, 0xefff },
3040 { 0x1f, 0x0003 },
3041 { 0x14, 0x6420 },
3042 { 0x1f, 0x0000 },
3043
3044 /* Update PFM & 10M TX idle timer */
3045 { 0x1f, 0x0007 },
3046 { 0x1e, 0x002f },
3047 { 0x15, 0x1919 },
3048 { 0x1f, 0x0000 },
3049
3050 { 0x1f, 0x0007 },
3051 { 0x1e, 0x00ac },
3052 { 0x18, 0x0006 },
3053 { 0x1f, 0x0000 }
3054 };
3055
Francois Romieu15ecd032011-04-27 13:52:22 -07003056 rtl_apply_firmware(tp);
3057
hayeswang01dc7fe2011-03-21 01:50:28 +00003058 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3059
3060 /* DCO enable for 10M IDLE Power */
3061 rtl_writephy(tp, 0x1f, 0x0007);
3062 rtl_writephy(tp, 0x1e, 0x0023);
3063 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3064 rtl_writephy(tp, 0x1f, 0x0000);
3065
3066 /* For impedance matching */
3067 rtl_writephy(tp, 0x1f, 0x0002);
3068 rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
Francois Romieucecb5fd2011-04-01 10:21:07 +02003069 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003070
3071 /* PHY auto speed down */
3072 rtl_writephy(tp, 0x1f, 0x0007);
3073 rtl_writephy(tp, 0x1e, 0x002d);
3074 rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
3075 rtl_writephy(tp, 0x1f, 0x0000);
3076 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3077
3078 rtl_writephy(tp, 0x1f, 0x0005);
3079 rtl_writephy(tp, 0x05, 0x8b86);
3080 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3081 rtl_writephy(tp, 0x1f, 0x0000);
3082
3083 rtl_writephy(tp, 0x1f, 0x0005);
3084 rtl_writephy(tp, 0x05, 0x8b85);
3085 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3086 rtl_writephy(tp, 0x1f, 0x0007);
3087 rtl_writephy(tp, 0x1e, 0x0020);
3088 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
3089 rtl_writephy(tp, 0x1f, 0x0006);
3090 rtl_writephy(tp, 0x00, 0x5a00);
3091 rtl_writephy(tp, 0x1f, 0x0000);
3092 rtl_writephy(tp, 0x0d, 0x0007);
3093 rtl_writephy(tp, 0x0e, 0x003c);
3094 rtl_writephy(tp, 0x0d, 0x4007);
3095 rtl_writephy(tp, 0x0e, 0x0000);
3096 rtl_writephy(tp, 0x0d, 0x0000);
3097}
3098
Hayes Wang70090422011-07-06 15:58:06 +08003099static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
3100{
3101 static const struct phy_reg phy_reg_init[] = {
3102 /* Enable Delay cap */
3103 { 0x1f, 0x0004 },
3104 { 0x1f, 0x0007 },
3105 { 0x1e, 0x00ac },
3106 { 0x18, 0x0006 },
3107 { 0x1f, 0x0002 },
3108 { 0x1f, 0x0000 },
3109 { 0x1f, 0x0000 },
3110
3111 /* Channel estimation fine tune */
3112 { 0x1f, 0x0003 },
3113 { 0x09, 0xa20f },
3114 { 0x1f, 0x0000 },
3115 { 0x1f, 0x0000 },
3116
3117 /* Green Setting */
3118 { 0x1f, 0x0005 },
3119 { 0x05, 0x8b5b },
3120 { 0x06, 0x9222 },
3121 { 0x05, 0x8b6d },
3122 { 0x06, 0x8000 },
3123 { 0x05, 0x8b76 },
3124 { 0x06, 0x8000 },
3125 { 0x1f, 0x0000 }
3126 };
3127
3128 rtl_apply_firmware(tp);
3129
3130 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3131
3132 /* For 4-corner performance improve */
3133 rtl_writephy(tp, 0x1f, 0x0005);
3134 rtl_writephy(tp, 0x05, 0x8b80);
3135 rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
3136 rtl_writephy(tp, 0x1f, 0x0000);
3137
3138 /* PHY auto speed down */
3139 rtl_writephy(tp, 0x1f, 0x0004);
3140 rtl_writephy(tp, 0x1f, 0x0007);
3141 rtl_writephy(tp, 0x1e, 0x002d);
3142 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3143 rtl_writephy(tp, 0x1f, 0x0002);
3144 rtl_writephy(tp, 0x1f, 0x0000);
3145 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3146
3147 /* improve 10M EEE waveform */
3148 rtl_writephy(tp, 0x1f, 0x0005);
3149 rtl_writephy(tp, 0x05, 0x8b86);
3150 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3151 rtl_writephy(tp, 0x1f, 0x0000);
3152
3153 /* Improve 2-pair detection performance */
3154 rtl_writephy(tp, 0x1f, 0x0005);
3155 rtl_writephy(tp, 0x05, 0x8b85);
3156 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3157 rtl_writephy(tp, 0x1f, 0x0000);
3158
3159 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003160 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_1111, 0x0000, 0x0003, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08003161 rtl_writephy(tp, 0x1f, 0x0005);
3162 rtl_writephy(tp, 0x05, 0x8b85);
3163 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3164 rtl_writephy(tp, 0x1f, 0x0004);
3165 rtl_writephy(tp, 0x1f, 0x0007);
3166 rtl_writephy(tp, 0x1e, 0x0020);
David S. Miller1805b2f2011-10-24 18:18:09 -04003167 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
Hayes Wang70090422011-07-06 15:58:06 +08003168 rtl_writephy(tp, 0x1f, 0x0002);
3169 rtl_writephy(tp, 0x1f, 0x0000);
3170 rtl_writephy(tp, 0x0d, 0x0007);
3171 rtl_writephy(tp, 0x0e, 0x003c);
3172 rtl_writephy(tp, 0x0d, 0x4007);
3173 rtl_writephy(tp, 0x0e, 0x0000);
3174 rtl_writephy(tp, 0x0d, 0x0000);
3175
3176 /* Green feature */
3177 rtl_writephy(tp, 0x1f, 0x0003);
3178 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3179 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3180 rtl_writephy(tp, 0x1f, 0x0000);
3181}
3182
Hayes Wang5f886e02012-03-30 14:33:03 +08003183static void rtl8168f_hw_phy_config(struct rtl8169_private *tp)
3184{
3185 /* For 4-corner performance improve */
3186 rtl_writephy(tp, 0x1f, 0x0005);
3187 rtl_writephy(tp, 0x05, 0x8b80);
3188 rtl_w1w0_phy(tp, 0x06, 0x0006, 0x0000);
3189 rtl_writephy(tp, 0x1f, 0x0000);
3190
3191 /* PHY auto speed down */
3192 rtl_writephy(tp, 0x1f, 0x0007);
3193 rtl_writephy(tp, 0x1e, 0x002d);
3194 rtl_w1w0_phy(tp, 0x18, 0x0010, 0x0000);
3195 rtl_writephy(tp, 0x1f, 0x0000);
3196 rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
3197
3198 /* Improve 10M EEE waveform */
3199 rtl_writephy(tp, 0x1f, 0x0005);
3200 rtl_writephy(tp, 0x05, 0x8b86);
3201 rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
3202 rtl_writephy(tp, 0x1f, 0x0000);
3203}
3204
Hayes Wangc2218922011-09-06 16:55:18 +08003205static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
3206{
3207 static const struct phy_reg phy_reg_init[] = {
3208 /* Channel estimation fine tune */
3209 { 0x1f, 0x0003 },
3210 { 0x09, 0xa20f },
3211 { 0x1f, 0x0000 },
3212
3213 /* Modify green table for giga & fnet */
3214 { 0x1f, 0x0005 },
3215 { 0x05, 0x8b55 },
3216 { 0x06, 0x0000 },
3217 { 0x05, 0x8b5e },
3218 { 0x06, 0x0000 },
3219 { 0x05, 0x8b67 },
3220 { 0x06, 0x0000 },
3221 { 0x05, 0x8b70 },
3222 { 0x06, 0x0000 },
3223 { 0x1f, 0x0000 },
3224 { 0x1f, 0x0007 },
3225 { 0x1e, 0x0078 },
3226 { 0x17, 0x0000 },
3227 { 0x19, 0x00fb },
3228 { 0x1f, 0x0000 },
3229
3230 /* Modify green table for 10M */
3231 { 0x1f, 0x0005 },
3232 { 0x05, 0x8b79 },
3233 { 0x06, 0xaa00 },
3234 { 0x1f, 0x0000 },
3235
3236 /* Disable hiimpedance detection (RTCT) */
3237 { 0x1f, 0x0003 },
3238 { 0x01, 0x328a },
3239 { 0x1f, 0x0000 }
3240 };
3241
3242 rtl_apply_firmware(tp);
3243
3244 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3245
Hayes Wang5f886e02012-03-30 14:33:03 +08003246 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003247
3248 /* Improve 2-pair detection performance */
3249 rtl_writephy(tp, 0x1f, 0x0005);
3250 rtl_writephy(tp, 0x05, 0x8b85);
3251 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3252 rtl_writephy(tp, 0x1f, 0x0000);
3253}
3254
3255static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
3256{
3257 rtl_apply_firmware(tp);
3258
Hayes Wang5f886e02012-03-30 14:33:03 +08003259 rtl8168f_hw_phy_config(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08003260}
3261
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003262static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
3263{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003264 static const struct phy_reg phy_reg_init[] = {
3265 /* Channel estimation fine tune */
3266 { 0x1f, 0x0003 },
3267 { 0x09, 0xa20f },
3268 { 0x1f, 0x0000 },
3269
3270 /* Modify green table for giga & fnet */
3271 { 0x1f, 0x0005 },
3272 { 0x05, 0x8b55 },
3273 { 0x06, 0x0000 },
3274 { 0x05, 0x8b5e },
3275 { 0x06, 0x0000 },
3276 { 0x05, 0x8b67 },
3277 { 0x06, 0x0000 },
3278 { 0x05, 0x8b70 },
3279 { 0x06, 0x0000 },
3280 { 0x1f, 0x0000 },
3281 { 0x1f, 0x0007 },
3282 { 0x1e, 0x0078 },
3283 { 0x17, 0x0000 },
3284 { 0x19, 0x00aa },
3285 { 0x1f, 0x0000 },
3286
3287 /* Modify green table for 10M */
3288 { 0x1f, 0x0005 },
3289 { 0x05, 0x8b79 },
3290 { 0x06, 0xaa00 },
3291 { 0x1f, 0x0000 },
3292
3293 /* Disable hiimpedance detection (RTCT) */
3294 { 0x1f, 0x0003 },
3295 { 0x01, 0x328a },
3296 { 0x1f, 0x0000 }
3297 };
3298
3299
3300 rtl_apply_firmware(tp);
3301
3302 rtl8168f_hw_phy_config(tp);
3303
3304 /* Improve 2-pair detection performance */
3305 rtl_writephy(tp, 0x1f, 0x0005);
3306 rtl_writephy(tp, 0x05, 0x8b85);
3307 rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
3308 rtl_writephy(tp, 0x1f, 0x0000);
3309
3310 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3311
3312 /* Modify green table for giga */
3313 rtl_writephy(tp, 0x1f, 0x0005);
3314 rtl_writephy(tp, 0x05, 0x8b54);
3315 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3316 rtl_writephy(tp, 0x05, 0x8b5d);
3317 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0800);
3318 rtl_writephy(tp, 0x05, 0x8a7c);
3319 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3320 rtl_writephy(tp, 0x05, 0x8a7f);
3321 rtl_w1w0_phy(tp, 0x06, 0x0100, 0x0000);
3322 rtl_writephy(tp, 0x05, 0x8a82);
3323 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3324 rtl_writephy(tp, 0x05, 0x8a85);
3325 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3326 rtl_writephy(tp, 0x05, 0x8a88);
3327 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x0100);
3328 rtl_writephy(tp, 0x1f, 0x0000);
3329
3330 /* uc same-seed solution */
3331 rtl_writephy(tp, 0x1f, 0x0005);
3332 rtl_writephy(tp, 0x05, 0x8b85);
3333 rtl_w1w0_phy(tp, 0x06, 0x8000, 0x0000);
3334 rtl_writephy(tp, 0x1f, 0x0000);
3335
3336 /* eee setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003337 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x00, 0x03, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003338 rtl_writephy(tp, 0x1f, 0x0005);
3339 rtl_writephy(tp, 0x05, 0x8b85);
3340 rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
3341 rtl_writephy(tp, 0x1f, 0x0004);
3342 rtl_writephy(tp, 0x1f, 0x0007);
3343 rtl_writephy(tp, 0x1e, 0x0020);
3344 rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0100);
3345 rtl_writephy(tp, 0x1f, 0x0000);
3346 rtl_writephy(tp, 0x0d, 0x0007);
3347 rtl_writephy(tp, 0x0e, 0x003c);
3348 rtl_writephy(tp, 0x0d, 0x4007);
3349 rtl_writephy(tp, 0x0e, 0x0000);
3350 rtl_writephy(tp, 0x0d, 0x0000);
3351
3352 /* Green feature */
3353 rtl_writephy(tp, 0x1f, 0x0003);
3354 rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
3355 rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
3356 rtl_writephy(tp, 0x1f, 0x0000);
3357}
3358
Hayes Wangc5583862012-07-02 17:23:22 +08003359static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
3360{
3361 static const u16 mac_ocp_patch[] = {
3362 0xe008, 0xe01b, 0xe01d, 0xe01f,
3363 0xe021, 0xe023, 0xe025, 0xe027,
3364 0x49d2, 0xf10d, 0x766c, 0x49e2,
3365 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
3366
3367 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
3368 0xc707, 0x8ee1, 0x9d6c, 0xc603,
3369 0xbe00, 0xb416, 0x0076, 0xe86c,
3370 0xc602, 0xbe00, 0x0000, 0xc602,
3371
3372 0xbe00, 0x0000, 0xc602, 0xbe00,
3373 0x0000, 0xc602, 0xbe00, 0x0000,
3374 0xc602, 0xbe00, 0x0000, 0xc602,
3375 0xbe00, 0x0000, 0xc602, 0xbe00,
3376
3377 0x0000, 0x0000, 0x0000, 0x0000
3378 };
3379 u32 i;
3380
3381 /* Patch code for GPHY reset */
3382 for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
3383 r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
3384 r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
3385 r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
3386
3387 rtl_apply_firmware(tp);
3388
3389 if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
3390 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
3391 else
3392 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
3393
3394 if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
3395 rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
3396 else
3397 rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
3398
3399 rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
3400 rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
3401
3402 r8168_phy_ocp_write(tp, 0xa436, 0x8012);
3403 rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
3404
3405 rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
3406}
3407
françois romieu4da19632011-01-03 15:07:55 +00003408static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02003409{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08003410 static const struct phy_reg phy_reg_init[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02003411 { 0x1f, 0x0003 },
3412 { 0x08, 0x441d },
3413 { 0x01, 0x9100 },
3414 { 0x1f, 0x0000 }
3415 };
3416
françois romieu4da19632011-01-03 15:07:55 +00003417 rtl_writephy(tp, 0x1f, 0x0000);
3418 rtl_patchphy(tp, 0x11, 1 << 12);
3419 rtl_patchphy(tp, 0x19, 1 << 13);
3420 rtl_patchphy(tp, 0x10, 1 << 15);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003421
françois romieu4da19632011-01-03 15:07:55 +00003422 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
Francois Romieu2857ffb2008-08-02 21:08:49 +02003423}
3424
Hayes Wang5a5e4442011-02-22 17:26:21 +08003425static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
3426{
3427 static const struct phy_reg phy_reg_init[] = {
3428 { 0x1f, 0x0005 },
3429 { 0x1a, 0x0000 },
3430 { 0x1f, 0x0000 },
3431
3432 { 0x1f, 0x0004 },
3433 { 0x1c, 0x0000 },
3434 { 0x1f, 0x0000 },
3435
3436 { 0x1f, 0x0001 },
3437 { 0x15, 0x7701 },
3438 { 0x1f, 0x0000 }
3439 };
3440
3441 /* Disable ALDPS before ram code */
3442 rtl_writephy(tp, 0x1f, 0x0000);
3443 rtl_writephy(tp, 0x18, 0x0310);
3444 msleep(100);
3445
François Romieu953a12c2011-04-24 17:38:48 +02003446 rtl_apply_firmware(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08003447
3448 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3449}
3450
Hayes Wang7e18dca2012-03-30 14:33:02 +08003451static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
3452{
Hayes Wang7e18dca2012-03-30 14:33:02 +08003453 /* Disable ALDPS before setting firmware */
3454 rtl_writephy(tp, 0x1f, 0x0000);
3455 rtl_writephy(tp, 0x18, 0x0310);
3456 msleep(20);
3457
3458 rtl_apply_firmware(tp);
3459
3460 /* EEE setting */
Francois Romieufdf6fc02012-07-06 22:40:38 +02003461 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08003462 rtl_writephy(tp, 0x1f, 0x0004);
3463 rtl_writephy(tp, 0x10, 0x401f);
3464 rtl_writephy(tp, 0x19, 0x7030);
3465 rtl_writephy(tp, 0x1f, 0x0000);
3466}
3467
Hayes Wang5598bfe2012-07-02 17:23:21 +08003468static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
3469{
Hayes Wang5598bfe2012-07-02 17:23:21 +08003470 static const struct phy_reg phy_reg_init[] = {
3471 { 0x1f, 0x0004 },
3472 { 0x10, 0xc07f },
3473 { 0x19, 0x7030 },
3474 { 0x1f, 0x0000 }
3475 };
3476
3477 /* Disable ALDPS before ram code */
3478 rtl_writephy(tp, 0x1f, 0x0000);
3479 rtl_writephy(tp, 0x18, 0x0310);
3480 msleep(100);
3481
3482 rtl_apply_firmware(tp);
3483
Francois Romieufdf6fc02012-07-06 22:40:38 +02003484 rtl_eri_write(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003485 rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
3486
Francois Romieufdf6fc02012-07-06 22:40:38 +02003487 rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
Hayes Wang5598bfe2012-07-02 17:23:21 +08003488}
3489
Francois Romieu5615d9f2007-08-17 17:50:46 +02003490static void rtl_hw_phy_config(struct net_device *dev)
3491{
3492 struct rtl8169_private *tp = netdev_priv(dev);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003493
3494 rtl8169_print_mac_version(tp);
3495
3496 switch (tp->mac_version) {
3497 case RTL_GIGA_MAC_VER_01:
3498 break;
3499 case RTL_GIGA_MAC_VER_02:
3500 case RTL_GIGA_MAC_VER_03:
françois romieu4da19632011-01-03 15:07:55 +00003501 rtl8169s_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003502 break;
3503 case RTL_GIGA_MAC_VER_04:
françois romieu4da19632011-01-03 15:07:55 +00003504 rtl8169sb_hw_phy_config(tp);
Francois Romieu5615d9f2007-08-17 17:50:46 +02003505 break;
françois romieu2e9558562009-08-10 19:44:19 +00003506 case RTL_GIGA_MAC_VER_05:
françois romieu4da19632011-01-03 15:07:55 +00003507 rtl8169scd_hw_phy_config(tp);
françois romieu2e9558562009-08-10 19:44:19 +00003508 break;
françois romieu8c7006a2009-08-10 19:43:29 +00003509 case RTL_GIGA_MAC_VER_06:
françois romieu4da19632011-01-03 15:07:55 +00003510 rtl8169sce_hw_phy_config(tp);
françois romieu8c7006a2009-08-10 19:43:29 +00003511 break;
Francois Romieu2857ffb2008-08-02 21:08:49 +02003512 case RTL_GIGA_MAC_VER_07:
3513 case RTL_GIGA_MAC_VER_08:
3514 case RTL_GIGA_MAC_VER_09:
françois romieu4da19632011-01-03 15:07:55 +00003515 rtl8102e_hw_phy_config(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02003516 break;
Francois Romieu236b8082008-05-30 16:11:48 +02003517 case RTL_GIGA_MAC_VER_11:
françois romieu4da19632011-01-03 15:07:55 +00003518 rtl8168bb_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003519 break;
3520 case RTL_GIGA_MAC_VER_12:
françois romieu4da19632011-01-03 15:07:55 +00003521 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003522 break;
3523 case RTL_GIGA_MAC_VER_17:
françois romieu4da19632011-01-03 15:07:55 +00003524 rtl8168bef_hw_phy_config(tp);
Francois Romieu236b8082008-05-30 16:11:48 +02003525 break;
Francois Romieu867763c2007-08-17 18:21:58 +02003526 case RTL_GIGA_MAC_VER_18:
françois romieu4da19632011-01-03 15:07:55 +00003527 rtl8168cp_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003528 break;
3529 case RTL_GIGA_MAC_VER_19:
françois romieu4da19632011-01-03 15:07:55 +00003530 rtl8168c_1_hw_phy_config(tp);
Francois Romieu867763c2007-08-17 18:21:58 +02003531 break;
Francois Romieu7da97ec2007-10-18 15:20:43 +02003532 case RTL_GIGA_MAC_VER_20:
françois romieu4da19632011-01-03 15:07:55 +00003533 rtl8168c_2_hw_phy_config(tp);
Francois Romieu7da97ec2007-10-18 15:20:43 +02003534 break;
Francois Romieu197ff762008-06-28 13:16:02 +02003535 case RTL_GIGA_MAC_VER_21:
françois romieu4da19632011-01-03 15:07:55 +00003536 rtl8168c_3_hw_phy_config(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02003537 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02003538 case RTL_GIGA_MAC_VER_22:
françois romieu4da19632011-01-03 15:07:55 +00003539 rtl8168c_4_hw_phy_config(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02003540 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003541 case RTL_GIGA_MAC_VER_23:
Francois Romieu7f3e3d32008-07-20 18:53:20 +02003542 case RTL_GIGA_MAC_VER_24:
françois romieu4da19632011-01-03 15:07:55 +00003543 rtl8168cp_2_hw_phy_config(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02003544 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02003545 case RTL_GIGA_MAC_VER_25:
françois romieubca03d52011-01-03 15:07:31 +00003546 rtl8168d_1_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003547 break;
3548 case RTL_GIGA_MAC_VER_26:
françois romieubca03d52011-01-03 15:07:31 +00003549 rtl8168d_2_hw_phy_config(tp);
françois romieudaf9df62009-10-07 12:44:20 +00003550 break;
3551 case RTL_GIGA_MAC_VER_27:
françois romieu4da19632011-01-03 15:07:55 +00003552 rtl8168d_3_hw_phy_config(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02003553 break;
françois romieue6de30d2011-01-03 15:08:37 +00003554 case RTL_GIGA_MAC_VER_28:
3555 rtl8168d_4_hw_phy_config(tp);
3556 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08003557 case RTL_GIGA_MAC_VER_29:
3558 case RTL_GIGA_MAC_VER_30:
3559 rtl8105e_hw_phy_config(tp);
3560 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02003561 case RTL_GIGA_MAC_VER_31:
3562 /* None. */
3563 break;
hayeswang01dc7fe2011-03-21 01:50:28 +00003564 case RTL_GIGA_MAC_VER_32:
hayeswang01dc7fe2011-03-21 01:50:28 +00003565 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08003566 rtl8168e_1_hw_phy_config(tp);
3567 break;
3568 case RTL_GIGA_MAC_VER_34:
3569 rtl8168e_2_hw_phy_config(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00003570 break;
Hayes Wangc2218922011-09-06 16:55:18 +08003571 case RTL_GIGA_MAC_VER_35:
3572 rtl8168f_1_hw_phy_config(tp);
3573 break;
3574 case RTL_GIGA_MAC_VER_36:
3575 rtl8168f_2_hw_phy_config(tp);
3576 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02003577
Hayes Wang7e18dca2012-03-30 14:33:02 +08003578 case RTL_GIGA_MAC_VER_37:
3579 rtl8402_hw_phy_config(tp);
3580 break;
3581
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003582 case RTL_GIGA_MAC_VER_38:
3583 rtl8411_hw_phy_config(tp);
3584 break;
3585
Hayes Wang5598bfe2012-07-02 17:23:21 +08003586 case RTL_GIGA_MAC_VER_39:
3587 rtl8106e_hw_phy_config(tp);
3588 break;
3589
Hayes Wangc5583862012-07-02 17:23:22 +08003590 case RTL_GIGA_MAC_VER_40:
3591 rtl8168g_1_hw_phy_config(tp);
3592 break;
3593
3594 case RTL_GIGA_MAC_VER_41:
Francois Romieu5615d9f2007-08-17 17:50:46 +02003595 default:
3596 break;
3597 }
3598}
3599
Francois Romieuda78dbf2012-01-26 14:18:23 +01003600static void rtl_phy_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 struct timer_list *timer = &tp->timer;
3603 void __iomem *ioaddr = tp->mmio_addr;
3604 unsigned long timeout = RTL8169_PHY_TIMEOUT;
3605
Francois Romieubcf0bf92006-07-26 23:14:13 +02003606 assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
françois romieu4da19632011-01-03 15:07:55 +00003608 if (tp->phy_reset_pending(tp)) {
Francois Romieu5b0384f2006-08-16 16:00:01 +02003609 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 * A busy loop could burn quite a few cycles on nowadays CPU.
3611 * Let's delay the execution of the timer for a few ticks.
3612 */
3613 timeout = HZ/10;
3614 goto out_mod_timer;
3615 }
3616
3617 if (tp->link_ok(ioaddr))
Francois Romieuda78dbf2012-01-26 14:18:23 +01003618 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619
Francois Romieuda78dbf2012-01-26 14:18:23 +01003620 netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
françois romieu4da19632011-01-03 15:07:55 +00003622 tp->phy_reset_enable(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
3624out_mod_timer:
3625 mod_timer(timer, jiffies + timeout);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003626}
3627
3628static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
3629{
Francois Romieuda78dbf2012-01-26 14:18:23 +01003630 if (!test_and_set_bit(flag, tp->wk.flags))
3631 schedule_work(&tp->wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01003632}
3633
3634static void rtl8169_phy_timer(unsigned long __opaque)
3635{
3636 struct net_device *dev = (struct net_device *)__opaque;
3637 struct rtl8169_private *tp = netdev_priv(dev);
3638
Francois Romieu98ddf982012-01-31 10:47:34 +01003639 rtl_schedule_task(tp, RTL_FLAG_TASK_PHY_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640}
3641
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
3643 void __iomem *ioaddr)
3644{
3645 iounmap(ioaddr);
3646 pci_release_regions(pdev);
françois romieu87aeec72010-04-26 11:42:06 +00003647 pci_clear_mwi(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 pci_disable_device(pdev);
3649 free_netdev(dev);
3650}
3651
Francois Romieuffc46952012-07-06 14:19:23 +02003652DECLARE_RTL_COND(rtl_phy_reset_cond)
3653{
3654 return tp->phy_reset_pending(tp);
3655}
3656
Francois Romieubf793292006-11-01 00:53:05 +01003657static void rtl8169_phy_reset(struct net_device *dev,
3658 struct rtl8169_private *tp)
3659{
françois romieu4da19632011-01-03 15:07:55 +00003660 tp->phy_reset_enable(tp);
Francois Romieuffc46952012-07-06 14:19:23 +02003661 rtl_msleep_loop_wait_low(tp, &rtl_phy_reset_cond, 1, 100);
Francois Romieubf793292006-11-01 00:53:05 +01003662}
3663
David S. Miller8decf862011-09-22 03:23:13 -04003664static bool rtl_tbi_enabled(struct rtl8169_private *tp)
3665{
3666 void __iomem *ioaddr = tp->mmio_addr;
3667
3668 return (tp->mac_version == RTL_GIGA_MAC_VER_01) &&
3669 (RTL_R8(PHYstatus) & TBI_Enable);
3670}
3671
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003672static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673{
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003674 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003675
Francois Romieu5615d9f2007-08-17 17:50:46 +02003676 rtl_hw_phy_config(dev);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003677
Marcus Sundberg773328942008-07-10 21:28:08 +02003678 if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
3679 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3680 RTL_W8(0x82, 0x01);
3681 }
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003682
Francois Romieu6dccd162007-02-13 23:38:05 +01003683 pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
3684
3685 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
3686 pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003687
Francois Romieubcf0bf92006-07-26 23:14:13 +02003688 if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003689 dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
3690 RTL_W8(0x82, 0x01);
3691 dprintk("Set PHY Reg 0x0bh = 0x00h\n");
françois romieu4da19632011-01-03 15:07:55 +00003692 rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003693 }
3694
Francois Romieubf793292006-11-01 00:53:05 +01003695 rtl8169_phy_reset(dev, tp);
3696
Oliver Neukum54405cd2011-01-06 21:55:13 +01003697 rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
Francois Romieucecb5fd2011-04-01 10:21:07 +02003698 ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
3699 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
3700 (tp->mii.supports_gmii ?
3701 ADVERTISED_1000baseT_Half |
3702 ADVERTISED_1000baseT_Full : 0));
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003703
David S. Miller8decf862011-09-22 03:23:13 -04003704 if (rtl_tbi_enabled(tp))
Joe Perchesbf82c182010-02-09 11:49:50 +00003705 netif_info(tp, link, dev, "TBI auto-negotiating\n");
Francois Romieu4ff96fa2006-07-26 22:05:06 +02003706}
3707
Francois Romieu773d2022007-01-31 23:47:43 +01003708static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
3709{
3710 void __iomem *ioaddr = tp->mmio_addr;
3711 u32 high;
3712 u32 low;
3713
3714 low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
3715 high = addr[4] | (addr[5] << 8);
3716
Francois Romieuda78dbf2012-01-26 14:18:23 +01003717 rtl_lock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003718
3719 RTL_W8(Cfg9346, Cfg9346_Unlock);
françois romieu908ba2b2010-04-26 11:42:58 +00003720
Francois Romieu773d2022007-01-31 23:47:43 +01003721 RTL_W32(MAC4, high);
françois romieu908ba2b2010-04-26 11:42:58 +00003722 RTL_R32(MAC4);
3723
Francois Romieu78f1cd02010-03-27 19:35:46 -07003724 RTL_W32(MAC0, low);
françois romieu908ba2b2010-04-26 11:42:58 +00003725 RTL_R32(MAC0);
3726
françois romieuc28aa382011-08-02 03:53:43 +00003727 if (tp->mac_version == RTL_GIGA_MAC_VER_34) {
3728 const struct exgmac_reg e[] = {
3729 { .addr = 0xe0, ERIAR_MASK_1111, .val = low },
3730 { .addr = 0xe4, ERIAR_MASK_1111, .val = high },
3731 { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 },
3732 { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 |
3733 low >> 16 },
3734 };
3735
Francois Romieufdf6fc02012-07-06 22:40:38 +02003736 rtl_write_exgmac_batch(tp, e, ARRAY_SIZE(e));
françois romieuc28aa382011-08-02 03:53:43 +00003737 }
3738
Francois Romieu773d2022007-01-31 23:47:43 +01003739 RTL_W8(Cfg9346, Cfg9346_Lock);
3740
Francois Romieuda78dbf2012-01-26 14:18:23 +01003741 rtl_unlock_work(tp);
Francois Romieu773d2022007-01-31 23:47:43 +01003742}
3743
3744static int rtl_set_mac_address(struct net_device *dev, void *p)
3745{
3746 struct rtl8169_private *tp = netdev_priv(dev);
3747 struct sockaddr *addr = p;
3748
3749 if (!is_valid_ether_addr(addr->sa_data))
3750 return -EADDRNOTAVAIL;
3751
3752 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
3753
3754 rtl_rar_set(tp, dev->dev_addr);
3755
3756 return 0;
3757}
3758
Francois Romieu5f787a12006-08-17 13:02:36 +02003759static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
3760{
3761 struct rtl8169_private *tp = netdev_priv(dev);
3762 struct mii_ioctl_data *data = if_mii(ifr);
3763
Francois Romieu8b4ab282008-11-19 22:05:25 -08003764 return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
3765}
Francois Romieu5f787a12006-08-17 13:02:36 +02003766
Francois Romieucecb5fd2011-04-01 10:21:07 +02003767static int rtl_xmii_ioctl(struct rtl8169_private *tp,
3768 struct mii_ioctl_data *data, int cmd)
Francois Romieu8b4ab282008-11-19 22:05:25 -08003769{
Francois Romieu5f787a12006-08-17 13:02:36 +02003770 switch (cmd) {
3771 case SIOCGMIIPHY:
3772 data->phy_id = 32; /* Internal PHY */
3773 return 0;
3774
3775 case SIOCGMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003776 data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
Francois Romieu5f787a12006-08-17 13:02:36 +02003777 return 0;
3778
3779 case SIOCSMIIREG:
françois romieu4da19632011-01-03 15:07:55 +00003780 rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
Francois Romieu5f787a12006-08-17 13:02:36 +02003781 return 0;
3782 }
3783 return -EOPNOTSUPP;
3784}
3785
Francois Romieu8b4ab282008-11-19 22:05:25 -08003786static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
3787{
3788 return -EOPNOTSUPP;
3789}
3790
Francois Romieufbac58f2007-10-04 22:51:38 +02003791static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
3792{
3793 if (tp->features & RTL_FEATURE_MSI) {
3794 pci_disable_msi(pdev);
3795 tp->features &= ~RTL_FEATURE_MSI;
3796 }
3797}
3798
françois romieuc0e45c12011-01-03 15:08:04 +00003799static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
3800{
3801 struct mdio_ops *ops = &tp->mdio_ops;
3802
3803 switch (tp->mac_version) {
3804 case RTL_GIGA_MAC_VER_27:
3805 ops->write = r8168dp_1_mdio_write;
3806 ops->read = r8168dp_1_mdio_read;
3807 break;
françois romieue6de30d2011-01-03 15:08:37 +00003808 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00003809 case RTL_GIGA_MAC_VER_31:
françois romieue6de30d2011-01-03 15:08:37 +00003810 ops->write = r8168dp_2_mdio_write;
3811 ops->read = r8168dp_2_mdio_read;
3812 break;
Hayes Wangc5583862012-07-02 17:23:22 +08003813 case RTL_GIGA_MAC_VER_40:
3814 case RTL_GIGA_MAC_VER_41:
3815 ops->write = r8168g_mdio_write;
3816 ops->read = r8168g_mdio_read;
3817 break;
françois romieuc0e45c12011-01-03 15:08:04 +00003818 default:
3819 ops->write = r8169_mdio_write;
3820 ops->read = r8169_mdio_read;
3821 break;
3822 }
3823}
3824
David S. Miller1805b2f2011-10-24 18:18:09 -04003825static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
3826{
3827 void __iomem *ioaddr = tp->mmio_addr;
3828
3829 switch (tp->mac_version) {
Cyril Bruleboisb00e69d2012-10-31 14:00:46 +00003830 case RTL_GIGA_MAC_VER_25:
3831 case RTL_GIGA_MAC_VER_26:
David S. Miller1805b2f2011-10-24 18:18:09 -04003832 case RTL_GIGA_MAC_VER_29:
3833 case RTL_GIGA_MAC_VER_30:
3834 case RTL_GIGA_MAC_VER_32:
3835 case RTL_GIGA_MAC_VER_33:
3836 case RTL_GIGA_MAC_VER_34:
Hayes Wang7e18dca2012-03-30 14:33:02 +08003837 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08003838 case RTL_GIGA_MAC_VER_38:
Hayes Wang5598bfe2012-07-02 17:23:21 +08003839 case RTL_GIGA_MAC_VER_39:
Hayes Wangc5583862012-07-02 17:23:22 +08003840 case RTL_GIGA_MAC_VER_40:
3841 case RTL_GIGA_MAC_VER_41:
David S. Miller1805b2f2011-10-24 18:18:09 -04003842 RTL_W32(RxConfig, RTL_R32(RxConfig) |
3843 AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
3844 break;
3845 default:
3846 break;
3847 }
3848}
3849
3850static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
3851{
3852 if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
3853 return false;
3854
3855 rtl_writephy(tp, 0x1f, 0x0000);
3856 rtl_writephy(tp, MII_BMCR, 0x0000);
3857
3858 rtl_wol_suspend_quirk(tp);
3859
3860 return true;
3861}
3862
françois romieu065c27c2011-01-03 15:08:12 +00003863static void r810x_phy_power_down(struct rtl8169_private *tp)
3864{
3865 rtl_writephy(tp, 0x1f, 0x0000);
3866 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3867}
3868
3869static void r810x_phy_power_up(struct rtl8169_private *tp)
3870{
3871 rtl_writephy(tp, 0x1f, 0x0000);
3872 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3873}
3874
3875static void r810x_pll_power_down(struct rtl8169_private *tp)
3876{
Hayes Wang00042992012-03-30 14:33:00 +08003877 void __iomem *ioaddr = tp->mmio_addr;
3878
David S. Miller1805b2f2011-10-24 18:18:09 -04003879 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003880 return;
françois romieu065c27c2011-01-03 15:08:12 +00003881
3882 r810x_phy_power_down(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003883
3884 switch (tp->mac_version) {
3885 case RTL_GIGA_MAC_VER_07:
3886 case RTL_GIGA_MAC_VER_08:
3887 case RTL_GIGA_MAC_VER_09:
3888 case RTL_GIGA_MAC_VER_10:
3889 case RTL_GIGA_MAC_VER_13:
3890 case RTL_GIGA_MAC_VER_16:
3891 break;
3892 default:
3893 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
3894 break;
3895 }
françois romieu065c27c2011-01-03 15:08:12 +00003896}
3897
3898static void r810x_pll_power_up(struct rtl8169_private *tp)
3899{
Hayes Wang00042992012-03-30 14:33:00 +08003900 void __iomem *ioaddr = tp->mmio_addr;
3901
françois romieu065c27c2011-01-03 15:08:12 +00003902 r810x_phy_power_up(tp);
Hayes Wang00042992012-03-30 14:33:00 +08003903
3904 switch (tp->mac_version) {
3905 case RTL_GIGA_MAC_VER_07:
3906 case RTL_GIGA_MAC_VER_08:
3907 case RTL_GIGA_MAC_VER_09:
3908 case RTL_GIGA_MAC_VER_10:
3909 case RTL_GIGA_MAC_VER_13:
3910 case RTL_GIGA_MAC_VER_16:
3911 break;
3912 default:
3913 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
3914 break;
3915 }
françois romieu065c27c2011-01-03 15:08:12 +00003916}
3917
3918static void r8168_phy_power_up(struct rtl8169_private *tp)
3919{
3920 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003921 switch (tp->mac_version) {
3922 case RTL_GIGA_MAC_VER_11:
3923 case RTL_GIGA_MAC_VER_12:
3924 case RTL_GIGA_MAC_VER_17:
3925 case RTL_GIGA_MAC_VER_18:
3926 case RTL_GIGA_MAC_VER_19:
3927 case RTL_GIGA_MAC_VER_20:
3928 case RTL_GIGA_MAC_VER_21:
3929 case RTL_GIGA_MAC_VER_22:
3930 case RTL_GIGA_MAC_VER_23:
3931 case RTL_GIGA_MAC_VER_24:
3932 case RTL_GIGA_MAC_VER_25:
3933 case RTL_GIGA_MAC_VER_26:
3934 case RTL_GIGA_MAC_VER_27:
3935 case RTL_GIGA_MAC_VER_28:
3936 case RTL_GIGA_MAC_VER_31:
3937 rtl_writephy(tp, 0x0e, 0x0000);
3938 break;
3939 default:
3940 break;
3941 }
françois romieu065c27c2011-01-03 15:08:12 +00003942 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
3943}
3944
3945static void r8168_phy_power_down(struct rtl8169_private *tp)
3946{
3947 rtl_writephy(tp, 0x1f, 0x0000);
hayeswang01dc7fe2011-03-21 01:50:28 +00003948 switch (tp->mac_version) {
3949 case RTL_GIGA_MAC_VER_32:
3950 case RTL_GIGA_MAC_VER_33:
3951 rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
3952 break;
3953
3954 case RTL_GIGA_MAC_VER_11:
3955 case RTL_GIGA_MAC_VER_12:
3956 case RTL_GIGA_MAC_VER_17:
3957 case RTL_GIGA_MAC_VER_18:
3958 case RTL_GIGA_MAC_VER_19:
3959 case RTL_GIGA_MAC_VER_20:
3960 case RTL_GIGA_MAC_VER_21:
3961 case RTL_GIGA_MAC_VER_22:
3962 case RTL_GIGA_MAC_VER_23:
3963 case RTL_GIGA_MAC_VER_24:
3964 case RTL_GIGA_MAC_VER_25:
3965 case RTL_GIGA_MAC_VER_26:
3966 case RTL_GIGA_MAC_VER_27:
3967 case RTL_GIGA_MAC_VER_28:
3968 case RTL_GIGA_MAC_VER_31:
3969 rtl_writephy(tp, 0x0e, 0x0200);
3970 default:
3971 rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
3972 break;
3973 }
françois romieu065c27c2011-01-03 15:08:12 +00003974}
3975
3976static void r8168_pll_power_down(struct rtl8169_private *tp)
3977{
3978 void __iomem *ioaddr = tp->mmio_addr;
3979
Francois Romieucecb5fd2011-04-01 10:21:07 +02003980 if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
3981 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
3982 tp->mac_version == RTL_GIGA_MAC_VER_31) &&
hayeswang4804b3b2011-03-21 01:50:29 +00003983 r8168dp_check_dash(tp)) {
françois romieu065c27c2011-01-03 15:08:12 +00003984 return;
Hayes Wang5d2e1952011-02-22 17:26:22 +08003985 }
françois romieu065c27c2011-01-03 15:08:12 +00003986
Francois Romieucecb5fd2011-04-01 10:21:07 +02003987 if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
3988 tp->mac_version == RTL_GIGA_MAC_VER_24) &&
françois romieu065c27c2011-01-03 15:08:12 +00003989 (RTL_R16(CPlusCmd) & ASF)) {
3990 return;
3991 }
3992
hayeswang01dc7fe2011-03-21 01:50:28 +00003993 if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
3994 tp->mac_version == RTL_GIGA_MAC_VER_33)
Francois Romieufdf6fc02012-07-06 22:40:38 +02003995 rtl_ephy_write(tp, 0x19, 0xff64);
hayeswang01dc7fe2011-03-21 01:50:28 +00003996
David S. Miller1805b2f2011-10-24 18:18:09 -04003997 if (rtl_wol_pll_power_down(tp))
françois romieu065c27c2011-01-03 15:08:12 +00003998 return;
françois romieu065c27c2011-01-03 15:08:12 +00003999
4000 r8168_phy_power_down(tp);
4001
4002 switch (tp->mac_version) {
4003 case RTL_GIGA_MAC_VER_25:
4004 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004005 case RTL_GIGA_MAC_VER_27:
4006 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004007 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004008 case RTL_GIGA_MAC_VER_32:
4009 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004010 RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
4011 break;
4012 }
4013}
4014
4015static void r8168_pll_power_up(struct rtl8169_private *tp)
4016{
4017 void __iomem *ioaddr = tp->mmio_addr;
4018
françois romieu065c27c2011-01-03 15:08:12 +00004019 switch (tp->mac_version) {
4020 case RTL_GIGA_MAC_VER_25:
4021 case RTL_GIGA_MAC_VER_26:
Hayes Wang5d2e1952011-02-22 17:26:22 +08004022 case RTL_GIGA_MAC_VER_27:
4023 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004024 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004025 case RTL_GIGA_MAC_VER_32:
4026 case RTL_GIGA_MAC_VER_33:
françois romieu065c27c2011-01-03 15:08:12 +00004027 RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
4028 break;
4029 }
4030
4031 r8168_phy_power_up(tp);
4032}
4033
Francois Romieud58d46b2011-05-03 16:38:29 +02004034static void rtl_generic_op(struct rtl8169_private *tp,
4035 void (*op)(struct rtl8169_private *))
françois romieu065c27c2011-01-03 15:08:12 +00004036{
4037 if (op)
4038 op(tp);
4039}
4040
4041static void rtl_pll_power_down(struct rtl8169_private *tp)
4042{
Francois Romieud58d46b2011-05-03 16:38:29 +02004043 rtl_generic_op(tp, tp->pll_power_ops.down);
françois romieu065c27c2011-01-03 15:08:12 +00004044}
4045
4046static void rtl_pll_power_up(struct rtl8169_private *tp)
4047{
Francois Romieud58d46b2011-05-03 16:38:29 +02004048 rtl_generic_op(tp, tp->pll_power_ops.up);
françois romieu065c27c2011-01-03 15:08:12 +00004049}
4050
4051static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
4052{
4053 struct pll_power_ops *ops = &tp->pll_power_ops;
4054
4055 switch (tp->mac_version) {
4056 case RTL_GIGA_MAC_VER_07:
4057 case RTL_GIGA_MAC_VER_08:
4058 case RTL_GIGA_MAC_VER_09:
4059 case RTL_GIGA_MAC_VER_10:
4060 case RTL_GIGA_MAC_VER_16:
Hayes Wang5a5e4442011-02-22 17:26:21 +08004061 case RTL_GIGA_MAC_VER_29:
4062 case RTL_GIGA_MAC_VER_30:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004063 case RTL_GIGA_MAC_VER_37:
Hayes Wang5598bfe2012-07-02 17:23:21 +08004064 case RTL_GIGA_MAC_VER_39:
françois romieu065c27c2011-01-03 15:08:12 +00004065 ops->down = r810x_pll_power_down;
4066 ops->up = r810x_pll_power_up;
4067 break;
4068
4069 case RTL_GIGA_MAC_VER_11:
4070 case RTL_GIGA_MAC_VER_12:
4071 case RTL_GIGA_MAC_VER_17:
4072 case RTL_GIGA_MAC_VER_18:
4073 case RTL_GIGA_MAC_VER_19:
4074 case RTL_GIGA_MAC_VER_20:
4075 case RTL_GIGA_MAC_VER_21:
4076 case RTL_GIGA_MAC_VER_22:
4077 case RTL_GIGA_MAC_VER_23:
4078 case RTL_GIGA_MAC_VER_24:
4079 case RTL_GIGA_MAC_VER_25:
4080 case RTL_GIGA_MAC_VER_26:
4081 case RTL_GIGA_MAC_VER_27:
françois romieue6de30d2011-01-03 15:08:37 +00004082 case RTL_GIGA_MAC_VER_28:
hayeswang4804b3b2011-03-21 01:50:29 +00004083 case RTL_GIGA_MAC_VER_31:
hayeswang01dc7fe2011-03-21 01:50:28 +00004084 case RTL_GIGA_MAC_VER_32:
4085 case RTL_GIGA_MAC_VER_33:
Hayes Wang70090422011-07-06 15:58:06 +08004086 case RTL_GIGA_MAC_VER_34:
Hayes Wangc2218922011-09-06 16:55:18 +08004087 case RTL_GIGA_MAC_VER_35:
4088 case RTL_GIGA_MAC_VER_36:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004089 case RTL_GIGA_MAC_VER_38:
Hayes Wangc5583862012-07-02 17:23:22 +08004090 case RTL_GIGA_MAC_VER_40:
4091 case RTL_GIGA_MAC_VER_41:
françois romieu065c27c2011-01-03 15:08:12 +00004092 ops->down = r8168_pll_power_down;
4093 ops->up = r8168_pll_power_up;
4094 break;
4095
4096 default:
4097 ops->down = NULL;
4098 ops->up = NULL;
4099 break;
4100 }
4101}
4102
Hayes Wange542a222011-07-06 15:58:04 +08004103static void rtl_init_rxcfg(struct rtl8169_private *tp)
4104{
4105 void __iomem *ioaddr = tp->mmio_addr;
4106
4107 switch (tp->mac_version) {
4108 case RTL_GIGA_MAC_VER_01:
4109 case RTL_GIGA_MAC_VER_02:
4110 case RTL_GIGA_MAC_VER_03:
4111 case RTL_GIGA_MAC_VER_04:
4112 case RTL_GIGA_MAC_VER_05:
4113 case RTL_GIGA_MAC_VER_06:
4114 case RTL_GIGA_MAC_VER_10:
4115 case RTL_GIGA_MAC_VER_11:
4116 case RTL_GIGA_MAC_VER_12:
4117 case RTL_GIGA_MAC_VER_13:
4118 case RTL_GIGA_MAC_VER_14:
4119 case RTL_GIGA_MAC_VER_15:
4120 case RTL_GIGA_MAC_VER_16:
4121 case RTL_GIGA_MAC_VER_17:
4122 RTL_W32(RxConfig, RX_FIFO_THRESH | RX_DMA_BURST);
4123 break;
4124 case RTL_GIGA_MAC_VER_18:
4125 case RTL_GIGA_MAC_VER_19:
4126 case RTL_GIGA_MAC_VER_20:
4127 case RTL_GIGA_MAC_VER_21:
4128 case RTL_GIGA_MAC_VER_22:
4129 case RTL_GIGA_MAC_VER_23:
4130 case RTL_GIGA_MAC_VER_24:
françois romieueb2dc352012-06-20 12:09:18 +00004131 case RTL_GIGA_MAC_VER_34:
Hayes Wange542a222011-07-06 15:58:04 +08004132 RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
4133 break;
4134 default:
4135 RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
4136 break;
4137 }
4138}
4139
Hayes Wang92fc43b2011-07-06 15:58:03 +08004140static void rtl8169_init_ring_indexes(struct rtl8169_private *tp)
4141{
4142 tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0;
4143}
4144
Francois Romieud58d46b2011-05-03 16:38:29 +02004145static void rtl_hw_jumbo_enable(struct rtl8169_private *tp)
4146{
françois romieu9c5028e2012-03-02 04:43:14 +00004147 void __iomem *ioaddr = tp->mmio_addr;
4148
4149 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004150 rtl_generic_op(tp, tp->jumbo_ops.enable);
françois romieu9c5028e2012-03-02 04:43:14 +00004151 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004152}
4153
4154static void rtl_hw_jumbo_disable(struct rtl8169_private *tp)
4155{
françois romieu9c5028e2012-03-02 04:43:14 +00004156 void __iomem *ioaddr = tp->mmio_addr;
4157
4158 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004159 rtl_generic_op(tp, tp->jumbo_ops.disable);
françois romieu9c5028e2012-03-02 04:43:14 +00004160 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieud58d46b2011-05-03 16:38:29 +02004161}
4162
4163static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
4164{
4165 void __iomem *ioaddr = tp->mmio_addr;
4166
4167 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4168 RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
4169 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
4170}
4171
4172static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
4173{
4174 void __iomem *ioaddr = tp->mmio_addr;
4175
4176 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4177 RTL_W8(Config4, RTL_R8(Config4) & ~Jumbo_En1);
4178 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
4179}
4180
4181static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp)
4182{
4183 void __iomem *ioaddr = tp->mmio_addr;
4184
4185 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4186}
4187
4188static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp)
4189{
4190 void __iomem *ioaddr = tp->mmio_addr;
4191
4192 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4193}
4194
4195static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
4196{
4197 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004198
4199 RTL_W8(MaxTxPacketSize, 0x3f);
4200 RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
4201 RTL_W8(Config4, RTL_R8(Config4) | 0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004202 rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004203}
4204
4205static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
4206{
4207 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieud58d46b2011-05-03 16:38:29 +02004208
4209 RTL_W8(MaxTxPacketSize, 0x0c);
4210 RTL_W8(Config3, RTL_R8(Config3) & ~Jumbo_En0);
4211 RTL_W8(Config4, RTL_R8(Config4) & ~0x01);
Francois Romieu4512ff92011-12-22 18:59:37 +01004212 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieud58d46b2011-05-03 16:38:29 +02004213}
4214
4215static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
4216{
4217 rtl_tx_performance_tweak(tp->pci_dev,
4218 (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4219}
4220
4221static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
4222{
4223 rtl_tx_performance_tweak(tp->pci_dev,
4224 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
4225}
4226
4227static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp)
4228{
4229 void __iomem *ioaddr = tp->mmio_addr;
4230
4231 r8168b_0_hw_jumbo_enable(tp);
4232
4233 RTL_W8(Config4, RTL_R8(Config4) | (1 << 0));
4234}
4235
4236static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp)
4237{
4238 void __iomem *ioaddr = tp->mmio_addr;
4239
4240 r8168b_0_hw_jumbo_disable(tp);
4241
4242 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
4243}
4244
4245static void __devinit rtl_init_jumbo_ops(struct rtl8169_private *tp)
4246{
4247 struct jumbo_ops *ops = &tp->jumbo_ops;
4248
4249 switch (tp->mac_version) {
4250 case RTL_GIGA_MAC_VER_11:
4251 ops->disable = r8168b_0_hw_jumbo_disable;
4252 ops->enable = r8168b_0_hw_jumbo_enable;
4253 break;
4254 case RTL_GIGA_MAC_VER_12:
4255 case RTL_GIGA_MAC_VER_17:
4256 ops->disable = r8168b_1_hw_jumbo_disable;
4257 ops->enable = r8168b_1_hw_jumbo_enable;
4258 break;
4259 case RTL_GIGA_MAC_VER_18: /* Wild guess. Needs info from Realtek. */
4260 case RTL_GIGA_MAC_VER_19:
4261 case RTL_GIGA_MAC_VER_20:
4262 case RTL_GIGA_MAC_VER_21: /* Wild guess. Needs info from Realtek. */
4263 case RTL_GIGA_MAC_VER_22:
4264 case RTL_GIGA_MAC_VER_23:
4265 case RTL_GIGA_MAC_VER_24:
4266 case RTL_GIGA_MAC_VER_25:
4267 case RTL_GIGA_MAC_VER_26:
4268 ops->disable = r8168c_hw_jumbo_disable;
4269 ops->enable = r8168c_hw_jumbo_enable;
4270 break;
4271 case RTL_GIGA_MAC_VER_27:
4272 case RTL_GIGA_MAC_VER_28:
4273 ops->disable = r8168dp_hw_jumbo_disable;
4274 ops->enable = r8168dp_hw_jumbo_enable;
4275 break;
4276 case RTL_GIGA_MAC_VER_31: /* Wild guess. Needs info from Realtek. */
4277 case RTL_GIGA_MAC_VER_32:
4278 case RTL_GIGA_MAC_VER_33:
4279 case RTL_GIGA_MAC_VER_34:
4280 ops->disable = r8168e_hw_jumbo_disable;
4281 ops->enable = r8168e_hw_jumbo_enable;
4282 break;
4283
4284 /*
4285 * No action needed for jumbo frames with 8169.
4286 * No jumbo for 810x at all.
4287 */
Hayes Wangc5583862012-07-02 17:23:22 +08004288 case RTL_GIGA_MAC_VER_40:
4289 case RTL_GIGA_MAC_VER_41:
Francois Romieud58d46b2011-05-03 16:38:29 +02004290 default:
4291 ops->disable = NULL;
4292 ops->enable = NULL;
4293 break;
4294 }
4295}
4296
Francois Romieuffc46952012-07-06 14:19:23 +02004297DECLARE_RTL_COND(rtl_chipcmd_cond)
4298{
4299 void __iomem *ioaddr = tp->mmio_addr;
4300
4301 return RTL_R8(ChipCmd) & CmdReset;
4302}
4303
Francois Romieu6f43adc2011-04-29 15:05:51 +02004304static void rtl_hw_reset(struct rtl8169_private *tp)
4305{
4306 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu6f43adc2011-04-29 15:05:51 +02004307
Francois Romieu6f43adc2011-04-29 15:05:51 +02004308 RTL_W8(ChipCmd, CmdReset);
4309
Francois Romieuffc46952012-07-06 14:19:23 +02004310 rtl_udelay_loop_wait_low(tp, &rtl_chipcmd_cond, 100, 100);
Francois Romieu6f43adc2011-04-29 15:05:51 +02004311}
4312
Francois Romieub6ffd972011-06-17 17:00:05 +02004313static void rtl_request_uncached_firmware(struct rtl8169_private *tp)
4314{
4315 struct rtl_fw *rtl_fw;
4316 const char *name;
4317 int rc = -ENOMEM;
4318
4319 name = rtl_lookup_firmware_name(tp);
4320 if (!name)
4321 goto out_no_firmware;
4322
4323 rtl_fw = kzalloc(sizeof(*rtl_fw), GFP_KERNEL);
4324 if (!rtl_fw)
4325 goto err_warn;
4326
4327 rc = request_firmware(&rtl_fw->fw, name, &tp->pci_dev->dev);
4328 if (rc < 0)
4329 goto err_free;
4330
Francois Romieufd112f22011-06-18 00:10:29 +02004331 rc = rtl_check_firmware(tp, rtl_fw);
4332 if (rc < 0)
4333 goto err_release_firmware;
4334
Francois Romieub6ffd972011-06-17 17:00:05 +02004335 tp->rtl_fw = rtl_fw;
4336out:
4337 return;
4338
Francois Romieufd112f22011-06-18 00:10:29 +02004339err_release_firmware:
4340 release_firmware(rtl_fw->fw);
Francois Romieub6ffd972011-06-17 17:00:05 +02004341err_free:
4342 kfree(rtl_fw);
4343err_warn:
4344 netif_warn(tp, ifup, tp->dev, "unable to load firmware patch %s (%d)\n",
4345 name, rc);
4346out_no_firmware:
4347 tp->rtl_fw = NULL;
4348 goto out;
4349}
4350
François Romieu953a12c2011-04-24 17:38:48 +02004351static void rtl_request_firmware(struct rtl8169_private *tp)
4352{
Francois Romieub6ffd972011-06-17 17:00:05 +02004353 if (IS_ERR(tp->rtl_fw))
4354 rtl_request_uncached_firmware(tp);
François Romieu953a12c2011-04-24 17:38:48 +02004355}
4356
Hayes Wang92fc43b2011-07-06 15:58:03 +08004357static void rtl_rx_close(struct rtl8169_private *tp)
4358{
4359 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang92fc43b2011-07-06 15:58:03 +08004360
Francois Romieu1687b562011-07-19 17:21:29 +02004361 RTL_W32(RxConfig, RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004362}
4363
Francois Romieuffc46952012-07-06 14:19:23 +02004364DECLARE_RTL_COND(rtl_npq_cond)
4365{
4366 void __iomem *ioaddr = tp->mmio_addr;
4367
4368 return RTL_R8(TxPoll) & NPQ;
4369}
4370
4371DECLARE_RTL_COND(rtl_txcfg_empty_cond)
4372{
4373 void __iomem *ioaddr = tp->mmio_addr;
4374
4375 return RTL_R32(TxConfig) & TXCFG_EMPTY;
4376}
4377
françois romieue6de30d2011-01-03 15:08:37 +00004378static void rtl8169_hw_reset(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379{
françois romieue6de30d2011-01-03 15:08:37 +00004380 void __iomem *ioaddr = tp->mmio_addr;
4381
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 /* Disable interrupts */
françois romieu811fd302011-12-04 20:30:45 +00004383 rtl8169_irq_mask_and_ack(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
Hayes Wang92fc43b2011-07-06 15:58:03 +08004385 rtl_rx_close(tp);
4386
Hayes Wang5d2e1952011-02-22 17:26:22 +08004387 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
hayeswang4804b3b2011-03-21 01:50:29 +00004388 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
4389 tp->mac_version == RTL_GIGA_MAC_VER_31) {
Francois Romieuffc46952012-07-06 14:19:23 +02004390 rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
Hayes Wangc2218922011-09-06 16:55:18 +08004391 } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
4392 tp->mac_version == RTL_GIGA_MAC_VER_35 ||
Hayes Wang7e18dca2012-03-30 14:33:02 +08004393 tp->mac_version == RTL_GIGA_MAC_VER_36 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004394 tp->mac_version == RTL_GIGA_MAC_VER_37 ||
Hayes Wangc5583862012-07-02 17:23:22 +08004395 tp->mac_version == RTL_GIGA_MAC_VER_40 ||
4396 tp->mac_version == RTL_GIGA_MAC_VER_41 ||
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004397 tp->mac_version == RTL_GIGA_MAC_VER_38) {
David S. Miller8decf862011-09-22 03:23:13 -04004398 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
Francois Romieuffc46952012-07-06 14:19:23 +02004399 rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
Hayes Wang92fc43b2011-07-06 15:58:03 +08004400 } else {
4401 RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
4402 udelay(100);
françois romieue6de30d2011-01-03 15:08:37 +00004403 }
4404
Hayes Wang92fc43b2011-07-06 15:58:03 +08004405 rtl_hw_reset(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406}
4407
Francois Romieu7f796d832007-06-11 23:04:41 +02004408static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004409{
4410 void __iomem *ioaddr = tp->mmio_addr;
Francois Romieu9cb427b2006-11-02 00:10:16 +01004411
4412 /* Set DMA burst size and Interframe Gap Time */
4413 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
4414 (InterFrameGap << TxInterFrameGapShift));
4415}
4416
Francois Romieu07ce4062007-02-23 23:36:39 +01004417static void rtl_hw_start(struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418{
4419 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420
Francois Romieu07ce4062007-02-23 23:36:39 +01004421 tp->hw_start(dev);
4422
Francois Romieuda78dbf2012-01-26 14:18:23 +01004423 rtl_irq_enable_all(tp);
Francois Romieu07ce4062007-02-23 23:36:39 +01004424}
4425
Francois Romieu7f796d832007-06-11 23:04:41 +02004426static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
4427 void __iomem *ioaddr)
4428{
4429 /*
4430 * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
4431 * register to be written before TxDescAddrLow to work.
4432 * Switching from MMIO to I/O access fixes the issue as well.
4433 */
4434 RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004435 RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004436 RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
Yang Hongyang284901a2009-04-06 19:01:15 -07004437 RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_BIT_MASK(32));
Francois Romieu7f796d832007-06-11 23:04:41 +02004438}
4439
4440static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
4441{
4442 u16 cmd;
4443
4444 cmd = RTL_R16(CPlusCmd);
4445 RTL_W16(CPlusCmd, cmd);
4446 return cmd;
4447}
4448
Eric Dumazetfdd7b4c2009-06-09 04:01:02 -07004449static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz)
Francois Romieu7f796d832007-06-11 23:04:41 +02004450{
4451 /* Low hurts. Let's disable the filtering. */
Raimonds Cicans207d6e82009-10-26 10:52:37 +00004452 RTL_W16(RxMaxSize, rx_buf_sz + 1);
Francois Romieu7f796d832007-06-11 23:04:41 +02004453}
4454
Francois Romieu6dccd162007-02-13 23:38:05 +01004455static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
4456{
Francois Romieu37441002011-06-17 22:58:54 +02004457 static const struct rtl_cfg2_info {
Francois Romieu6dccd162007-02-13 23:38:05 +01004458 u32 mac_version;
4459 u32 clk;
4460 u32 val;
4461 } cfg2_info [] = {
4462 { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
4463 { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
4464 { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
4465 { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
Francois Romieu37441002011-06-17 22:58:54 +02004466 };
4467 const struct rtl_cfg2_info *p = cfg2_info;
Francois Romieu6dccd162007-02-13 23:38:05 +01004468 unsigned int i;
4469 u32 clk;
4470
4471 clk = RTL_R8(Config2) & PCI_Clock_66MHz;
Francois Romieucadf1852008-01-03 23:38:38 +01004472 for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
Francois Romieu6dccd162007-02-13 23:38:05 +01004473 if ((p->mac_version == mac_version) && (p->clk == clk)) {
4474 RTL_W32(0x7c, p->val);
4475 break;
4476 }
4477 }
4478}
4479
Francois Romieue6b763e2012-03-08 09:35:39 +01004480static void rtl_set_rx_mode(struct net_device *dev)
4481{
4482 struct rtl8169_private *tp = netdev_priv(dev);
4483 void __iomem *ioaddr = tp->mmio_addr;
4484 u32 mc_filter[2]; /* Multicast hash filter */
4485 int rx_mode;
4486 u32 tmp = 0;
4487
4488 if (dev->flags & IFF_PROMISC) {
4489 /* Unconditionally log net taps. */
4490 netif_notice(tp, link, dev, "Promiscuous mode enabled\n");
4491 rx_mode =
4492 AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
4493 AcceptAllPhys;
4494 mc_filter[1] = mc_filter[0] = 0xffffffff;
4495 } else if ((netdev_mc_count(dev) > multicast_filter_limit) ||
4496 (dev->flags & IFF_ALLMULTI)) {
4497 /* Too many to filter perfectly -- accept all multicasts. */
4498 rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
4499 mc_filter[1] = mc_filter[0] = 0xffffffff;
4500 } else {
4501 struct netdev_hw_addr *ha;
4502
4503 rx_mode = AcceptBroadcast | AcceptMyPhys;
4504 mc_filter[1] = mc_filter[0] = 0;
4505 netdev_for_each_mc_addr(ha, dev) {
4506 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
4507 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
4508 rx_mode |= AcceptMulticast;
4509 }
4510 }
4511
4512 if (dev->features & NETIF_F_RXALL)
4513 rx_mode |= (AcceptErr | AcceptRunt);
4514
4515 tmp = (RTL_R32(RxConfig) & ~RX_CONFIG_ACCEPT_MASK) | rx_mode;
4516
4517 if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
4518 u32 data = mc_filter[0];
4519
4520 mc_filter[0] = swab32(mc_filter[1]);
4521 mc_filter[1] = swab32(data);
4522 }
4523
Nathan Walp04817762012-11-01 12:08:47 +00004524 if (tp->mac_version == RTL_GIGA_MAC_VER_35)
4525 mc_filter[1] = mc_filter[0] = 0xffffffff;
4526
Francois Romieue6b763e2012-03-08 09:35:39 +01004527 RTL_W32(MAR0 + 4, mc_filter[1]);
4528 RTL_W32(MAR0 + 0, mc_filter[0]);
4529
4530 RTL_W32(RxConfig, tmp);
4531}
4532
Francois Romieu07ce4062007-02-23 23:36:39 +01004533static void rtl_hw_start_8169(struct net_device *dev)
4534{
4535 struct rtl8169_private *tp = netdev_priv(dev);
4536 void __iomem *ioaddr = tp->mmio_addr;
4537 struct pci_dev *pdev = tp->pci_dev;
Francois Romieu07ce4062007-02-23 23:36:39 +01004538
Francois Romieu9cb427b2006-11-02 00:10:16 +01004539 if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
4540 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
4541 pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
4542 }
4543
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 RTL_W8(Cfg9346, Cfg9346_Unlock);
Francois Romieucecb5fd2011-04-01 10:21:07 +02004545 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4546 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4547 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4548 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieu9cb427b2006-11-02 00:10:16 +01004549 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4550
Hayes Wange542a222011-07-06 15:58:04 +08004551 rtl_init_rxcfg(tp);
4552
françois romieuf0298f82011-01-03 15:07:42 +00004553 RTL_W8(EarlyTxThres, NoEarlyTx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
Eric Dumazet6f0333b2010-10-11 11:17:47 +00004555 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Francois Romieucecb5fd2011-04-01 10:21:07 +02004557 if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
4558 tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4559 tp->mac_version == RTL_GIGA_MAC_VER_03 ||
4560 tp->mac_version == RTL_GIGA_MAC_VER_04)
Francois Romieuc946b302007-10-04 00:42:50 +02004561 rtl_set_rx_tx_config_registers(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
Francois Romieu7f796d832007-06-11 23:04:41 +02004563 tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
Francois Romieubcf0bf92006-07-26 23:14:13 +02004564
Francois Romieucecb5fd2011-04-01 10:21:07 +02004565 if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
4566 tp->mac_version == RTL_GIGA_MAC_VER_03) {
Joe Perches06fa7352007-10-18 21:15:00 +02004567 dprintk("Set MAC Reg C+CR Offset 0xE0. "
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 "Bit-3 and bit-14 MUST be 1\n");
Francois Romieubcf0bf92006-07-26 23:14:13 +02004569 tp->cp_cmd |= (1 << 14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571
Francois Romieubcf0bf92006-07-26 23:14:13 +02004572 RTL_W16(CPlusCmd, tp->cp_cmd);
4573
Francois Romieu6dccd162007-02-13 23:38:05 +01004574 rtl8169_set_magic_reg(ioaddr, tp->mac_version);
4575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 /*
4577 * Undocumented corner. Supposedly:
4578 * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
4579 */
4580 RTL_W16(IntrMitigate, 0x0000);
4581
Francois Romieu7f796d832007-06-11 23:04:41 +02004582 rtl_set_rx_tx_desc_registers(tp, ioaddr);
Francois Romieu9cb427b2006-11-02 00:10:16 +01004583
Francois Romieucecb5fd2011-04-01 10:21:07 +02004584 if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
4585 tp->mac_version != RTL_GIGA_MAC_VER_02 &&
4586 tp->mac_version != RTL_GIGA_MAC_VER_03 &&
4587 tp->mac_version != RTL_GIGA_MAC_VER_04) {
Francois Romieuc946b302007-10-04 00:42:50 +02004588 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
4589 rtl_set_rx_tx_config_registers(tp);
4590 }
4591
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieub518fa82006-08-16 15:23:13 +02004593
4594 /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
4595 RTL_R8(IntrMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596
4597 RTL_W32(RxMissed, 0);
4598
Francois Romieu07ce4062007-02-23 23:36:39 +01004599 rtl_set_rx_mode(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601 /* no early-rx interrupts */
4602 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01004603}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004605static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
4606{
4607 if (tp->csi_ops.write)
Francois Romieu52989f02012-07-06 13:37:00 +02004608 tp->csi_ops.write(tp, addr, value);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004609}
4610
4611static u32 rtl_csi_read(struct rtl8169_private *tp, int addr)
4612{
Francois Romieu52989f02012-07-06 13:37:00 +02004613 return tp->csi_ops.read ? tp->csi_ops.read(tp, addr) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004614}
4615
4616static void rtl_csi_access_enable(struct rtl8169_private *tp, u32 bits)
Francois Romieudacf8152008-08-02 20:44:13 +02004617{
4618 u32 csi;
4619
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004620 csi = rtl_csi_read(tp, 0x070c) & 0x00ffffff;
4621 rtl_csi_write(tp, 0x070c, csi | bits);
françois romieu650e8d52011-01-03 15:08:29 +00004622}
4623
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004624static void rtl_csi_access_enable_1(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004625{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004626 rtl_csi_access_enable(tp, 0x17000000);
françois romieue6de30d2011-01-03 15:08:37 +00004627}
4628
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004629static void rtl_csi_access_enable_2(struct rtl8169_private *tp)
françois romieu650e8d52011-01-03 15:08:29 +00004630{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004631 rtl_csi_access_enable(tp, 0x27000000);
4632}
4633
Francois Romieuffc46952012-07-06 14:19:23 +02004634DECLARE_RTL_COND(rtl_csiar_cond)
4635{
4636 void __iomem *ioaddr = tp->mmio_addr;
4637
4638 return RTL_R32(CSIAR) & CSIAR_FLAG;
4639}
4640
Francois Romieu52989f02012-07-06 13:37:00 +02004641static void r8169_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004642{
Francois Romieu52989f02012-07-06 13:37:00 +02004643 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004644
4645 RTL_W32(CSIDR, value);
4646 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4647 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4648
Francois Romieuffc46952012-07-06 14:19:23 +02004649 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004650}
4651
Francois Romieu52989f02012-07-06 13:37:00 +02004652static u32 r8169_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004653{
Francois Romieu52989f02012-07-06 13:37:00 +02004654 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004655
4656 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
4657 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4658
Francois Romieuffc46952012-07-06 14:19:23 +02004659 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4660 RTL_R32(CSIDR) : ~0;
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004661}
4662
Francois Romieu52989f02012-07-06 13:37:00 +02004663static void r8402_csi_write(struct rtl8169_private *tp, int addr, int value)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004664{
Francois Romieu52989f02012-07-06 13:37:00 +02004665 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004666
4667 RTL_W32(CSIDR, value);
4668 RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
4669 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT |
4670 CSIAR_FUNC_NIC);
4671
Francois Romieuffc46952012-07-06 14:19:23 +02004672 rtl_udelay_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
Hayes Wang7e18dca2012-03-30 14:33:02 +08004673}
4674
Francois Romieu52989f02012-07-06 13:37:00 +02004675static u32 r8402_csi_read(struct rtl8169_private *tp, int addr)
Hayes Wang7e18dca2012-03-30 14:33:02 +08004676{
Francois Romieu52989f02012-07-06 13:37:00 +02004677 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004678
4679 RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | CSIAR_FUNC_NIC |
4680 CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
4681
Francois Romieuffc46952012-07-06 14:19:23 +02004682 return rtl_udelay_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
4683 RTL_R32(CSIDR) : ~0;
Hayes Wang7e18dca2012-03-30 14:33:02 +08004684}
4685
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004686static void __devinit rtl_init_csi_ops(struct rtl8169_private *tp)
4687{
4688 struct csi_ops *ops = &tp->csi_ops;
4689
4690 switch (tp->mac_version) {
4691 case RTL_GIGA_MAC_VER_01:
4692 case RTL_GIGA_MAC_VER_02:
4693 case RTL_GIGA_MAC_VER_03:
4694 case RTL_GIGA_MAC_VER_04:
4695 case RTL_GIGA_MAC_VER_05:
4696 case RTL_GIGA_MAC_VER_06:
4697 case RTL_GIGA_MAC_VER_10:
4698 case RTL_GIGA_MAC_VER_11:
4699 case RTL_GIGA_MAC_VER_12:
4700 case RTL_GIGA_MAC_VER_13:
4701 case RTL_GIGA_MAC_VER_14:
4702 case RTL_GIGA_MAC_VER_15:
4703 case RTL_GIGA_MAC_VER_16:
4704 case RTL_GIGA_MAC_VER_17:
4705 ops->write = NULL;
4706 ops->read = NULL;
4707 break;
4708
Hayes Wang7e18dca2012-03-30 14:33:02 +08004709 case RTL_GIGA_MAC_VER_37:
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08004710 case RTL_GIGA_MAC_VER_38:
Hayes Wang7e18dca2012-03-30 14:33:02 +08004711 ops->write = r8402_csi_write;
4712 ops->read = r8402_csi_read;
4713 break;
4714
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004715 default:
4716 ops->write = r8169_csi_write;
4717 ops->read = r8169_csi_read;
4718 break;
4719 }
Francois Romieudacf8152008-08-02 20:44:13 +02004720}
4721
4722struct ephy_info {
4723 unsigned int offset;
4724 u16 mask;
4725 u16 bits;
4726};
4727
Francois Romieufdf6fc02012-07-06 22:40:38 +02004728static void rtl_ephy_init(struct rtl8169_private *tp, const struct ephy_info *e,
4729 int len)
Francois Romieudacf8152008-08-02 20:44:13 +02004730{
4731 u16 w;
4732
4733 while (len-- > 0) {
Francois Romieufdf6fc02012-07-06 22:40:38 +02004734 w = (rtl_ephy_read(tp, e->offset) & ~e->mask) | e->bits;
4735 rtl_ephy_write(tp, e->offset, w);
Francois Romieudacf8152008-08-02 20:44:13 +02004736 e++;
4737 }
4738}
4739
Francois Romieub726e492008-06-28 12:22:59 +02004740static void rtl_disable_clock_request(struct pci_dev *pdev)
4741{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004742 pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL,
4743 PCI_EXP_LNKCTL_CLKREQ_EN);
Francois Romieub726e492008-06-28 12:22:59 +02004744}
4745
françois romieue6de30d2011-01-03 15:08:37 +00004746static void rtl_enable_clock_request(struct pci_dev *pdev)
4747{
Jiang Liu7d7903b2012-07-24 17:20:16 +08004748 pcie_capability_set_word(pdev, PCI_EXP_LNKCTL,
4749 PCI_EXP_LNKCTL_CLKREQ_EN);
françois romieue6de30d2011-01-03 15:08:37 +00004750}
4751
Francois Romieub726e492008-06-28 12:22:59 +02004752#define R8168_CPCMD_QUIRK_MASK (\
4753 EnableBist | \
4754 Mac_dbgo_oe | \
4755 Force_half_dup | \
4756 Force_rxflow_en | \
4757 Force_txflow_en | \
4758 Cxpl_dbg_sel | \
4759 ASF | \
4760 PktCntrDisable | \
4761 Mac_dbgo_sel)
4762
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004763static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004764{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004765 void __iomem *ioaddr = tp->mmio_addr;
4766 struct pci_dev *pdev = tp->pci_dev;
4767
Francois Romieub726e492008-06-28 12:22:59 +02004768 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4769
4770 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4771
Francois Romieu2e68ae42008-06-28 12:00:55 +02004772 rtl_tx_performance_tweak(pdev,
4773 (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieu219a1e92008-06-28 11:58:39 +02004774}
4775
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004776static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004777{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004778 void __iomem *ioaddr = tp->mmio_addr;
4779
4780 rtl_hw_start_8168bb(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004781
françois romieuf0298f82011-01-03 15:07:42 +00004782 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieub726e492008-06-28 12:22:59 +02004783
4784 RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
Francois Romieu219a1e92008-06-28 11:58:39 +02004785}
4786
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004787static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004788{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004789 void __iomem *ioaddr = tp->mmio_addr;
4790 struct pci_dev *pdev = tp->pci_dev;
4791
Francois Romieub726e492008-06-28 12:22:59 +02004792 RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
4793
4794 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4795
Francois Romieu219a1e92008-06-28 11:58:39 +02004796 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
Francois Romieub726e492008-06-28 12:22:59 +02004797
4798 rtl_disable_clock_request(pdev);
4799
4800 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
Francois Romieu219a1e92008-06-28 11:58:39 +02004801}
4802
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004803static void rtl_hw_start_8168cp_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004804{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004805 static const struct ephy_info e_info_8168cp[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004806 { 0x01, 0, 0x0001 },
4807 { 0x02, 0x0800, 0x1000 },
4808 { 0x03, 0, 0x0042 },
4809 { 0x06, 0x0080, 0x0000 },
4810 { 0x07, 0, 0x2000 }
4811 };
4812
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004813 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004814
Francois Romieufdf6fc02012-07-06 22:40:38 +02004815 rtl_ephy_init(tp, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
Francois Romieub726e492008-06-28 12:22:59 +02004816
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004817 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004818}
4819
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004820static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
Francois Romieuef3386f2008-06-29 12:24:30 +02004821{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004822 void __iomem *ioaddr = tp->mmio_addr;
4823 struct pci_dev *pdev = tp->pci_dev;
4824
4825 rtl_csi_access_enable_2(tp);
Francois Romieuef3386f2008-06-29 12:24:30 +02004826
4827 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4828
4829 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4830
4831 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4832}
4833
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004834static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004835{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004836 void __iomem *ioaddr = tp->mmio_addr;
4837 struct pci_dev *pdev = tp->pci_dev;
4838
4839 rtl_csi_access_enable_2(tp);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004840
4841 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
4842
4843 /* Magic. */
4844 RTL_W8(DBG_REG, 0x20);
4845
françois romieuf0298f82011-01-03 15:07:42 +00004846 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu7f3e3d32008-07-20 18:53:20 +02004847
4848 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4849
4850 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4851}
4852
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004853static void rtl_hw_start_8168c_1(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004854{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004855 void __iomem *ioaddr = tp->mmio_addr;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004856 static const struct ephy_info e_info_8168c_1[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004857 { 0x02, 0x0800, 0x1000 },
4858 { 0x03, 0, 0x0002 },
4859 { 0x06, 0x0080, 0x0000 }
4860 };
4861
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004862 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004863
4864 RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
4865
Francois Romieufdf6fc02012-07-06 22:40:38 +02004866 rtl_ephy_init(tp, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
Francois Romieub726e492008-06-28 12:22:59 +02004867
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004868 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004869}
4870
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004871static void rtl_hw_start_8168c_2(struct rtl8169_private *tp)
Francois Romieu219a1e92008-06-28 11:58:39 +02004872{
Alexey Dobriyan350f7592009-11-25 15:54:21 -08004873 static const struct ephy_info e_info_8168c_2[] = {
Francois Romieub726e492008-06-28 12:22:59 +02004874 { 0x01, 0, 0x0001 },
4875 { 0x03, 0x0400, 0x0220 }
4876 };
4877
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004878 rtl_csi_access_enable_2(tp);
Francois Romieub726e492008-06-28 12:22:59 +02004879
Francois Romieufdf6fc02012-07-06 22:40:38 +02004880 rtl_ephy_init(tp, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
Francois Romieub726e492008-06-28 12:22:59 +02004881
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004882 __rtl_hw_start_8168cp(tp);
Francois Romieu219a1e92008-06-28 11:58:39 +02004883}
4884
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004885static void rtl_hw_start_8168c_3(struct rtl8169_private *tp)
Francois Romieu197ff762008-06-28 13:16:02 +02004886{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004887 rtl_hw_start_8168c_2(tp);
Francois Romieu197ff762008-06-28 13:16:02 +02004888}
4889
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004890static void rtl_hw_start_8168c_4(struct rtl8169_private *tp)
Francois Romieu6fb07052008-06-29 11:54:28 +02004891{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004892 rtl_csi_access_enable_2(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004893
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004894 __rtl_hw_start_8168cp(tp);
Francois Romieu6fb07052008-06-29 11:54:28 +02004895}
4896
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004897static void rtl_hw_start_8168d(struct rtl8169_private *tp)
Francois Romieu5b538df2008-07-20 16:22:45 +02004898{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004899 void __iomem *ioaddr = tp->mmio_addr;
4900 struct pci_dev *pdev = tp->pci_dev;
4901
4902 rtl_csi_access_enable_2(tp);
Francois Romieu5b538df2008-07-20 16:22:45 +02004903
4904 rtl_disable_clock_request(pdev);
4905
françois romieuf0298f82011-01-03 15:07:42 +00004906 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu5b538df2008-07-20 16:22:45 +02004907
4908 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4909
4910 RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
4911}
4912
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004913static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
hayeswang4804b3b2011-03-21 01:50:29 +00004914{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004915 void __iomem *ioaddr = tp->mmio_addr;
4916 struct pci_dev *pdev = tp->pci_dev;
4917
4918 rtl_csi_access_enable_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00004919
4920 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4921
4922 RTL_W8(MaxTxPacketSize, TxPacketMax);
4923
4924 rtl_disable_clock_request(pdev);
4925}
4926
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004927static void rtl_hw_start_8168d_4(struct rtl8169_private *tp)
françois romieue6de30d2011-01-03 15:08:37 +00004928{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004929 void __iomem *ioaddr = tp->mmio_addr;
4930 struct pci_dev *pdev = tp->pci_dev;
françois romieue6de30d2011-01-03 15:08:37 +00004931 static const struct ephy_info e_info_8168d_4[] = {
4932 { 0x0b, ~0, 0x48 },
4933 { 0x19, 0x20, 0x50 },
4934 { 0x0c, ~0, 0x20 }
4935 };
4936 int i;
4937
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004938 rtl_csi_access_enable_1(tp);
françois romieue6de30d2011-01-03 15:08:37 +00004939
4940 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4941
4942 RTL_W8(MaxTxPacketSize, TxPacketMax);
4943
4944 for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
4945 const struct ephy_info *e = e_info_8168d_4 + i;
4946 u16 w;
4947
Francois Romieufdf6fc02012-07-06 22:40:38 +02004948 w = rtl_ephy_read(tp, e->offset);
4949 rtl_ephy_write(tp, 0x03, (w & e->mask) | e->bits);
françois romieue6de30d2011-01-03 15:08:37 +00004950 }
4951
4952 rtl_enable_clock_request(pdev);
4953}
4954
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004955static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
hayeswang01dc7fe2011-03-21 01:50:28 +00004956{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004957 void __iomem *ioaddr = tp->mmio_addr;
4958 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004959 static const struct ephy_info e_info_8168e_1[] = {
hayeswang01dc7fe2011-03-21 01:50:28 +00004960 { 0x00, 0x0200, 0x0100 },
4961 { 0x00, 0x0000, 0x0004 },
4962 { 0x06, 0x0002, 0x0001 },
4963 { 0x06, 0x0000, 0x0030 },
4964 { 0x07, 0x0000, 0x2000 },
4965 { 0x00, 0x0000, 0x0020 },
4966 { 0x03, 0x5800, 0x2000 },
4967 { 0x03, 0x0000, 0x0001 },
4968 { 0x01, 0x0800, 0x1000 },
4969 { 0x07, 0x0000, 0x4000 },
4970 { 0x1e, 0x0000, 0x2000 },
4971 { 0x19, 0xffff, 0xfe6c },
4972 { 0x0a, 0x0000, 0x0040 }
4973 };
4974
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004975 rtl_csi_access_enable_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00004976
Francois Romieufdf6fc02012-07-06 22:40:38 +02004977 rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
hayeswang01dc7fe2011-03-21 01:50:28 +00004978
4979 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
4980
4981 RTL_W8(MaxTxPacketSize, TxPacketMax);
4982
4983 rtl_disable_clock_request(pdev);
4984
4985 /* Reset tx FIFO pointer */
Francois Romieucecb5fd2011-04-01 10:21:07 +02004986 RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
4987 RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
hayeswang01dc7fe2011-03-21 01:50:28 +00004988
Francois Romieucecb5fd2011-04-01 10:21:07 +02004989 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
hayeswang01dc7fe2011-03-21 01:50:28 +00004990}
4991
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004992static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
Hayes Wang70090422011-07-06 15:58:06 +08004993{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08004994 void __iomem *ioaddr = tp->mmio_addr;
4995 struct pci_dev *pdev = tp->pci_dev;
Hayes Wang70090422011-07-06 15:58:06 +08004996 static const struct ephy_info e_info_8168e_2[] = {
4997 { 0x09, 0x0000, 0x0080 },
4998 { 0x19, 0x0000, 0x0224 }
4999 };
5000
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005001 rtl_csi_access_enable_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005002
Francois Romieufdf6fc02012-07-06 22:40:38 +02005003 rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
Hayes Wang70090422011-07-06 15:58:06 +08005004
5005 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5006
Francois Romieufdf6fc02012-07-06 22:40:38 +02005007 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5008 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5009 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5010 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5011 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5012 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x07ff0060, ERIAR_EXGMAC);
5013 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5014 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang70090422011-07-06 15:58:06 +08005015
Hayes Wang3090bd92011-09-06 16:55:15 +08005016 RTL_W8(MaxTxPacketSize, EarlySize);
Hayes Wang70090422011-07-06 15:58:06 +08005017
5018 rtl_disable_clock_request(pdev);
5019
5020 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5021 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5022
5023 /* Adjust EEE LED frequency */
5024 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5025
5026 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5027 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5028 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5029}
5030
Hayes Wang5f886e02012-03-30 14:33:03 +08005031static void rtl_hw_start_8168f(struct rtl8169_private *tp)
Hayes Wangc2218922011-09-06 16:55:18 +08005032{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005033 void __iomem *ioaddr = tp->mmio_addr;
5034 struct pci_dev *pdev = tp->pci_dev;
Hayes Wangc2218922011-09-06 16:55:18 +08005035
Hayes Wang5f886e02012-03-30 14:33:03 +08005036 rtl_csi_access_enable_2(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005037
5038 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5039
Francois Romieufdf6fc02012-07-06 22:40:38 +02005040 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5041 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5042 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00100002, ERIAR_EXGMAC);
5043 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5044 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5045 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5046 rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5047 rtl_w1w0_eri(tp, 0x1d0, ERIAR_MASK_0001, 0x10, 0x00, ERIAR_EXGMAC);
5048 rtl_eri_write(tp, 0xcc, ERIAR_MASK_1111, 0x00000050, ERIAR_EXGMAC);
5049 rtl_eri_write(tp, 0xd0, ERIAR_MASK_1111, 0x00000060, ERIAR_EXGMAC);
Hayes Wangc2218922011-09-06 16:55:18 +08005050
5051 RTL_W8(MaxTxPacketSize, EarlySize);
5052
5053 rtl_disable_clock_request(pdev);
5054
5055 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5056 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
Hayes Wangc2218922011-09-06 16:55:18 +08005057 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
5058 RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
5059 RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
5060}
5061
Hayes Wang5f886e02012-03-30 14:33:03 +08005062static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
5063{
5064 void __iomem *ioaddr = tp->mmio_addr;
5065 static const struct ephy_info e_info_8168f_1[] = {
5066 { 0x06, 0x00c0, 0x0020 },
5067 { 0x08, 0x0001, 0x0002 },
5068 { 0x09, 0x0000, 0x0080 },
5069 { 0x19, 0x0000, 0x0224 }
5070 };
5071
5072 rtl_hw_start_8168f(tp);
5073
Francois Romieufdf6fc02012-07-06 22:40:38 +02005074 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wang5f886e02012-03-30 14:33:03 +08005075
Francois Romieufdf6fc02012-07-06 22:40:38 +02005076 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0xff00, ERIAR_EXGMAC);
Hayes Wang5f886e02012-03-30 14:33:03 +08005077
5078 /* Adjust EEE LED frequency */
5079 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5080}
5081
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005082static void rtl_hw_start_8411(struct rtl8169_private *tp)
5083{
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005084 static const struct ephy_info e_info_8168f_1[] = {
5085 { 0x06, 0x00c0, 0x0020 },
5086 { 0x0f, 0xffff, 0x5200 },
5087 { 0x1e, 0x0000, 0x4000 },
5088 { 0x19, 0x0000, 0x0224 }
5089 };
5090
5091 rtl_hw_start_8168f(tp);
5092
Francois Romieufdf6fc02012-07-06 22:40:38 +02005093 rtl_ephy_init(tp, e_info_8168f_1, ARRAY_SIZE(e_info_8168f_1));
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005094
Francois Romieufdf6fc02012-07-06 22:40:38 +02005095 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0c00, 0x0000, ERIAR_EXGMAC);
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005096}
5097
Hayes Wangc5583862012-07-02 17:23:22 +08005098static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
5099{
5100 void __iomem *ioaddr = tp->mmio_addr;
5101 struct pci_dev *pdev = tp->pci_dev;
5102
5103 rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
5104 rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
5105 rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
5106 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
5107
5108 rtl_csi_access_enable_1(tp);
5109
5110 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5111
5112 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5113 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5114
5115 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5116 RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
5117 RTL_W8(MaxTxPacketSize, EarlySize);
5118
5119 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5120 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5121
5122 /* Adjust EEE LED frequency */
5123 RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
5124
5125 rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
5126}
5127
Francois Romieu07ce4062007-02-23 23:36:39 +01005128static void rtl_hw_start_8168(struct net_device *dev)
5129{
Francois Romieu2dd99532007-06-11 23:22:52 +02005130 struct rtl8169_private *tp = netdev_priv(dev);
5131 void __iomem *ioaddr = tp->mmio_addr;
5132
5133 RTL_W8(Cfg9346, Cfg9346_Unlock);
5134
françois romieuf0298f82011-01-03 15:07:42 +00005135 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieu2dd99532007-06-11 23:22:52 +02005136
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005137 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieu2dd99532007-06-11 23:22:52 +02005138
Francois Romieu0e485152007-02-20 00:00:26 +01005139 tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
Francois Romieu2dd99532007-06-11 23:22:52 +02005140
5141 RTL_W16(CPlusCmd, tp->cp_cmd);
5142
Francois Romieu0e485152007-02-20 00:00:26 +01005143 RTL_W16(IntrMitigate, 0x5151);
5144
5145 /* Work around for RxFIFO overflow. */
françois romieu811fd302011-12-04 20:30:45 +00005146 if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01005147 tp->event_slow |= RxFIFOOver | PCSTimeout;
5148 tp->event_slow &= ~RxOverflow;
Francois Romieu0e485152007-02-20 00:00:26 +01005149 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005150
5151 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5152
Francois Romieub8363902008-06-01 12:31:57 +02005153 rtl_set_rx_mode(dev);
5154
5155 RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
5156 (InterFrameGap << TxInterFrameGapShift));
Francois Romieu2dd99532007-06-11 23:22:52 +02005157
5158 RTL_R8(IntrMask);
5159
Francois Romieu219a1e92008-06-28 11:58:39 +02005160 switch (tp->mac_version) {
5161 case RTL_GIGA_MAC_VER_11:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005162 rtl_hw_start_8168bb(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005163 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005164
5165 case RTL_GIGA_MAC_VER_12:
5166 case RTL_GIGA_MAC_VER_17:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005167 rtl_hw_start_8168bef(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005168 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005169
5170 case RTL_GIGA_MAC_VER_18:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005171 rtl_hw_start_8168cp_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005172 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005173
5174 case RTL_GIGA_MAC_VER_19:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005175 rtl_hw_start_8168c_1(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005176 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005177
5178 case RTL_GIGA_MAC_VER_20:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005179 rtl_hw_start_8168c_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005180 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005181
Francois Romieu197ff762008-06-28 13:16:02 +02005182 case RTL_GIGA_MAC_VER_21:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005183 rtl_hw_start_8168c_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005184 break;
Francois Romieu197ff762008-06-28 13:16:02 +02005185
Francois Romieu6fb07052008-06-29 11:54:28 +02005186 case RTL_GIGA_MAC_VER_22:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005187 rtl_hw_start_8168c_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005188 break;
Francois Romieu6fb07052008-06-29 11:54:28 +02005189
Francois Romieuef3386f2008-06-29 12:24:30 +02005190 case RTL_GIGA_MAC_VER_23:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005191 rtl_hw_start_8168cp_2(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005192 break;
Francois Romieuef3386f2008-06-29 12:24:30 +02005193
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005194 case RTL_GIGA_MAC_VER_24:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005195 rtl_hw_start_8168cp_3(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005196 break;
Francois Romieu7f3e3d32008-07-20 18:53:20 +02005197
Francois Romieu5b538df2008-07-20 16:22:45 +02005198 case RTL_GIGA_MAC_VER_25:
françois romieudaf9df62009-10-07 12:44:20 +00005199 case RTL_GIGA_MAC_VER_26:
5200 case RTL_GIGA_MAC_VER_27:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005201 rtl_hw_start_8168d(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005202 break;
Francois Romieu5b538df2008-07-20 16:22:45 +02005203
françois romieue6de30d2011-01-03 15:08:37 +00005204 case RTL_GIGA_MAC_VER_28:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005205 rtl_hw_start_8168d_4(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005206 break;
Francois Romieucecb5fd2011-04-01 10:21:07 +02005207
hayeswang4804b3b2011-03-21 01:50:29 +00005208 case RTL_GIGA_MAC_VER_31:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005209 rtl_hw_start_8168dp(tp);
hayeswang4804b3b2011-03-21 01:50:29 +00005210 break;
5211
hayeswang01dc7fe2011-03-21 01:50:28 +00005212 case RTL_GIGA_MAC_VER_32:
5213 case RTL_GIGA_MAC_VER_33:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005214 rtl_hw_start_8168e_1(tp);
Hayes Wang70090422011-07-06 15:58:06 +08005215 break;
5216 case RTL_GIGA_MAC_VER_34:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005217 rtl_hw_start_8168e_2(tp);
hayeswang01dc7fe2011-03-21 01:50:28 +00005218 break;
françois romieue6de30d2011-01-03 15:08:37 +00005219
Hayes Wangc2218922011-09-06 16:55:18 +08005220 case RTL_GIGA_MAC_VER_35:
5221 case RTL_GIGA_MAC_VER_36:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005222 rtl_hw_start_8168f_1(tp);
Hayes Wangc2218922011-09-06 16:55:18 +08005223 break;
5224
Hayes Wangb3d7b2f2012-03-30 14:48:06 +08005225 case RTL_GIGA_MAC_VER_38:
5226 rtl_hw_start_8411(tp);
5227 break;
5228
Hayes Wangc5583862012-07-02 17:23:22 +08005229 case RTL_GIGA_MAC_VER_40:
5230 case RTL_GIGA_MAC_VER_41:
5231 rtl_hw_start_8168g_1(tp);
5232 break;
5233
Francois Romieu219a1e92008-06-28 11:58:39 +02005234 default:
5235 printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
5236 dev->name, tp->mac_version);
hayeswang4804b3b2011-03-21 01:50:29 +00005237 break;
Francois Romieu219a1e92008-06-28 11:58:39 +02005238 }
Francois Romieu2dd99532007-06-11 23:22:52 +02005239
Francois Romieu0e485152007-02-20 00:00:26 +01005240 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5241
Francois Romieub8363902008-06-01 12:31:57 +02005242 RTL_W8(Cfg9346, Cfg9346_Lock);
5243
Francois Romieu2dd99532007-06-11 23:22:52 +02005244 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
Francois Romieu07ce4062007-02-23 23:36:39 +01005245}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
Francois Romieu2857ffb2008-08-02 21:08:49 +02005247#define R810X_CPCMD_QUIRK_MASK (\
5248 EnableBist | \
5249 Mac_dbgo_oe | \
5250 Force_half_dup | \
françois romieu5edcc532009-08-10 19:41:52 +00005251 Force_rxflow_en | \
Francois Romieu2857ffb2008-08-02 21:08:49 +02005252 Force_txflow_en | \
5253 Cxpl_dbg_sel | \
5254 ASF | \
5255 PktCntrDisable | \
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005256 Mac_dbgo_sel)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005257
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005258static void rtl_hw_start_8102e_1(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005259{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005260 void __iomem *ioaddr = tp->mmio_addr;
5261 struct pci_dev *pdev = tp->pci_dev;
Alexey Dobriyan350f7592009-11-25 15:54:21 -08005262 static const struct ephy_info e_info_8102e_1[] = {
Francois Romieu2857ffb2008-08-02 21:08:49 +02005263 { 0x01, 0, 0x6e65 },
5264 { 0x02, 0, 0x091f },
5265 { 0x03, 0, 0xc2f9 },
5266 { 0x06, 0, 0xafb5 },
5267 { 0x07, 0, 0x0e00 },
5268 { 0x19, 0, 0xec80 },
5269 { 0x01, 0, 0x2e65 },
5270 { 0x01, 0, 0x6e65 }
5271 };
5272 u8 cfg1;
5273
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005274 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005275
5276 RTL_W8(DBG_REG, FIX_NAK_1);
5277
5278 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5279
5280 RTL_W8(Config1,
5281 LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
5282 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
5283
5284 cfg1 = RTL_R8(Config1);
5285 if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
5286 RTL_W8(Config1, cfg1 & ~LEDS0);
5287
Francois Romieufdf6fc02012-07-06 22:40:38 +02005288 rtl_ephy_init(tp, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
Francois Romieu2857ffb2008-08-02 21:08:49 +02005289}
5290
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005291static void rtl_hw_start_8102e_2(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005292{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005293 void __iomem *ioaddr = tp->mmio_addr;
5294 struct pci_dev *pdev = tp->pci_dev;
5295
5296 rtl_csi_access_enable_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005297
5298 rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
5299
5300 RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
5301 RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005302}
5303
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005304static void rtl_hw_start_8102e_3(struct rtl8169_private *tp)
Francois Romieu2857ffb2008-08-02 21:08:49 +02005305{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005306 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005307
Francois Romieufdf6fc02012-07-06 22:40:38 +02005308 rtl_ephy_write(tp, 0x03, 0xc2f9);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005309}
5310
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005311static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005312{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005313 void __iomem *ioaddr = tp->mmio_addr;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005314 static const struct ephy_info e_info_8105e_1[] = {
5315 { 0x07, 0, 0x4000 },
5316 { 0x19, 0, 0x0200 },
5317 { 0x19, 0, 0x0020 },
5318 { 0x1e, 0, 0x2000 },
5319 { 0x03, 0, 0x0001 },
5320 { 0x19, 0, 0x0100 },
5321 { 0x19, 0, 0x0004 },
5322 { 0x0a, 0, 0x0020 }
5323 };
5324
Francois Romieucecb5fd2011-04-01 10:21:07 +02005325 /* Force LAN exit from ASPM if Rx/Tx are not idle */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005326 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5327
Francois Romieucecb5fd2011-04-01 10:21:07 +02005328 /* Disable Early Tally Counter */
Hayes Wang5a5e4442011-02-22 17:26:21 +08005329 RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
5330
5331 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
Hayes Wang4f6b00e2011-07-06 15:58:02 +08005332 RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005333
Francois Romieufdf6fc02012-07-06 22:40:38 +02005334 rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
Hayes Wang5a5e4442011-02-22 17:26:21 +08005335}
5336
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005337static void rtl_hw_start_8105e_2(struct rtl8169_private *tp)
Hayes Wang5a5e4442011-02-22 17:26:21 +08005338{
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005339 rtl_hw_start_8105e_1(tp);
Francois Romieufdf6fc02012-07-06 22:40:38 +02005340 rtl_ephy_write(tp, 0x1e, rtl_ephy_read(tp, 0x1e) | 0x8000);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005341}
5342
Hayes Wang7e18dca2012-03-30 14:33:02 +08005343static void rtl_hw_start_8402(struct rtl8169_private *tp)
5344{
5345 void __iomem *ioaddr = tp->mmio_addr;
5346 static const struct ephy_info e_info_8402[] = {
5347 { 0x19, 0xffff, 0xff64 },
5348 { 0x1e, 0, 0x4000 }
5349 };
5350
5351 rtl_csi_access_enable_2(tp);
5352
5353 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5354 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5355
5356 RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
5357 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
5358
Francois Romieufdf6fc02012-07-06 22:40:38 +02005359 rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
Hayes Wang7e18dca2012-03-30 14:33:02 +08005360
5361 rtl_tx_performance_tweak(tp->pci_dev, 0x5 << MAX_READ_REQUEST_SHIFT);
5362
Francois Romieufdf6fc02012-07-06 22:40:38 +02005363 rtl_eri_write(tp, 0xc8, ERIAR_MASK_1111, 0x00000002, ERIAR_EXGMAC);
5364 rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00000006, ERIAR_EXGMAC);
5365 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
5366 rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
5367 rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5368 rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
5369 rtl_w1w0_eri(tp, 0x0d4, ERIAR_MASK_0011, 0x0e00, 0xff00, ERIAR_EXGMAC);
Hayes Wang7e18dca2012-03-30 14:33:02 +08005370}
5371
Hayes Wang5598bfe2012-07-02 17:23:21 +08005372static void rtl_hw_start_8106(struct rtl8169_private *tp)
5373{
5374 void __iomem *ioaddr = tp->mmio_addr;
5375
5376 /* Force LAN exit from ASPM if Rx/Tx are not idle */
5377 RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
5378
5379 RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
5380 RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
5381 RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
5382}
5383
Francois Romieu07ce4062007-02-23 23:36:39 +01005384static void rtl_hw_start_8101(struct net_device *dev)
5385{
Francois Romieucdf1a602007-06-11 23:29:50 +02005386 struct rtl8169_private *tp = netdev_priv(dev);
5387 void __iomem *ioaddr = tp->mmio_addr;
5388 struct pci_dev *pdev = tp->pci_dev;
5389
Francois Romieuda78dbf2012-01-26 14:18:23 +01005390 if (tp->mac_version >= RTL_GIGA_MAC_VER_30)
5391 tp->event_slow &= ~RxFIFOOver;
françois romieu811fd302011-12-04 20:30:45 +00005392
Francois Romieucecb5fd2011-04-01 10:21:07 +02005393 if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
Jiang Liu7d7903b2012-07-24 17:20:16 +08005394 tp->mac_version == RTL_GIGA_MAC_VER_16)
Bjorn Helgaas8200bc72012-08-22 10:29:42 -06005395 pcie_capability_set_word(pdev, PCI_EXP_DEVCTL,
5396 PCI_EXP_DEVCTL_NOSNOOP_EN);
Francois Romieucdf1a602007-06-11 23:29:50 +02005397
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005398 RTL_W8(Cfg9346, Cfg9346_Unlock);
5399
Francois Romieu2857ffb2008-08-02 21:08:49 +02005400 switch (tp->mac_version) {
5401 case RTL_GIGA_MAC_VER_07:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005402 rtl_hw_start_8102e_1(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005403 break;
5404
5405 case RTL_GIGA_MAC_VER_08:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005406 rtl_hw_start_8102e_3(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005407 break;
5408
5409 case RTL_GIGA_MAC_VER_09:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005410 rtl_hw_start_8102e_2(tp);
Francois Romieu2857ffb2008-08-02 21:08:49 +02005411 break;
Hayes Wang5a5e4442011-02-22 17:26:21 +08005412
5413 case RTL_GIGA_MAC_VER_29:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005414 rtl_hw_start_8105e_1(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005415 break;
5416 case RTL_GIGA_MAC_VER_30:
Hayes Wangbeb1fe12012-03-30 14:33:01 +08005417 rtl_hw_start_8105e_2(tp);
Hayes Wang5a5e4442011-02-22 17:26:21 +08005418 break;
Hayes Wang7e18dca2012-03-30 14:33:02 +08005419
5420 case RTL_GIGA_MAC_VER_37:
5421 rtl_hw_start_8402(tp);
5422 break;
Hayes Wang5598bfe2012-07-02 17:23:21 +08005423
5424 case RTL_GIGA_MAC_VER_39:
5425 rtl_hw_start_8106(tp);
5426 break;
Francois Romieucdf1a602007-06-11 23:29:50 +02005427 }
5428
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005429 RTL_W8(Cfg9346, Cfg9346_Lock);
Francois Romieucdf1a602007-06-11 23:29:50 +02005430
françois romieuf0298f82011-01-03 15:07:42 +00005431 RTL_W8(MaxTxPacketSize, TxPacketMax);
Francois Romieucdf1a602007-06-11 23:29:50 +02005432
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005433 rtl_set_rx_max_size(ioaddr, rx_buf_sz);
Francois Romieucdf1a602007-06-11 23:29:50 +02005434
Hayes Wangd24e9aa2011-02-22 17:26:19 +08005435 tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
Francois Romieucdf1a602007-06-11 23:29:50 +02005436 RTL_W16(CPlusCmd, tp->cp_cmd);
5437
5438 RTL_W16(IntrMitigate, 0x0000);
5439
5440 rtl_set_rx_tx_desc_registers(tp, ioaddr);
5441
5442 RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
5443 rtl_set_rx_tx_config_registers(tp);
5444
Francois Romieucdf1a602007-06-11 23:29:50 +02005445 RTL_R8(IntrMask);
5446
Francois Romieucdf1a602007-06-11 23:29:50 +02005447 rtl_set_rx_mode(dev);
5448
5449 RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450}
5451
5452static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
5453{
Francois Romieud58d46b2011-05-03 16:38:29 +02005454 struct rtl8169_private *tp = netdev_priv(dev);
5455
5456 if (new_mtu < ETH_ZLEN ||
5457 new_mtu > rtl_chip_infos[tp->mac_version].jumbo_max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 return -EINVAL;
5459
Francois Romieud58d46b2011-05-03 16:38:29 +02005460 if (new_mtu > ETH_DATA_LEN)
5461 rtl_hw_jumbo_enable(tp);
5462 else
5463 rtl_hw_jumbo_disable(tp);
5464
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 dev->mtu = new_mtu;
Michał Mirosław350fb322011-04-08 06:35:56 +00005466 netdev_update_features(dev);
5467
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00005468 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469}
5470
5471static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
5472{
Al Viro95e09182007-12-22 18:55:39 +00005473 desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
5475}
5476
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005477static void rtl8169_free_rx_databuff(struct rtl8169_private *tp,
5478 void **data_buff, struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479{
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005480 dma_unmap_single(&tp->pci_dev->dev, le64_to_cpu(desc->addr), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005481 DMA_FROM_DEVICE);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005482
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005483 kfree(*data_buff);
5484 *data_buff = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 rtl8169_make_unusable_by_asic(desc);
5486}
5487
5488static inline void rtl8169_mark_to_asic(struct RxDesc *desc, u32 rx_buf_sz)
5489{
5490 u32 eor = le32_to_cpu(desc->opts1) & RingEnd;
5491
5492 desc->opts1 = cpu_to_le32(DescOwn | eor | rx_buf_sz);
5493}
5494
5495static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
5496 u32 rx_buf_sz)
5497{
5498 desc->addr = cpu_to_le64(mapping);
5499 wmb();
5500 rtl8169_mark_to_asic(desc, rx_buf_sz);
5501}
5502
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005503static inline void *rtl8169_align(void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504{
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005505 return (void *)ALIGN((long)data, 16);
5506}
5507
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005508static struct sk_buff *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
5509 struct RxDesc *desc)
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005510{
5511 void *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 dma_addr_t mapping;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005513 struct device *d = &tp->pci_dev->dev;
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005514 struct net_device *dev = tp->dev;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005515 int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005517 data = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
5518 if (!data)
5519 return NULL;
Francois Romieue9f63f32007-02-28 23:16:57 +01005520
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005521 if (rtl8169_align(data) != data) {
5522 kfree(data);
5523 data = kmalloc_node(rx_buf_sz + 15, GFP_KERNEL, node);
5524 if (!data)
5525 return NULL;
5526 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005527
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005528 mapping = dma_map_single(d, rtl8169_align(data), rx_buf_sz,
Stanislaw Gruszka231aee62010-10-20 22:25:38 +00005529 DMA_FROM_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005530 if (unlikely(dma_mapping_error(d, mapping))) {
5531 if (net_ratelimit())
5532 netif_err(tp, drv, tp->dev, "Failed to map RX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005533 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
5536 rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005537 return data;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005538
5539err_out:
5540 kfree(data);
5541 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542}
5543
5544static void rtl8169_rx_clear(struct rtl8169_private *tp)
5545{
Francois Romieu07d3f512007-02-21 22:40:46 +01005546 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547
5548 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005549 if (tp->Rx_databuff[i]) {
5550 rtl8169_free_rx_databuff(tp, tp->Rx_databuff + i,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 tp->RxDescArray + i);
5552 }
5553 }
5554}
5555
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005556static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557{
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005558 desc->opts1 |= cpu_to_le32(RingEnd);
5559}
Francois Romieu5b0384f2006-08-16 16:00:01 +02005560
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005561static int rtl8169_rx_fill(struct rtl8169_private *tp)
5562{
5563 unsigned int i;
5564
5565 for (i = 0; i < NUM_RX_DESC; i++) {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005566 void *data;
Francois Romieu4ae47c22007-06-16 23:28:45 +02005567
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005568 if (tp->Rx_databuff[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569 continue;
Francois Romieubcf0bf92006-07-26 23:14:13 +02005570
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005571 data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005572 if (!data) {
5573 rtl8169_make_unusable_by_asic(tp->RxDescArray + i);
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005574 goto err_out;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005575 }
5576 tp->Rx_databuff[i] = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005579 rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1);
5580 return 0;
5581
5582err_out:
5583 rtl8169_rx_clear(tp);
5584 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585}
5586
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587static int rtl8169_init_ring(struct net_device *dev)
5588{
5589 struct rtl8169_private *tp = netdev_priv(dev);
5590
5591 rtl8169_init_ring_indexes(tp);
5592
5593 memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005594 memset(tp->Rx_databuff, 0x0, NUM_RX_DESC * sizeof(void *));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595
Stanislaw Gruszka0ecbe1c2010-10-20 22:25:37 +00005596 return rtl8169_rx_fill(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597}
5598
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005599static void rtl8169_unmap_tx_skb(struct device *d, struct ring_info *tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 struct TxDesc *desc)
5601{
5602 unsigned int len = tx_skb->len;
5603
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005604 dma_unmap_single(d, le64_to_cpu(desc->addr), len, DMA_TO_DEVICE);
5605
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606 desc->opts1 = 0x00;
5607 desc->opts2 = 0x00;
5608 desc->addr = 0x00;
5609 tx_skb->len = 0;
5610}
5611
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005612static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
5613 unsigned int n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614{
5615 unsigned int i;
5616
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005617 for (i = 0; i < n; i++) {
5618 unsigned int entry = (start + i) % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 struct ring_info *tx_skb = tp->tx_skb + entry;
5620 unsigned int len = tx_skb->len;
5621
5622 if (len) {
5623 struct sk_buff *skb = tx_skb->skb;
5624
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005625 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 tp->TxDescArray + entry);
5627 if (skb) {
Stanislaw Gruszkacac4b222010-10-20 22:25:40 +00005628 tp->dev->stats.tx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 dev_kfree_skb(skb);
5630 tx_skb->skb = NULL;
5631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 }
5633 }
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005634}
5635
5636static void rtl8169_tx_clear(struct rtl8169_private *tp)
5637{
5638 rtl8169_tx_clear_range(tp, tp->dirty_tx, NUM_TX_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 tp->cur_tx = tp->dirty_tx = 0;
5640}
5641
Francois Romieu4422bcd2012-01-26 11:23:32 +01005642static void rtl_reset_work(struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643{
David Howellsc4028952006-11-22 14:57:56 +00005644 struct net_device *dev = tp->dev;
Francois Romieu56de4142011-03-15 17:29:31 +01005645 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646
Francois Romieuda78dbf2012-01-26 14:18:23 +01005647 napi_disable(&tp->napi);
5648 netif_stop_queue(dev);
5649 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
françois romieuc7c2c392011-12-04 20:30:52 +00005651 rtl8169_hw_reset(tp);
5652
Francois Romieu56de4142011-03-15 17:29:31 +01005653 for (i = 0; i < NUM_RX_DESC; i++)
5654 rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
5655
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 rtl8169_tx_clear(tp);
françois romieuc7c2c392011-12-04 20:30:52 +00005657 rtl8169_init_ring_indexes(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658
Francois Romieuda78dbf2012-01-26 14:18:23 +01005659 napi_enable(&tp->napi);
Francois Romieu56de4142011-03-15 17:29:31 +01005660 rtl_hw_start(dev);
5661 netif_wake_queue(dev);
5662 rtl8169_check_link_status(dev, tp, tp->mmio_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663}
5664
5665static void rtl8169_tx_timeout(struct net_device *dev)
5666{
Francois Romieuda78dbf2012-01-26 14:18:23 +01005667 struct rtl8169_private *tp = netdev_priv(dev);
5668
5669 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670}
5671
5672static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
Francois Romieu2b7b4312011-04-18 22:53:24 -07005673 u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674{
5675 struct skb_shared_info *info = skb_shinfo(skb);
5676 unsigned int cur_frag, entry;
Jeff Garzika6343af2007-07-17 05:39:58 -04005677 struct TxDesc * uninitialized_var(txd);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005678 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
5680 entry = tp->cur_tx;
5681 for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
Eric Dumazet9e903e02011-10-18 21:00:24 +00005682 const skb_frag_t *frag = info->frags + cur_frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 dma_addr_t mapping;
5684 u32 status, len;
5685 void *addr;
5686
5687 entry = (entry + 1) % NUM_TX_DESC;
5688
5689 txd = tp->TxDescArray + entry;
Eric Dumazet9e903e02011-10-18 21:00:24 +00005690 len = skb_frag_size(frag);
Ian Campbell929f6182011-08-31 00:47:06 +00005691 addr = skb_frag_address(frag);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005692 mapping = dma_map_single(d, addr, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005693 if (unlikely(dma_mapping_error(d, mapping))) {
5694 if (net_ratelimit())
5695 netif_err(tp, drv, tp->dev,
5696 "Failed to map TX fragments DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005697 goto err_out;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
Francois Romieucecb5fd2011-04-01 10:21:07 +02005700 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005701 status = opts[0] | len |
5702 (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
5704 txd->opts1 = cpu_to_le32(status);
Francois Romieu2b7b4312011-04-18 22:53:24 -07005705 txd->opts2 = cpu_to_le32(opts[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 txd->addr = cpu_to_le64(mapping);
5707
5708 tp->tx_skb[entry].len = len;
5709 }
5710
5711 if (cur_frag) {
5712 tp->tx_skb[entry].skb = skb;
5713 txd->opts1 |= cpu_to_le32(LastFrag);
5714 }
5715
5716 return cur_frag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005717
5718err_out:
5719 rtl8169_tx_clear_range(tp, tp->cur_tx + 1, cur_frag);
5720 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721}
5722
Francois Romieu2b7b4312011-04-18 22:53:24 -07005723static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
5724 struct sk_buff *skb, u32 *opts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725{
Francois Romieu2b7b4312011-04-18 22:53:24 -07005726 const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
Michał Mirosław350fb322011-04-08 06:35:56 +00005727 u32 mss = skb_shinfo(skb)->gso_size;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005728 int offset = info->opts_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729
Francois Romieu2b7b4312011-04-18 22:53:24 -07005730 if (mss) {
5731 opts[0] |= TD_LSO;
5732 opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
5733 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005734 const struct iphdr *ip = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
5736 if (ip->protocol == IPPROTO_TCP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005737 opts[offset] |= info->checksum.tcp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 else if (ip->protocol == IPPROTO_UDP)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005739 opts[offset] |= info->checksum.udp;
5740 else
5741 WARN_ON_ONCE(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743}
5744
Stephen Hemminger613573252009-08-31 19:50:58 +00005745static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
5746 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005747{
5748 struct rtl8169_private *tp = netdev_priv(dev);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005749 unsigned int entry = tp->cur_tx % NUM_TX_DESC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 struct TxDesc *txd = tp->TxDescArray + entry;
5751 void __iomem *ioaddr = tp->mmio_addr;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005752 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 dma_addr_t mapping;
5754 u32 status, len;
Francois Romieu2b7b4312011-04-18 22:53:24 -07005755 u32 opts[2];
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005756 int frags;
Francois Romieu5b0384f2006-08-16 16:00:01 +02005757
Julien Ducourthial477206a2012-05-09 00:00:06 +02005758 if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
Joe Perchesbf82c182010-02-09 11:49:50 +00005759 netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005760 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 }
5762
5763 if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005764 goto err_stop_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005766 len = skb_headlen(skb);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005767 mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005768 if (unlikely(dma_mapping_error(d, mapping))) {
5769 if (net_ratelimit())
5770 netif_err(tp, drv, dev, "Failed to map TX DMA!\n");
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005771 goto err_dma_0;
Stanislaw Gruszkad827d862010-10-20 22:25:43 +00005772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
5774 tp->tx_skb[entry].len = len;
5775 txd->addr = cpu_to_le64(mapping);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
Francois Romieu2b7b4312011-04-18 22:53:24 -07005777 opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
5778 opts[0] = DescOwn;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005779
Francois Romieu2b7b4312011-04-18 22:53:24 -07005780 rtl8169_tso_csum(tp, skb, opts);
5781
5782 frags = rtl8169_xmit_frags(tp, skb, opts);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005783 if (frags < 0)
5784 goto err_dma_1;
5785 else if (frags)
Francois Romieu2b7b4312011-04-18 22:53:24 -07005786 opts[0] |= FirstFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005787 else {
Francois Romieu2b7b4312011-04-18 22:53:24 -07005788 opts[0] |= FirstFrag | LastFrag;
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005789 tp->tx_skb[entry].skb = skb;
5790 }
5791
Francois Romieu2b7b4312011-04-18 22:53:24 -07005792 txd->opts2 = cpu_to_le32(opts[1]);
5793
Richard Cochran5047fb52012-03-10 07:29:42 +00005794 skb_tx_timestamp(skb);
5795
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 wmb();
5797
Francois Romieucecb5fd2011-04-01 10:21:07 +02005798 /* Anti gcc 2.95.3 bugware (sic) */
Francois Romieu2b7b4312011-04-18 22:53:24 -07005799 status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 txd->opts1 = cpu_to_le32(status);
5801
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 tp->cur_tx += frags + 1;
5803
David Dillow4c020a92010-03-03 16:33:10 +00005804 wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805
Francois Romieucecb5fd2011-04-01 10:21:07 +02005806 RTL_W8(TxPoll, NPQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807
Francois Romieuda78dbf2012-01-26 14:18:23 +01005808 mmiowb();
5809
Julien Ducourthial477206a2012-05-09 00:00:06 +02005810 if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Francois Romieuae1f23f2012-01-31 00:00:19 +01005811 /* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
5812 * not miss a ring update when it notices a stopped queue.
5813 */
5814 smp_wmb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 netif_stop_queue(dev);
Francois Romieuae1f23f2012-01-31 00:00:19 +01005816 /* Sync with rtl_tx:
5817 * - publish queue status and cur_tx ring index (write barrier)
5818 * - refresh dirty_tx ring index (read barrier).
5819 * May the current thread have a pessimistic view of the ring
5820 * status and forget to wake up queue, a racing rtl_tx thread
5821 * can't.
5822 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005823 smp_mb();
Julien Ducourthial477206a2012-05-09 00:00:06 +02005824 if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825 netif_wake_queue(dev);
5826 }
5827
Stephen Hemminger613573252009-08-31 19:50:58 +00005828 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005830err_dma_1:
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005831 rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
Stanislaw Gruszka3eafe502010-10-20 22:25:36 +00005832err_dma_0:
5833 dev_kfree_skb(skb);
5834 dev->stats.tx_dropped++;
5835 return NETDEV_TX_OK;
5836
5837err_stop_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 netif_stop_queue(dev);
Francois Romieucebf8cc2007-10-18 12:06:54 +02005839 dev->stats.tx_dropped++;
Stephen Hemminger613573252009-08-31 19:50:58 +00005840 return NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841}
5842
5843static void rtl8169_pcierr_interrupt(struct net_device *dev)
5844{
5845 struct rtl8169_private *tp = netdev_priv(dev);
5846 struct pci_dev *pdev = tp->pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 u16 pci_status, pci_cmd;
5848
5849 pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
5850 pci_read_config_word(pdev, PCI_STATUS, &pci_status);
5851
Joe Perchesbf82c182010-02-09 11:49:50 +00005852 netif_err(tp, intr, dev, "PCI error (cmd = 0x%04x, status = 0x%04x)\n",
5853 pci_cmd, pci_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854
5855 /*
5856 * The recovery sequence below admits a very elaborated explanation:
5857 * - it seems to work;
Francois Romieud03902b2006-11-23 00:00:42 +01005858 * - I did not see what else could be done;
5859 * - it makes iop3xx happy.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 *
5861 * Feel free to adjust to your needs.
5862 */
Francois Romieua27993f2006-12-18 00:04:19 +01005863 if (pdev->broken_parity_status)
Francois Romieud03902b2006-11-23 00:00:42 +01005864 pci_cmd &= ~PCI_COMMAND_PARITY;
5865 else
5866 pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
5867
5868 pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
5870 pci_write_config_word(pdev, PCI_STATUS,
5871 pci_status & (PCI_STATUS_DETECTED_PARITY |
5872 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_REC_MASTER_ABORT |
5873 PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_SIG_TARGET_ABORT));
5874
5875 /* The infamous DAC f*ckup only happens at boot time */
5876 if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
françois romieue6de30d2011-01-03 15:08:37 +00005877 void __iomem *ioaddr = tp->mmio_addr;
5878
Joe Perchesbf82c182010-02-09 11:49:50 +00005879 netif_info(tp, intr, dev, "disabling PCI DAC\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 tp->cp_cmd &= ~PCIDAC;
5881 RTL_W16(CPlusCmd, tp->cp_cmd);
5882 dev->features &= ~NETIF_F_HIGHDMA;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 }
5884
françois romieue6de30d2011-01-03 15:08:37 +00005885 rtl8169_hw_reset(tp);
Francois Romieud03902b2006-11-23 00:00:42 +01005886
Francois Romieu98ddf982012-01-31 10:47:34 +01005887 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888}
5889
Francois Romieuda78dbf2012-01-26 14:18:23 +01005890static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891{
5892 unsigned int dirty_tx, tx_left;
5893
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 dirty_tx = tp->dirty_tx;
5895 smp_rmb();
5896 tx_left = tp->cur_tx - dirty_tx;
5897
5898 while (tx_left > 0) {
5899 unsigned int entry = dirty_tx % NUM_TX_DESC;
5900 struct ring_info *tx_skb = tp->tx_skb + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 u32 status;
5902
5903 rmb();
5904 status = le32_to_cpu(tp->TxDescArray[entry].opts1);
5905 if (status & DescOwn)
5906 break;
5907
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005908 rtl8169_unmap_tx_skb(&tp->pci_dev->dev, tx_skb,
5909 tp->TxDescArray + entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 if (status & LastFrag) {
Francois Romieu17bcb682012-07-23 22:55:55 +02005911 u64_stats_update_begin(&tp->tx_stats.syncp);
5912 tp->tx_stats.packets++;
5913 tp->tx_stats.bytes += tx_skb->skb->len;
5914 u64_stats_update_end(&tp->tx_stats.syncp);
5915 dev_kfree_skb(tx_skb->skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 tx_skb->skb = NULL;
5917 }
5918 dirty_tx++;
5919 tx_left--;
5920 }
5921
5922 if (tp->dirty_tx != dirty_tx) {
5923 tp->dirty_tx = dirty_tx;
Francois Romieuae1f23f2012-01-31 00:00:19 +01005924 /* Sync with rtl8169_start_xmit:
5925 * - publish dirty_tx ring index (write barrier)
5926 * - refresh cur_tx ring index and queue status (read barrier)
5927 * May the current thread miss the stopped queue condition,
5928 * a racing xmit thread can only have a right view of the
5929 * ring status.
5930 */
Francois Romieu1e874e02012-01-27 15:05:38 +01005931 smp_mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 if (netif_queue_stopped(dev) &&
Julien Ducourthial477206a2012-05-09 00:00:06 +02005933 TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 netif_wake_queue(dev);
5935 }
Francois Romieud78ae2d2007-08-26 20:08:19 +02005936 /*
5937 * 8168 hack: TxPoll requests are lost when the Tx packets are
5938 * too close. Let's kick an extra TxPoll request when a burst
5939 * of start_xmit activity is detected (if it is not detected,
5940 * it is slow enough). -- FR
5941 */
Francois Romieuda78dbf2012-01-26 14:18:23 +01005942 if (tp->cur_tx != dirty_tx) {
5943 void __iomem *ioaddr = tp->mmio_addr;
5944
Francois Romieud78ae2d2007-08-26 20:08:19 +02005945 RTL_W8(TxPoll, NPQ);
Francois Romieuda78dbf2012-01-26 14:18:23 +01005946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 }
5948}
5949
Francois Romieu126fa4b2005-05-12 20:09:17 -04005950static inline int rtl8169_fragmented_frame(u32 status)
5951{
5952 return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
5953}
5954
Eric Dumazetadea1ac72010-09-05 20:04:05 -07005955static inline void rtl8169_rx_csum(struct sk_buff *skb, u32 opts1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 u32 status = opts1 & RxProtoMask;
5958
5959 if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
Shan Weid5d3ebe2010-11-12 00:15:25 +00005960 ((status == RxProtoUDP) && !(opts1 & UDPFail)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 skb->ip_summed = CHECKSUM_UNNECESSARY;
5962 else
Eric Dumazetbc8acf22010-09-02 13:07:41 -07005963 skb_checksum_none_assert(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964}
5965
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005966static struct sk_buff *rtl8169_try_rx_copy(void *data,
5967 struct rtl8169_private *tp,
5968 int pkt_size,
5969 dma_addr_t addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970{
Stephen Hemmingerb4496552007-06-17 01:06:49 +02005971 struct sk_buff *skb;
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005972 struct device *d = &tp->pci_dev->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005974 data = rtl8169_align(data);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005975 dma_sync_single_for_cpu(d, addr, pkt_size, DMA_FROM_DEVICE);
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005976 prefetch(data);
5977 skb = netdev_alloc_skb_ip_align(tp->dev, pkt_size);
5978 if (skb)
5979 memcpy(skb->data, data, pkt_size);
Stanislaw Gruszka48addcc2010-10-20 22:25:39 +00005980 dma_sync_single_for_device(d, addr, pkt_size, DMA_FROM_DEVICE);
5981
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005982 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983}
5984
Francois Romieuda78dbf2012-01-26 14:18:23 +01005985static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986{
5987 unsigned int cur_rx, rx_left;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00005988 unsigned int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 cur_rx = tp->cur_rx;
5991 rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
Francois Romieu865c6522008-05-11 14:51:00 +02005992 rx_left = min(rx_left, budget);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
Richard Dawe4dcb7d32005-05-27 21:12:00 +02005994 for (; rx_left > 0; rx_left--, cur_rx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 unsigned int entry = cur_rx % NUM_RX_DESC;
Francois Romieu126fa4b2005-05-12 20:09:17 -04005996 struct RxDesc *desc = tp->RxDescArray + entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 u32 status;
5998
5999 rmb();
David S. Miller8decf862011-09-22 03:23:13 -04006000 status = le32_to_cpu(desc->opts1) & tp->opts1_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
6002 if (status & DescOwn)
6003 break;
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006004 if (unlikely(status & RxRES)) {
Joe Perchesbf82c182010-02-09 11:49:50 +00006005 netif_info(tp, rx_err, dev, "Rx ERROR. status = %08x\n",
6006 status);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006007 dev->stats.rx_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 if (status & (RxRWT | RxRUNT))
Francois Romieucebf8cc2007-10-18 12:06:54 +02006009 dev->stats.rx_length_errors++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010 if (status & RxCRC)
Francois Romieucebf8cc2007-10-18 12:06:54 +02006011 dev->stats.rx_crc_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006012 if (status & RxFOVF) {
Francois Romieuda78dbf2012-01-26 14:18:23 +01006013 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Francois Romieucebf8cc2007-10-18 12:06:54 +02006014 dev->stats.rx_fifo_errors++;
Francois Romieu9dccf612006-05-14 12:31:17 +02006015 }
Ben Greear6bbe0212012-02-10 15:04:33 +00006016 if ((status & (RxRUNT | RxCRC)) &&
6017 !(status & (RxRWT | RxFOVF)) &&
6018 (dev->features & NETIF_F_RXALL))
6019 goto process_pkt;
6020
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006021 rtl8169_mark_to_asic(desc, rx_buf_sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022 } else {
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006023 struct sk_buff *skb;
Ben Greear6bbe0212012-02-10 15:04:33 +00006024 dma_addr_t addr;
6025 int pkt_size;
6026
6027process_pkt:
6028 addr = le64_to_cpu(desc->addr);
Ben Greear79d0c1d2012-02-10 15:04:34 +00006029 if (likely(!(dev->features & NETIF_F_RXFCS)))
6030 pkt_size = (status & 0x00003fff) - 4;
6031 else
6032 pkt_size = status & 0x00003fff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033
Francois Romieu126fa4b2005-05-12 20:09:17 -04006034 /*
6035 * The driver does not support incoming fragmented
6036 * frames. They are seen as a symptom of over-mtu
6037 * sized frames.
6038 */
6039 if (unlikely(rtl8169_fragmented_frame(status))) {
Francois Romieucebf8cc2007-10-18 12:06:54 +02006040 dev->stats.rx_dropped++;
6041 dev->stats.rx_length_errors++;
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006042 rtl8169_mark_to_asic(desc, rx_buf_sz);
Richard Dawe4dcb7d32005-05-27 21:12:00 +02006043 continue;
Francois Romieu126fa4b2005-05-12 20:09:17 -04006044 }
6045
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006046 skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
6047 tp, pkt_size, addr);
6048 rtl8169_mark_to_asic(desc, rx_buf_sz);
6049 if (!skb) {
6050 dev->stats.rx_dropped++;
6051 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 }
6053
Eric Dumazetadea1ac72010-09-05 20:04:05 -07006054 rtl8169_rx_csum(skb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 skb_put(skb, pkt_size);
6056 skb->protocol = eth_type_trans(skb, dev);
6057
Francois Romieu7a8fc772011-03-01 17:18:33 +01006058 rtl8169_rx_vlan_tag(desc, skb);
6059
Francois Romieu56de4142011-03-15 17:29:31 +01006060 napi_gro_receive(&tp->napi, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061
Junchang Wang8027aa22012-03-04 23:30:32 +01006062 u64_stats_update_begin(&tp->rx_stats.syncp);
6063 tp->rx_stats.packets++;
6064 tp->rx_stats.bytes += pkt_size;
6065 u64_stats_update_end(&tp->rx_stats.syncp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 }
Francois Romieu6dccd162007-02-13 23:38:05 +01006067
6068 /* Work around for AMD plateform. */
Al Viro95e09182007-12-22 18:55:39 +00006069 if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
Francois Romieu6dccd162007-02-13 23:38:05 +01006070 (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
6071 desc->opts2 = 0;
6072 cur_rx++;
6073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 }
6075
6076 count = cur_rx - tp->cur_rx;
6077 tp->cur_rx = cur_rx;
6078
Eric Dumazet6f0333b2010-10-11 11:17:47 +00006079 tp->dirty_rx += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
6081 return count;
6082}
6083
Francois Romieu07d3f512007-02-21 22:40:46 +01006084static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085{
Francois Romieu07d3f512007-02-21 22:40:46 +01006086 struct net_device *dev = dev_instance;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 struct rtl8169_private *tp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 int handled = 0;
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006089 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090
Francois Romieu9085cdfa2012-01-26 12:59:08 +01006091 status = rtl_get_events(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006092 if (status && status != 0xffff) {
6093 status &= RTL_EVENT_NAPI | tp->event_slow;
6094 if (status) {
6095 handled = 1;
françois romieu811fd302011-12-04 20:30:45 +00006096
Francois Romieuda78dbf2012-01-26 14:18:23 +01006097 rtl_irq_disable(tp);
6098 napi_schedule(&tp->napi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 return IRQ_RETVAL(handled);
6102}
6103
Francois Romieuda78dbf2012-01-26 14:18:23 +01006104/*
6105 * Workqueue context.
6106 */
6107static void rtl_slow_event_work(struct rtl8169_private *tp)
6108{
6109 struct net_device *dev = tp->dev;
6110 u16 status;
6111
6112 status = rtl_get_events(tp) & tp->event_slow;
6113 rtl_ack_events(tp, status);
6114
6115 if (unlikely(status & RxFIFOOver)) {
6116 switch (tp->mac_version) {
6117 /* Work around for rx fifo overflow */
6118 case RTL_GIGA_MAC_VER_11:
6119 netif_stop_queue(dev);
Francois Romieu934714d2012-01-31 11:09:21 +01006120 /* XXX - Hack alert. See rtl_task(). */
6121 set_bit(RTL_FLAG_TASK_RESET_PENDING, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006122 default:
6123 break;
6124 }
6125 }
6126
6127 if (unlikely(status & SYSErr))
6128 rtl8169_pcierr_interrupt(dev);
6129
6130 if (status & LinkChg)
6131 __rtl8169_check_link_status(dev, tp, tp->mmio_addr, true);
6132
françois romieu7dbb4912012-06-09 10:53:16 +00006133 rtl_irq_enable_all(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006134}
6135
Francois Romieu4422bcd2012-01-26 11:23:32 +01006136static void rtl_task(struct work_struct *work)
6137{
Francois Romieuda78dbf2012-01-26 14:18:23 +01006138 static const struct {
6139 int bitnr;
6140 void (*action)(struct rtl8169_private *);
6141 } rtl_work[] = {
Francois Romieu934714d2012-01-31 11:09:21 +01006142 /* XXX - keep rtl_slow_event_work() as first element. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006143 { RTL_FLAG_TASK_SLOW_PENDING, rtl_slow_event_work },
6144 { RTL_FLAG_TASK_RESET_PENDING, rtl_reset_work },
6145 { RTL_FLAG_TASK_PHY_PENDING, rtl_phy_work }
6146 };
Francois Romieu4422bcd2012-01-26 11:23:32 +01006147 struct rtl8169_private *tp =
6148 container_of(work, struct rtl8169_private, wk.work);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006149 struct net_device *dev = tp->dev;
6150 int i;
Francois Romieu4422bcd2012-01-26 11:23:32 +01006151
Francois Romieuda78dbf2012-01-26 14:18:23 +01006152 rtl_lock_work(tp);
6153
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006154 if (!netif_running(dev) ||
6155 !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
Francois Romieuda78dbf2012-01-26 14:18:23 +01006156 goto out_unlock;
6157
6158 for (i = 0; i < ARRAY_SIZE(rtl_work); i++) {
6159 bool pending;
6160
Francois Romieuda78dbf2012-01-26 14:18:23 +01006161 pending = test_and_clear_bit(rtl_work[i].bitnr, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006162 if (pending)
6163 rtl_work[i].action(tp);
6164 }
6165
6166out_unlock:
6167 rtl_unlock_work(tp);
Francois Romieu4422bcd2012-01-26 11:23:32 +01006168}
6169
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006170static int rtl8169_poll(struct napi_struct *napi, int budget)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171{
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006172 struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
6173 struct net_device *dev = tp->dev;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006174 u16 enable_mask = RTL_EVENT_NAPI | tp->event_slow;
6175 int work_done= 0;
6176 u16 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177
Francois Romieuda78dbf2012-01-26 14:18:23 +01006178 status = rtl_get_events(tp);
6179 rtl_ack_events(tp, status & ~tp->event_slow);
6180
6181 if (status & RTL_EVENT_NAPI_RX)
6182 work_done = rtl_rx(dev, tp, (u32) budget);
6183
6184 if (status & RTL_EVENT_NAPI_TX)
6185 rtl_tx(dev, tp);
6186
6187 if (status & tp->event_slow) {
6188 enable_mask &= ~tp->event_slow;
6189
6190 rtl_schedule_task(tp, RTL_FLAG_TASK_SLOW_PENDING);
6191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006193 if (work_done < budget) {
Ben Hutchings288379f2009-01-19 16:43:59 -08006194 napi_complete(napi);
David Dillowf11a3772009-05-22 15:29:34 +00006195
Francois Romieuda78dbf2012-01-26 14:18:23 +01006196 rtl_irq_enable(tp, enable_mask);
6197 mmiowb();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 }
6199
Stephen Hemmingerbea33482007-10-03 16:41:36 -07006200 return work_done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202
Francois Romieu523a6092008-09-10 22:28:56 +02006203static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
6204{
6205 struct rtl8169_private *tp = netdev_priv(dev);
6206
6207 if (tp->mac_version > RTL_GIGA_MAC_VER_06)
6208 return;
6209
6210 dev->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
6211 RTL_W32(RxMissed, 0);
6212}
6213
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214static void rtl8169_down(struct net_device *dev)
6215{
6216 struct rtl8169_private *tp = netdev_priv(dev);
6217 void __iomem *ioaddr = tp->mmio_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218
Francois Romieu4876cc12011-03-11 21:07:11 +01006219 del_timer_sync(&tp->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220
Stephen Hemminger93dd79e2007-10-28 17:14:06 +01006221 napi_disable(&tp->napi);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006222 netif_stop_queue(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Hayes Wang92fc43b2011-07-06 15:58:03 +08006224 rtl8169_hw_reset(tp);
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006225 /*
6226 * At this point device interrupts can not be enabled in any function,
Francois Romieu209e5ac2012-01-26 09:59:50 +01006227 * as netif_running is not true (rtl8169_interrupt, rtl8169_reset_task)
6228 * and napi is disabled (rtl8169_poll).
Stanislaw Gruszka323bb682010-10-20 22:25:41 +00006229 */
Francois Romieu523a6092008-09-10 22:28:56 +02006230 rtl8169_rx_missed(dev, ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 /* Give a racing hard_start_xmit a few cycles to complete. */
Francois Romieuda78dbf2012-01-26 14:18:23 +01006233 synchronize_sched();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Linus Torvalds1da177e2005-04-16 15:20:36 -07006235 rtl8169_tx_clear(tp);
6236
6237 rtl8169_rx_clear(tp);
françois romieu065c27c2011-01-03 15:08:12 +00006238
6239 rtl_pll_power_down(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240}
6241
6242static int rtl8169_close(struct net_device *dev)
6243{
6244 struct rtl8169_private *tp = netdev_priv(dev);
6245 struct pci_dev *pdev = tp->pci_dev;
6246
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006247 pm_runtime_get_sync(&pdev->dev);
6248
Francois Romieucecb5fd2011-04-01 10:21:07 +02006249 /* Update counters before going down */
Ivan Vecera355423d2009-02-06 21:49:57 -08006250 rtl8169_update_counters(dev);
6251
Francois Romieuda78dbf2012-01-26 14:18:23 +01006252 rtl_lock_work(tp);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006253 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006254
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 rtl8169_down(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006256 rtl_unlock_work(tp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006258 free_irq(pdev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Stanislaw Gruszka82553bb2010-10-08 04:25:01 +00006260 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6261 tp->RxPhyAddr);
6262 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6263 tp->TxPhyAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 tp->TxDescArray = NULL;
6265 tp->RxDescArray = NULL;
6266
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006267 pm_runtime_put_sync(&pdev->dev);
6268
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 return 0;
6270}
6271
Francois Romieudc1c00c2012-03-08 10:06:18 +01006272#ifdef CONFIG_NET_POLL_CONTROLLER
6273static void rtl8169_netpoll(struct net_device *dev)
6274{
6275 struct rtl8169_private *tp = netdev_priv(dev);
6276
6277 rtl8169_interrupt(tp->pci_dev->irq, dev);
6278}
6279#endif
6280
Francois Romieudf43ac72012-03-08 09:48:40 +01006281static int rtl_open(struct net_device *dev)
6282{
6283 struct rtl8169_private *tp = netdev_priv(dev);
6284 void __iomem *ioaddr = tp->mmio_addr;
6285 struct pci_dev *pdev = tp->pci_dev;
6286 int retval = -ENOMEM;
6287
6288 pm_runtime_get_sync(&pdev->dev);
6289
6290 /*
Jiri Kosinae75d6602012-04-08 21:48:52 +02006291 * Rx and Tx descriptors needs 256 bytes alignment.
Francois Romieudf43ac72012-03-08 09:48:40 +01006292 * dma_alloc_coherent provides more.
6293 */
6294 tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6295 &tp->TxPhyAddr, GFP_KERNEL);
6296 if (!tp->TxDescArray)
6297 goto err_pm_runtime_put;
6298
6299 tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6300 &tp->RxPhyAddr, GFP_KERNEL);
6301 if (!tp->RxDescArray)
6302 goto err_free_tx_0;
6303
6304 retval = rtl8169_init_ring(dev);
6305 if (retval < 0)
6306 goto err_free_rx_1;
6307
6308 INIT_WORK(&tp->wk.work, rtl_task);
6309
6310 smp_mb();
6311
6312 rtl_request_firmware(tp);
6313
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006314 retval = request_irq(pdev->irq, rtl8169_interrupt,
Francois Romieudf43ac72012-03-08 09:48:40 +01006315 (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
6316 dev->name, dev);
6317 if (retval < 0)
6318 goto err_release_fw_2;
6319
6320 rtl_lock_work(tp);
6321
6322 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
6323
6324 napi_enable(&tp->napi);
6325
6326 rtl8169_init_phy(dev, tp);
6327
6328 __rtl8169_set_features(dev, dev->features);
6329
6330 rtl_pll_power_up(tp);
6331
6332 rtl_hw_start(dev);
6333
6334 netif_start_queue(dev);
6335
6336 rtl_unlock_work(tp);
6337
6338 tp->saved_wolopts = 0;
6339 pm_runtime_put_noidle(&pdev->dev);
6340
6341 rtl8169_check_link_status(dev, tp, ioaddr);
6342out:
6343 return retval;
6344
6345err_release_fw_2:
6346 rtl_release_firmware(tp);
6347 rtl8169_rx_clear(tp);
6348err_free_rx_1:
6349 dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
6350 tp->RxPhyAddr);
6351 tp->RxDescArray = NULL;
6352err_free_tx_0:
6353 dma_free_coherent(&pdev->dev, R8169_TX_RING_BYTES, tp->TxDescArray,
6354 tp->TxPhyAddr);
6355 tp->TxDescArray = NULL;
6356err_pm_runtime_put:
6357 pm_runtime_put_noidle(&pdev->dev);
6358 goto out;
6359}
6360
Junchang Wang8027aa22012-03-04 23:30:32 +01006361static struct rtnl_link_stats64 *
6362rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363{
6364 struct rtl8169_private *tp = netdev_priv(dev);
6365 void __iomem *ioaddr = tp->mmio_addr;
Junchang Wang8027aa22012-03-04 23:30:32 +01006366 unsigned int start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367
Francois Romieuda78dbf2012-01-26 14:18:23 +01006368 if (netif_running(dev))
Francois Romieu523a6092008-09-10 22:28:56 +02006369 rtl8169_rx_missed(dev, ioaddr);
Francois Romieu5b0384f2006-08-16 16:00:01 +02006370
Junchang Wang8027aa22012-03-04 23:30:32 +01006371 do {
6372 start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
6373 stats->rx_packets = tp->rx_stats.packets;
6374 stats->rx_bytes = tp->rx_stats.bytes;
6375 } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
6376
6377
6378 do {
6379 start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
6380 stats->tx_packets = tp->tx_stats.packets;
6381 stats->tx_bytes = tp->tx_stats.bytes;
6382 } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
6383
6384 stats->rx_dropped = dev->stats.rx_dropped;
6385 stats->tx_dropped = dev->stats.tx_dropped;
6386 stats->rx_length_errors = dev->stats.rx_length_errors;
6387 stats->rx_errors = dev->stats.rx_errors;
6388 stats->rx_crc_errors = dev->stats.rx_crc_errors;
6389 stats->rx_fifo_errors = dev->stats.rx_fifo_errors;
6390 stats->rx_missed_errors = dev->stats.rx_missed_errors;
6391
6392 return stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393}
6394
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006395static void rtl8169_net_suspend(struct net_device *dev)
Francois Romieu5d06a992006-02-23 00:47:58 +01006396{
françois romieu065c27c2011-01-03 15:08:12 +00006397 struct rtl8169_private *tp = netdev_priv(dev);
6398
Francois Romieu5d06a992006-02-23 00:47:58 +01006399 if (!netif_running(dev))
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006400 return;
Francois Romieu5d06a992006-02-23 00:47:58 +01006401
6402 netif_device_detach(dev);
6403 netif_stop_queue(dev);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006404
6405 rtl_lock_work(tp);
6406 napi_disable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006407 clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006408 rtl_unlock_work(tp);
6409
6410 rtl_pll_power_down(tp);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006411}
Francois Romieu5d06a992006-02-23 00:47:58 +01006412
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006413#ifdef CONFIG_PM
6414
6415static int rtl8169_suspend(struct device *device)
6416{
6417 struct pci_dev *pdev = to_pci_dev(device);
6418 struct net_device *dev = pci_get_drvdata(pdev);
6419
6420 rtl8169_net_suspend(dev);
Francois Romieu1371fa62007-04-02 23:01:11 +02006421
Francois Romieu5d06a992006-02-23 00:47:58 +01006422 return 0;
6423}
6424
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006425static void __rtl8169_resume(struct net_device *dev)
6426{
françois romieu065c27c2011-01-03 15:08:12 +00006427 struct rtl8169_private *tp = netdev_priv(dev);
6428
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006429 netif_device_attach(dev);
françois romieu065c27c2011-01-03 15:08:12 +00006430
6431 rtl_pll_power_up(tp);
6432
Artem Savkovcff4c162012-04-03 10:29:11 +00006433 rtl_lock_work(tp);
6434 napi_enable(&tp->napi);
Francois Romieu6c4a70c2012-01-31 10:56:44 +01006435 set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags);
Artem Savkovcff4c162012-04-03 10:29:11 +00006436 rtl_unlock_work(tp);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006437
Francois Romieu98ddf982012-01-31 10:47:34 +01006438 rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006439}
6440
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006441static int rtl8169_resume(struct device *device)
Francois Romieu5d06a992006-02-23 00:47:58 +01006442{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006443 struct pci_dev *pdev = to_pci_dev(device);
Francois Romieu5d06a992006-02-23 00:47:58 +01006444 struct net_device *dev = pci_get_drvdata(pdev);
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006445 struct rtl8169_private *tp = netdev_priv(dev);
6446
6447 rtl8169_init_phy(dev, tp);
Francois Romieu5d06a992006-02-23 00:47:58 +01006448
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006449 if (netif_running(dev))
6450 __rtl8169_resume(dev);
Francois Romieu5d06a992006-02-23 00:47:58 +01006451
Francois Romieu5d06a992006-02-23 00:47:58 +01006452 return 0;
6453}
6454
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006455static int rtl8169_runtime_suspend(struct device *device)
6456{
6457 struct pci_dev *pdev = to_pci_dev(device);
6458 struct net_device *dev = pci_get_drvdata(pdev);
6459 struct rtl8169_private *tp = netdev_priv(dev);
6460
6461 if (!tp->TxDescArray)
6462 return 0;
6463
Francois Romieuda78dbf2012-01-26 14:18:23 +01006464 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006465 tp->saved_wolopts = __rtl8169_get_wol(tp);
6466 __rtl8169_set_wol(tp, WAKE_ANY);
Francois Romieuda78dbf2012-01-26 14:18:23 +01006467 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006468
6469 rtl8169_net_suspend(dev);
6470
6471 return 0;
6472}
6473
6474static int rtl8169_runtime_resume(struct device *device)
6475{
6476 struct pci_dev *pdev = to_pci_dev(device);
6477 struct net_device *dev = pci_get_drvdata(pdev);
6478 struct rtl8169_private *tp = netdev_priv(dev);
6479
6480 if (!tp->TxDescArray)
6481 return 0;
6482
Francois Romieuda78dbf2012-01-26 14:18:23 +01006483 rtl_lock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006484 __rtl8169_set_wol(tp, tp->saved_wolopts);
6485 tp->saved_wolopts = 0;
Francois Romieuda78dbf2012-01-26 14:18:23 +01006486 rtl_unlock_work(tp);
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006487
Stanislaw Gruszkafccec102010-10-20 22:25:42 +00006488 rtl8169_init_phy(dev, tp);
6489
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006490 __rtl8169_resume(dev);
6491
6492 return 0;
6493}
6494
6495static int rtl8169_runtime_idle(struct device *device)
6496{
6497 struct pci_dev *pdev = to_pci_dev(device);
6498 struct net_device *dev = pci_get_drvdata(pdev);
6499 struct rtl8169_private *tp = netdev_priv(dev);
6500
Rafael J. Wysockie4fbce72010-12-08 15:32:14 +00006501 return tp->TxDescArray ? -EBUSY : 0;
Rafael J. Wysockie1759442010-03-14 14:33:51 +00006502}
6503
Alexey Dobriyan47145212009-12-14 18:00:08 -08006504static const struct dev_pm_ops rtl8169_pm_ops = {
Francois Romieucecb5fd2011-04-01 10:21:07 +02006505 .suspend = rtl8169_suspend,
6506 .resume = rtl8169_resume,
6507 .freeze = rtl8169_suspend,
6508 .thaw = rtl8169_resume,
6509 .poweroff = rtl8169_suspend,
6510 .restore = rtl8169_resume,
6511 .runtime_suspend = rtl8169_runtime_suspend,
6512 .runtime_resume = rtl8169_runtime_resume,
6513 .runtime_idle = rtl8169_runtime_idle,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006514};
6515
6516#define RTL8169_PM_OPS (&rtl8169_pm_ops)
6517
6518#else /* !CONFIG_PM */
6519
6520#define RTL8169_PM_OPS NULL
6521
6522#endif /* !CONFIG_PM */
6523
David S. Miller1805b2f2011-10-24 18:18:09 -04006524static void rtl_wol_shutdown_quirk(struct rtl8169_private *tp)
6525{
6526 void __iomem *ioaddr = tp->mmio_addr;
6527
6528 /* WoL fails with 8168b when the receiver is disabled. */
6529 switch (tp->mac_version) {
6530 case RTL_GIGA_MAC_VER_11:
6531 case RTL_GIGA_MAC_VER_12:
6532 case RTL_GIGA_MAC_VER_17:
6533 pci_clear_master(tp->pci_dev);
6534
6535 RTL_W8(ChipCmd, CmdRxEnb);
6536 /* PCI commit */
6537 RTL_R8(ChipCmd);
6538 break;
6539 default:
6540 break;
6541 }
6542}
6543
Francois Romieu1765f952008-09-13 17:21:40 +02006544static void rtl_shutdown(struct pci_dev *pdev)
6545{
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006546 struct net_device *dev = pci_get_drvdata(pdev);
françois romieu4bb3f522009-06-17 11:41:45 +00006547 struct rtl8169_private *tp = netdev_priv(dev);
françois romieu2a15cd22012-03-06 01:14:12 +00006548 struct device *d = &pdev->dev;
6549
6550 pm_runtime_get_sync(d);
Francois Romieu1765f952008-09-13 17:21:40 +02006551
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006552 rtl8169_net_suspend(dev);
6553
Francois Romieucecb5fd2011-04-01 10:21:07 +02006554 /* Restore original MAC address */
Ivan Veceracc098dc2009-11-29 23:12:52 -08006555 rtl_rar_set(tp, dev->perm_addr);
6556
Hayes Wang92fc43b2011-07-06 15:58:03 +08006557 rtl8169_hw_reset(tp);
françois romieu4bb3f522009-06-17 11:41:45 +00006558
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006559 if (system_state == SYSTEM_POWER_OFF) {
David S. Miller1805b2f2011-10-24 18:18:09 -04006560 if (__rtl8169_get_wol(tp) & WAKE_ANY) {
6561 rtl_wol_suspend_quirk(tp);
6562 rtl_wol_shutdown_quirk(tp);
françois romieuca52efd2009-07-24 12:34:19 +00006563 }
6564
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006565 pci_wake_from_d3(pdev, true);
6566 pci_set_power_state(pdev, PCI_D3hot);
6567 }
françois romieu2a15cd22012-03-06 01:14:12 +00006568
6569 pm_runtime_put_noidle(d);
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006570}
Francois Romieu5d06a992006-02-23 00:47:58 +01006571
Francois Romieue27566e2012-03-08 09:54:01 +01006572static void __devexit rtl_remove_one(struct pci_dev *pdev)
6573{
6574 struct net_device *dev = pci_get_drvdata(pdev);
6575 struct rtl8169_private *tp = netdev_priv(dev);
6576
6577 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6578 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6579 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6580 rtl8168_driver_stop(tp);
6581 }
6582
6583 cancel_work_sync(&tp->wk.work);
6584
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006585 netif_napi_del(&tp->napi);
6586
Francois Romieue27566e2012-03-08 09:54:01 +01006587 unregister_netdev(dev);
6588
6589 rtl_release_firmware(tp);
6590
6591 if (pci_dev_run_wake(pdev))
6592 pm_runtime_get_noresume(&pdev->dev);
6593
6594 /* restore original MAC address */
6595 rtl_rar_set(tp, dev->perm_addr);
6596
6597 rtl_disable_msi(pdev, tp);
6598 rtl8169_release_board(pdev, dev, tp->mmio_addr);
6599 pci_set_drvdata(pdev, NULL);
6600}
6601
Francois Romieufa9c3852012-03-08 10:01:50 +01006602static const struct net_device_ops rtl_netdev_ops = {
Francois Romieudf43ac72012-03-08 09:48:40 +01006603 .ndo_open = rtl_open,
Francois Romieufa9c3852012-03-08 10:01:50 +01006604 .ndo_stop = rtl8169_close,
6605 .ndo_get_stats64 = rtl8169_get_stats64,
6606 .ndo_start_xmit = rtl8169_start_xmit,
6607 .ndo_tx_timeout = rtl8169_tx_timeout,
6608 .ndo_validate_addr = eth_validate_addr,
6609 .ndo_change_mtu = rtl8169_change_mtu,
6610 .ndo_fix_features = rtl8169_fix_features,
6611 .ndo_set_features = rtl8169_set_features,
6612 .ndo_set_mac_address = rtl_set_mac_address,
6613 .ndo_do_ioctl = rtl8169_ioctl,
6614 .ndo_set_rx_mode = rtl_set_rx_mode,
6615#ifdef CONFIG_NET_POLL_CONTROLLER
6616 .ndo_poll_controller = rtl8169_netpoll,
6617#endif
6618
6619};
6620
Francois Romieu31fa8b12012-03-08 10:09:40 +01006621static const struct rtl_cfg_info {
6622 void (*hw_start)(struct net_device *);
6623 unsigned int region;
6624 unsigned int align;
6625 u16 event_slow;
6626 unsigned features;
6627 u8 default_ver;
6628} rtl_cfg_infos [] = {
6629 [RTL_CFG_0] = {
6630 .hw_start = rtl_hw_start_8169,
6631 .region = 1,
6632 .align = 0,
6633 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver,
6634 .features = RTL_FEATURE_GMII,
6635 .default_ver = RTL_GIGA_MAC_VER_01,
6636 },
6637 [RTL_CFG_1] = {
6638 .hw_start = rtl_hw_start_8168,
6639 .region = 2,
6640 .align = 8,
6641 .event_slow = SYSErr | LinkChg | RxOverflow,
6642 .features = RTL_FEATURE_GMII | RTL_FEATURE_MSI,
6643 .default_ver = RTL_GIGA_MAC_VER_11,
6644 },
6645 [RTL_CFG_2] = {
6646 .hw_start = rtl_hw_start_8101,
6647 .region = 2,
6648 .align = 8,
6649 .event_slow = SYSErr | LinkChg | RxOverflow | RxFIFOOver |
6650 PCSTimeout,
6651 .features = RTL_FEATURE_MSI,
6652 .default_ver = RTL_GIGA_MAC_VER_13,
6653 }
6654};
6655
6656/* Cfg9346_Unlock assumed. */
6657static unsigned rtl_try_msi(struct rtl8169_private *tp,
6658 const struct rtl_cfg_info *cfg)
6659{
6660 void __iomem *ioaddr = tp->mmio_addr;
6661 unsigned msi = 0;
6662 u8 cfg2;
6663
6664 cfg2 = RTL_R8(Config2) & ~MSIEnable;
6665 if (cfg->features & RTL_FEATURE_MSI) {
6666 if (pci_enable_msi(tp->pci_dev)) {
6667 netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n");
6668 } else {
6669 cfg2 |= MSIEnable;
6670 msi = RTL_FEATURE_MSI;
6671 }
6672 }
6673 if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
6674 RTL_W8(Config2, cfg2);
6675 return msi;
6676}
6677
Hayes Wangc5583862012-07-02 17:23:22 +08006678DECLARE_RTL_COND(rtl_link_list_ready_cond)
6679{
6680 void __iomem *ioaddr = tp->mmio_addr;
6681
6682 return RTL_R8(MCU) & LINK_LIST_RDY;
6683}
6684
6685DECLARE_RTL_COND(rtl_rxtx_empty_cond)
6686{
6687 void __iomem *ioaddr = tp->mmio_addr;
6688
6689 return (RTL_R8(MCU) & RXTX_EMPTY) == RXTX_EMPTY;
6690}
6691
6692static void __devinit rtl_hw_init_8168g(struct rtl8169_private *tp)
6693{
6694 void __iomem *ioaddr = tp->mmio_addr;
6695 u32 data;
6696
6697 tp->ocp_base = OCP_STD_PHY_BASE;
6698
6699 RTL_W32(MISC, RTL_R32(MISC) | RXDV_GATED_EN);
6700
6701 if (!rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 42))
6702 return;
6703
6704 if (!rtl_udelay_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42))
6705 return;
6706
6707 RTL_W8(ChipCmd, RTL_R8(ChipCmd) & ~(CmdTxEnb | CmdRxEnb));
6708 msleep(1);
6709 RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
6710
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006711 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006712 data &= ~(1 << 14);
6713 r8168_mac_ocp_write(tp, 0xe8de, data);
6714
6715 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6716 return;
6717
Hayes Wang5f8bcce2012-07-10 08:47:05 +02006718 data = r8168_mac_ocp_read(tp, 0xe8de);
Hayes Wangc5583862012-07-02 17:23:22 +08006719 data |= (1 << 15);
6720 r8168_mac_ocp_write(tp, 0xe8de, data);
6721
6722 if (!rtl_udelay_loop_wait_high(tp, &rtl_link_list_ready_cond, 100, 42))
6723 return;
6724}
6725
6726static void __devinit rtl_hw_initialize(struct rtl8169_private *tp)
6727{
6728 switch (tp->mac_version) {
6729 case RTL_GIGA_MAC_VER_40:
6730 case RTL_GIGA_MAC_VER_41:
6731 rtl_hw_init_8168g(tp);
6732 break;
6733
6734 default:
6735 break;
6736 }
6737}
6738
Francois Romieu3b6cf252012-03-08 09:59:04 +01006739static int __devinit
6740rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6741{
6742 const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
6743 const unsigned int region = cfg->region;
6744 struct rtl8169_private *tp;
6745 struct mii_if_info *mii;
6746 struct net_device *dev;
6747 void __iomem *ioaddr;
6748 int chipset, i;
6749 int rc;
6750
6751 if (netif_msg_drv(&debug)) {
6752 printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
6753 MODULENAME, RTL8169_VERSION);
6754 }
6755
6756 dev = alloc_etherdev(sizeof (*tp));
6757 if (!dev) {
6758 rc = -ENOMEM;
6759 goto out;
6760 }
6761
6762 SET_NETDEV_DEV(dev, &pdev->dev);
Francois Romieufa9c3852012-03-08 10:01:50 +01006763 dev->netdev_ops = &rtl_netdev_ops;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006764 tp = netdev_priv(dev);
6765 tp->dev = dev;
6766 tp->pci_dev = pdev;
6767 tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
6768
6769 mii = &tp->mii;
6770 mii->dev = dev;
6771 mii->mdio_read = rtl_mdio_read;
6772 mii->mdio_write = rtl_mdio_write;
6773 mii->phy_id_mask = 0x1f;
6774 mii->reg_num_mask = 0x1f;
6775 mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
6776
6777 /* disable ASPM completely as that cause random device stop working
6778 * problems as well as full system hangs for some PCIe devices users */
6779 pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
6780 PCIE_LINK_STATE_CLKPM);
6781
6782 /* enable device (incl. PCI PM wakeup and hotplug setup) */
6783 rc = pci_enable_device(pdev);
6784 if (rc < 0) {
6785 netif_err(tp, probe, dev, "enable failure\n");
6786 goto err_out_free_dev_1;
6787 }
6788
6789 if (pci_set_mwi(pdev) < 0)
6790 netif_info(tp, probe, dev, "Mem-Wr-Inval unavailable\n");
6791
6792 /* make sure PCI base addr 1 is MMIO */
6793 if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
6794 netif_err(tp, probe, dev,
6795 "region #%d not an MMIO resource, aborting\n",
6796 region);
6797 rc = -ENODEV;
6798 goto err_out_mwi_2;
6799 }
6800
6801 /* check for weird/broken PCI region reporting */
6802 if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
6803 netif_err(tp, probe, dev,
6804 "Invalid PCI region size(s), aborting\n");
6805 rc = -ENODEV;
6806 goto err_out_mwi_2;
6807 }
6808
6809 rc = pci_request_regions(pdev, MODULENAME);
6810 if (rc < 0) {
6811 netif_err(tp, probe, dev, "could not request regions\n");
6812 goto err_out_mwi_2;
6813 }
6814
6815 tp->cp_cmd = RxChkSum;
6816
6817 if ((sizeof(dma_addr_t) > 4) &&
6818 !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && use_dac) {
6819 tp->cp_cmd |= PCIDAC;
6820 dev->features |= NETIF_F_HIGHDMA;
6821 } else {
6822 rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
6823 if (rc < 0) {
6824 netif_err(tp, probe, dev, "DMA configuration failed\n");
6825 goto err_out_free_res_3;
6826 }
6827 }
6828
6829 /* ioremap MMIO region */
6830 ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
6831 if (!ioaddr) {
6832 netif_err(tp, probe, dev, "cannot remap MMIO, aborting\n");
6833 rc = -EIO;
6834 goto err_out_free_res_3;
6835 }
6836 tp->mmio_addr = ioaddr;
6837
6838 if (!pci_is_pcie(pdev))
6839 netif_info(tp, probe, dev, "not PCI Express\n");
6840
6841 /* Identify chip attached to board */
6842 rtl8169_get_mac_version(tp, dev, cfg->default_ver);
6843
6844 rtl_init_rxcfg(tp);
6845
6846 rtl_irq_disable(tp);
6847
Hayes Wangc5583862012-07-02 17:23:22 +08006848 rtl_hw_initialize(tp);
6849
Francois Romieu3b6cf252012-03-08 09:59:04 +01006850 rtl_hw_reset(tp);
6851
6852 rtl_ack_events(tp, 0xffff);
6853
6854 pci_set_master(pdev);
6855
6856 /*
6857 * Pretend we are using VLANs; This bypasses a nasty bug where
6858 * Interrupts stop flowing on high load on 8110SCd controllers.
6859 */
6860 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6861 tp->cp_cmd |= RxVlan;
6862
6863 rtl_init_mdio_ops(tp);
6864 rtl_init_pll_power_ops(tp);
6865 rtl_init_jumbo_ops(tp);
Hayes Wangbeb1fe12012-03-30 14:33:01 +08006866 rtl_init_csi_ops(tp);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006867
6868 rtl8169_print_mac_version(tp);
6869
6870 chipset = tp->mac_version;
6871 tp->txd_version = rtl_chip_infos[chipset].txd_version;
6872
6873 RTL_W8(Cfg9346, Cfg9346_Unlock);
6874 RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
6875 RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
6876 if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
6877 tp->features |= RTL_FEATURE_WOL;
6878 if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
6879 tp->features |= RTL_FEATURE_WOL;
6880 tp->features |= rtl_try_msi(tp, cfg);
6881 RTL_W8(Cfg9346, Cfg9346_Lock);
6882
6883 if (rtl_tbi_enabled(tp)) {
6884 tp->set_speed = rtl8169_set_speed_tbi;
6885 tp->get_settings = rtl8169_gset_tbi;
6886 tp->phy_reset_enable = rtl8169_tbi_reset_enable;
6887 tp->phy_reset_pending = rtl8169_tbi_reset_pending;
6888 tp->link_ok = rtl8169_tbi_link_ok;
6889 tp->do_ioctl = rtl_tbi_ioctl;
6890 } else {
6891 tp->set_speed = rtl8169_set_speed_xmii;
6892 tp->get_settings = rtl8169_gset_xmii;
6893 tp->phy_reset_enable = rtl8169_xmii_reset_enable;
6894 tp->phy_reset_pending = rtl8169_xmii_reset_pending;
6895 tp->link_ok = rtl8169_xmii_link_ok;
6896 tp->do_ioctl = rtl_xmii_ioctl;
6897 }
6898
6899 mutex_init(&tp->wk.mutex);
6900
6901 /* Get MAC address */
6902 for (i = 0; i < ETH_ALEN; i++)
6903 dev->dev_addr[i] = RTL_R8(MAC0 + i);
6904 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
6905
6906 SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
6907 dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
Francois Romieu3b6cf252012-03-08 09:59:04 +01006908
6909 netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
6910
6911 /* don't enable SG, IP_CSUM and TSO by default - it might not work
6912 * properly for all devices */
6913 dev->features |= NETIF_F_RXCSUM |
6914 NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6915
6916 dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6917 NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6918 dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
6919 NETIF_F_HIGHDMA;
6920
6921 if (tp->mac_version == RTL_GIGA_MAC_VER_05)
6922 /* 8110SCd requires hardware Rx VLAN - disallow toggling */
6923 dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
6924
6925 dev->hw_features |= NETIF_F_RXALL;
6926 dev->hw_features |= NETIF_F_RXFCS;
6927
6928 tp->hw_start = cfg->hw_start;
6929 tp->event_slow = cfg->event_slow;
6930
6931 tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ?
6932 ~(RxBOVF | RxFOVF) : ~0;
6933
6934 init_timer(&tp->timer);
6935 tp->timer.data = (unsigned long) dev;
6936 tp->timer.function = rtl8169_phy_timer;
6937
6938 tp->rtl_fw = RTL_FIRMWARE_UNKNOWN;
6939
6940 rc = register_netdev(dev);
6941 if (rc < 0)
6942 goto err_out_msi_4;
6943
6944 pci_set_drvdata(pdev, dev);
6945
Francois Romieu92a7c4e2012-03-10 10:42:12 +01006946 netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
6947 rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
6948 (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006949 if (rtl_chip_infos[chipset].jumbo_max != JUMBO_1K) {
6950 netif_info(tp, probe, dev, "jumbo features [frames: %d bytes, "
6951 "tx checksumming: %s]\n",
6952 rtl_chip_infos[chipset].jumbo_max,
6953 rtl_chip_infos[chipset].jumbo_tx_csum ? "ok" : "ko");
6954 }
6955
6956 if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
6957 tp->mac_version == RTL_GIGA_MAC_VER_28 ||
6958 tp->mac_version == RTL_GIGA_MAC_VER_31) {
6959 rtl8168_driver_start(tp);
6960 }
6961
6962 device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
6963
6964 if (pci_dev_run_wake(pdev))
6965 pm_runtime_put_noidle(&pdev->dev);
6966
6967 netif_carrier_off(dev);
6968
6969out:
6970 return rc;
6971
6972err_out_msi_4:
Devendra Nagaad1be8d2012-05-31 01:51:20 +00006973 netif_napi_del(&tp->napi);
Francois Romieu3b6cf252012-03-08 09:59:04 +01006974 rtl_disable_msi(pdev, tp);
6975 iounmap(ioaddr);
6976err_out_free_res_3:
6977 pci_release_regions(pdev);
6978err_out_mwi_2:
6979 pci_clear_mwi(pdev);
6980 pci_disable_device(pdev);
6981err_out_free_dev_1:
6982 free_netdev(dev);
6983 goto out;
6984}
6985
Linus Torvalds1da177e2005-04-16 15:20:36 -07006986static struct pci_driver rtl8169_pci_driver = {
6987 .name = MODULENAME,
6988 .id_table = rtl8169_pci_tbl,
Francois Romieu3b6cf252012-03-08 09:59:04 +01006989 .probe = rtl_init_one,
Francois Romieue27566e2012-03-08 09:54:01 +01006990 .remove = __devexit_p(rtl_remove_one),
Francois Romieu1765f952008-09-13 17:21:40 +02006991 .shutdown = rtl_shutdown,
Rafael J. Wysocki861ab442009-04-05 08:40:04 +00006992 .driver.pm = RTL8169_PM_OPS,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006993};
6994
Francois Romieu07d3f512007-02-21 22:40:46 +01006995static int __init rtl8169_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996{
Jeff Garzik29917622006-08-19 17:48:59 -04006997 return pci_register_driver(&rtl8169_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998}
6999
Francois Romieu07d3f512007-02-21 22:40:46 +01007000static void __exit rtl8169_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007001{
7002 pci_unregister_driver(&rtl8169_pci_driver);
7003}
7004
7005module_init(rtl8169_init_module);
7006module_exit(rtl8169_cleanup_module);