1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This file is free software: you may copy, redistribute and/or modify it
5*4882a593Smuzhiyun * under the terms of the GNU General Public License as published by the
6*4882a593Smuzhiyun * Free Software Foundation, either version 2 of the License, or (at your
7*4882a593Smuzhiyun * option) any later version.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This file is distributed in the hope that it will be useful, but
10*4882a593Smuzhiyun * WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12*4882a593Smuzhiyun * General Public License for more details.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
15*4882a593Smuzhiyun * along with this program. If not, see <http://www.gnu.org/licenses/>.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * This file incorporates work covered by the following copyright and
18*4882a593Smuzhiyun * permission notice:
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Copyright (c) 2012 Qualcomm Atheros, Inc.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
23*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
24*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
27*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
28*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
29*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
30*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
31*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun #include <linux/etherdevice.h>
35*4882a593Smuzhiyun #include <linux/delay.h>
36*4882a593Smuzhiyun #include <linux/pci.h>
37*4882a593Smuzhiyun #include <linux/mdio.h>
38*4882a593Smuzhiyun #include "reg.h"
39*4882a593Smuzhiyun #include "hw.h"
40*4882a593Smuzhiyun
alx_is_rev_a(u8 rev)41*4882a593Smuzhiyun static inline bool alx_is_rev_a(u8 rev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun return rev == ALX_REV_A0 || rev == ALX_REV_A1;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
alx_wait_mdio_idle(struct alx_hw * hw)46*4882a593Smuzhiyun static int alx_wait_mdio_idle(struct alx_hw *hw)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun u32 val;
49*4882a593Smuzhiyun int i;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun for (i = 0; i < ALX_MDIO_MAX_AC_TO; i++) {
52*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MDIO);
53*4882a593Smuzhiyun if (!(val & ALX_MDIO_BUSY))
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun udelay(10);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun return -ETIMEDOUT;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
alx_read_phy_core(struct alx_hw * hw,bool ext,u8 dev,u16 reg,u16 * phy_data)61*4882a593Smuzhiyun static int alx_read_phy_core(struct alx_hw *hw, bool ext, u8 dev,
62*4882a593Smuzhiyun u16 reg, u16 *phy_data)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun u32 val, clk_sel;
65*4882a593Smuzhiyun int err;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun *phy_data = 0;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* use slow clock when it's in hibernation status */
70*4882a593Smuzhiyun clk_sel = hw->link_speed != SPEED_UNKNOWN ?
71*4882a593Smuzhiyun ALX_MDIO_CLK_SEL_25MD4 :
72*4882a593Smuzhiyun ALX_MDIO_CLK_SEL_25MD128;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (ext) {
75*4882a593Smuzhiyun val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
76*4882a593Smuzhiyun reg << ALX_MDIO_EXTN_REG_SHIFT;
77*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MDIO_EXTN, val);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun val = ALX_MDIO_SPRES_PRMBL | ALX_MDIO_START |
80*4882a593Smuzhiyun ALX_MDIO_MODE_EXT | ALX_MDIO_OP_READ |
81*4882a593Smuzhiyun clk_sel << ALX_MDIO_CLK_SEL_SHIFT;
82*4882a593Smuzhiyun } else {
83*4882a593Smuzhiyun val = ALX_MDIO_SPRES_PRMBL |
84*4882a593Smuzhiyun clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
85*4882a593Smuzhiyun reg << ALX_MDIO_REG_SHIFT |
86*4882a593Smuzhiyun ALX_MDIO_START | ALX_MDIO_OP_READ;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MDIO, val);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun err = alx_wait_mdio_idle(hw);
91*4882a593Smuzhiyun if (err)
92*4882a593Smuzhiyun return err;
93*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MDIO);
94*4882a593Smuzhiyun *phy_data = ALX_GET_FIELD(val, ALX_MDIO_DATA);
95*4882a593Smuzhiyun return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
alx_write_phy_core(struct alx_hw * hw,bool ext,u8 dev,u16 reg,u16 phy_data)98*4882a593Smuzhiyun static int alx_write_phy_core(struct alx_hw *hw, bool ext, u8 dev,
99*4882a593Smuzhiyun u16 reg, u16 phy_data)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun u32 val, clk_sel;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* use slow clock when it's in hibernation status */
104*4882a593Smuzhiyun clk_sel = hw->link_speed != SPEED_UNKNOWN ?
105*4882a593Smuzhiyun ALX_MDIO_CLK_SEL_25MD4 :
106*4882a593Smuzhiyun ALX_MDIO_CLK_SEL_25MD128;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (ext) {
109*4882a593Smuzhiyun val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
110*4882a593Smuzhiyun reg << ALX_MDIO_EXTN_REG_SHIFT;
111*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MDIO_EXTN, val);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun val = ALX_MDIO_SPRES_PRMBL |
114*4882a593Smuzhiyun clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
115*4882a593Smuzhiyun phy_data << ALX_MDIO_DATA_SHIFT |
116*4882a593Smuzhiyun ALX_MDIO_START | ALX_MDIO_MODE_EXT;
117*4882a593Smuzhiyun } else {
118*4882a593Smuzhiyun val = ALX_MDIO_SPRES_PRMBL |
119*4882a593Smuzhiyun clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
120*4882a593Smuzhiyun reg << ALX_MDIO_REG_SHIFT |
121*4882a593Smuzhiyun phy_data << ALX_MDIO_DATA_SHIFT |
122*4882a593Smuzhiyun ALX_MDIO_START;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MDIO, val);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return alx_wait_mdio_idle(hw);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
__alx_read_phy_reg(struct alx_hw * hw,u16 reg,u16 * phy_data)129*4882a593Smuzhiyun static int __alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun return alx_read_phy_core(hw, false, 0, reg, phy_data);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
__alx_write_phy_reg(struct alx_hw * hw,u16 reg,u16 phy_data)134*4882a593Smuzhiyun static int __alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun return alx_write_phy_core(hw, false, 0, reg, phy_data);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
__alx_read_phy_ext(struct alx_hw * hw,u8 dev,u16 reg,u16 * pdata)139*4882a593Smuzhiyun static int __alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun return alx_read_phy_core(hw, true, dev, reg, pdata);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
__alx_write_phy_ext(struct alx_hw * hw,u8 dev,u16 reg,u16 data)144*4882a593Smuzhiyun static int __alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun return alx_write_phy_core(hw, true, dev, reg, data);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
__alx_read_phy_dbg(struct alx_hw * hw,u16 reg,u16 * pdata)149*4882a593Smuzhiyun static int __alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun int err;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
154*4882a593Smuzhiyun if (err)
155*4882a593Smuzhiyun return err;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return __alx_read_phy_reg(hw, ALX_MII_DBG_DATA, pdata);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
__alx_write_phy_dbg(struct alx_hw * hw,u16 reg,u16 data)160*4882a593Smuzhiyun static int __alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun int err;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
165*4882a593Smuzhiyun if (err)
166*4882a593Smuzhiyun return err;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return __alx_write_phy_reg(hw, ALX_MII_DBG_DATA, data);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
alx_read_phy_reg(struct alx_hw * hw,u16 reg,u16 * phy_data)171*4882a593Smuzhiyun int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun int err;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
176*4882a593Smuzhiyun err = __alx_read_phy_reg(hw, reg, phy_data);
177*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return err;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
alx_write_phy_reg(struct alx_hw * hw,u16 reg,u16 phy_data)182*4882a593Smuzhiyun int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun int err;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
187*4882a593Smuzhiyun err = __alx_write_phy_reg(hw, reg, phy_data);
188*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun return err;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
alx_read_phy_ext(struct alx_hw * hw,u8 dev,u16 reg,u16 * pdata)193*4882a593Smuzhiyun int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun int err;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
198*4882a593Smuzhiyun err = __alx_read_phy_ext(hw, dev, reg, pdata);
199*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun return err;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
alx_write_phy_ext(struct alx_hw * hw,u8 dev,u16 reg,u16 data)204*4882a593Smuzhiyun int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun int err;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
209*4882a593Smuzhiyun err = __alx_write_phy_ext(hw, dev, reg, data);
210*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun return err;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
alx_read_phy_dbg(struct alx_hw * hw,u16 reg,u16 * pdata)215*4882a593Smuzhiyun static int alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun int err;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
220*4882a593Smuzhiyun err = __alx_read_phy_dbg(hw, reg, pdata);
221*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun return err;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
alx_write_phy_dbg(struct alx_hw * hw,u16 reg,u16 data)226*4882a593Smuzhiyun static int alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun int err;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun spin_lock(&hw->mdio_lock);
231*4882a593Smuzhiyun err = __alx_write_phy_dbg(hw, reg, data);
232*4882a593Smuzhiyun spin_unlock(&hw->mdio_lock);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return err;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
alx_get_phy_config(struct alx_hw * hw)237*4882a593Smuzhiyun static u16 alx_get_phy_config(struct alx_hw *hw)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun u32 val;
240*4882a593Smuzhiyun u16 phy_val;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_PHY_CTRL);
243*4882a593Smuzhiyun /* phy in reset */
244*4882a593Smuzhiyun if ((val & ALX_PHY_CTRL_DSPRST_OUT) == 0)
245*4882a593Smuzhiyun return ALX_DRV_PHY_UNKNOWN;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_DRV);
248*4882a593Smuzhiyun val = ALX_GET_FIELD(val, ALX_DRV_PHY);
249*4882a593Smuzhiyun if (ALX_DRV_PHY_UNKNOWN == val)
250*4882a593Smuzhiyun return ALX_DRV_PHY_UNKNOWN;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun alx_read_phy_reg(hw, ALX_MII_DBG_ADDR, &phy_val);
253*4882a593Smuzhiyun if (ALX_PHY_INITED == phy_val)
254*4882a593Smuzhiyun return val;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return ALX_DRV_PHY_UNKNOWN;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
alx_wait_reg(struct alx_hw * hw,u32 reg,u32 wait,u32 * val)259*4882a593Smuzhiyun static bool alx_wait_reg(struct alx_hw *hw, u32 reg, u32 wait, u32 *val)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun u32 read;
262*4882a593Smuzhiyun int i;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun for (i = 0; i < ALX_SLD_MAX_TO; i++) {
265*4882a593Smuzhiyun read = alx_read_mem32(hw, reg);
266*4882a593Smuzhiyun if ((read & wait) == 0) {
267*4882a593Smuzhiyun if (val)
268*4882a593Smuzhiyun *val = read;
269*4882a593Smuzhiyun return true;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun mdelay(1);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun return false;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
alx_read_macaddr(struct alx_hw * hw,u8 * addr)277*4882a593Smuzhiyun static bool alx_read_macaddr(struct alx_hw *hw, u8 *addr)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun u32 mac0, mac1;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun mac0 = alx_read_mem32(hw, ALX_STAD0);
282*4882a593Smuzhiyun mac1 = alx_read_mem32(hw, ALX_STAD1);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /* addr should be big-endian */
285*4882a593Smuzhiyun put_unaligned(cpu_to_be32(mac0), (__be32 *)(addr + 2));
286*4882a593Smuzhiyun put_unaligned(cpu_to_be16(mac1), (__be16 *)addr);
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return is_valid_ether_addr(addr);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
alx_get_perm_macaddr(struct alx_hw * hw,u8 * addr)291*4882a593Smuzhiyun int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun u32 val;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /* try to get it from register first */
296*4882a593Smuzhiyun if (alx_read_macaddr(hw, addr))
297*4882a593Smuzhiyun return 0;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun /* try to load from efuse */
300*4882a593Smuzhiyun if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val))
301*4882a593Smuzhiyun return -EIO;
302*4882a593Smuzhiyun alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START);
303*4882a593Smuzhiyun if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL))
304*4882a593Smuzhiyun return -EIO;
305*4882a593Smuzhiyun if (alx_read_macaddr(hw, addr))
306*4882a593Smuzhiyun return 0;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* try to load from flash/eeprom (if present) */
309*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_EFLD);
310*4882a593Smuzhiyun if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) {
311*4882a593Smuzhiyun if (!alx_wait_reg(hw, ALX_EFLD,
312*4882a593Smuzhiyun ALX_EFLD_STAT | ALX_EFLD_START, &val))
313*4882a593Smuzhiyun return -EIO;
314*4882a593Smuzhiyun alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START);
315*4882a593Smuzhiyun if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL))
316*4882a593Smuzhiyun return -EIO;
317*4882a593Smuzhiyun if (alx_read_macaddr(hw, addr))
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return -EIO;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
alx_set_macaddr(struct alx_hw * hw,const u8 * addr)324*4882a593Smuzhiyun void alx_set_macaddr(struct alx_hw *hw, const u8 *addr)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun u32 val;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun /* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */
329*4882a593Smuzhiyun val = be32_to_cpu(get_unaligned((__be32 *)(addr + 2)));
330*4882a593Smuzhiyun alx_write_mem32(hw, ALX_STAD0, val);
331*4882a593Smuzhiyun val = be16_to_cpu(get_unaligned((__be16 *)addr));
332*4882a593Smuzhiyun alx_write_mem32(hw, ALX_STAD1, val);
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
alx_reset_osc(struct alx_hw * hw,u8 rev)335*4882a593Smuzhiyun static void alx_reset_osc(struct alx_hw *hw, u8 rev)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun u32 val, val2;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* clear Internal OSC settings, switching OSC by hw itself */
340*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MISC3);
341*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC3,
342*4882a593Smuzhiyun (val & ~ALX_MISC3_25M_BY_SW) |
343*4882a593Smuzhiyun ALX_MISC3_25M_NOTO_INTNL);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /* 25M clk from chipset may be unstable 1s after de-assert of
346*4882a593Smuzhiyun * PERST, driver need re-calibrate before enter Sleep for WoL
347*4882a593Smuzhiyun */
348*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MISC);
349*4882a593Smuzhiyun if (rev >= ALX_REV_B0) {
350*4882a593Smuzhiyun /* restore over current protection def-val,
351*4882a593Smuzhiyun * this val could be reset by MAC-RST
352*4882a593Smuzhiyun */
353*4882a593Smuzhiyun ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF);
354*4882a593Smuzhiyun /* a 0->1 change will update the internal val of osc */
355*4882a593Smuzhiyun val &= ~ALX_MISC_INTNLOSC_OPEN;
356*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC, val);
357*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
358*4882a593Smuzhiyun /* hw will automatically dis OSC after cab. */
359*4882a593Smuzhiyun val2 = alx_read_mem32(hw, ALX_MSIC2);
360*4882a593Smuzhiyun val2 &= ~ALX_MSIC2_CALB_START;
361*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MSIC2, val2);
362*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MSIC2, val2 | ALX_MSIC2_CALB_START);
363*4882a593Smuzhiyun } else {
364*4882a593Smuzhiyun val &= ~ALX_MISC_INTNLOSC_OPEN;
365*4882a593Smuzhiyun /* disable isolate for rev A devices */
366*4882a593Smuzhiyun if (alx_is_rev_a(rev))
367*4882a593Smuzhiyun val &= ~ALX_MISC_ISO_EN;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
370*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC, val);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun udelay(20);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
alx_stop_mac(struct alx_hw * hw)376*4882a593Smuzhiyun static int alx_stop_mac(struct alx_hw *hw)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun u32 rxq, txq, val;
379*4882a593Smuzhiyun u16 i;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun rxq = alx_read_mem32(hw, ALX_RXQ0);
382*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RXQ0, rxq & ~ALX_RXQ0_EN);
383*4882a593Smuzhiyun txq = alx_read_mem32(hw, ALX_TXQ0);
384*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TXQ0, txq & ~ALX_TXQ0_EN);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun udelay(40);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun hw->rx_ctrl &= ~(ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
389*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
392*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MAC_STS);
393*4882a593Smuzhiyun if (!(val & ALX_MAC_STS_IDLE))
394*4882a593Smuzhiyun return 0;
395*4882a593Smuzhiyun udelay(10);
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return -ETIMEDOUT;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
alx_reset_mac(struct alx_hw * hw)401*4882a593Smuzhiyun int alx_reset_mac(struct alx_hw *hw)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun u32 val, pmctrl;
404*4882a593Smuzhiyun int i, ret;
405*4882a593Smuzhiyun u8 rev;
406*4882a593Smuzhiyun bool a_cr;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun pmctrl = 0;
409*4882a593Smuzhiyun rev = alx_hw_revision(hw);
410*4882a593Smuzhiyun a_cr = alx_is_rev_a(rev) && alx_hw_with_cr(hw);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /* disable all interrupts, RXQ/TXQ */
413*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MSIX_MASK, 0xFFFFFFFF);
414*4882a593Smuzhiyun alx_write_mem32(hw, ALX_IMR, 0);
415*4882a593Smuzhiyun alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun ret = alx_stop_mac(hw);
418*4882a593Smuzhiyun if (ret)
419*4882a593Smuzhiyun return ret;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun /* mac reset workaroud */
422*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RFD_PIDX, 1);
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /* dis l0s/l1 before mac reset */
425*4882a593Smuzhiyun if (a_cr) {
426*4882a593Smuzhiyun pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
427*4882a593Smuzhiyun if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
428*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PMCTRL,
429*4882a593Smuzhiyun pmctrl & ~(ALX_PMCTRL_L1_EN |
430*4882a593Smuzhiyun ALX_PMCTRL_L0S_EN));
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /* reset whole mac safely */
434*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MASTER);
435*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MASTER,
436*4882a593Smuzhiyun val | ALX_MASTER_DMA_MAC_RST | ALX_MASTER_OOB_DIS);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* make sure it's real idle */
439*4882a593Smuzhiyun udelay(10);
440*4882a593Smuzhiyun for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
441*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_RFD_PIDX);
442*4882a593Smuzhiyun if (val == 0)
443*4882a593Smuzhiyun break;
444*4882a593Smuzhiyun udelay(10);
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun for (; i < ALX_DMA_MAC_RST_TO; i++) {
447*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MASTER);
448*4882a593Smuzhiyun if ((val & ALX_MASTER_DMA_MAC_RST) == 0)
449*4882a593Smuzhiyun break;
450*4882a593Smuzhiyun udelay(10);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun if (i == ALX_DMA_MAC_RST_TO)
453*4882a593Smuzhiyun return -EIO;
454*4882a593Smuzhiyun udelay(10);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (a_cr) {
457*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MASTER, val | ALX_MASTER_PCLKSEL_SRDS);
458*4882a593Smuzhiyun /* restore l0s / l1 */
459*4882a593Smuzhiyun if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
460*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun alx_reset_osc(hw, rev);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun /* clear Internal OSC settings, switching OSC by hw itself,
466*4882a593Smuzhiyun * disable isolate for rev A devices
467*4882a593Smuzhiyun */
468*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MISC3);
469*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC3,
470*4882a593Smuzhiyun (val & ~ALX_MISC3_25M_BY_SW) |
471*4882a593Smuzhiyun ALX_MISC3_25M_NOTO_INTNL);
472*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MISC);
473*4882a593Smuzhiyun val &= ~ALX_MISC_INTNLOSC_OPEN;
474*4882a593Smuzhiyun if (alx_is_rev_a(rev))
475*4882a593Smuzhiyun val &= ~ALX_MISC_ISO_EN;
476*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MISC, val);
477*4882a593Smuzhiyun udelay(20);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* driver control speed/duplex, hash-alg */
480*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_SERDES);
483*4882a593Smuzhiyun alx_write_mem32(hw, ALX_SERDES,
484*4882a593Smuzhiyun val | ALX_SERDES_MACCLK_SLWDWN |
485*4882a593Smuzhiyun ALX_SERDES_PHYCLK_SLWDWN);
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
alx_reset_phy(struct alx_hw * hw)490*4882a593Smuzhiyun void alx_reset_phy(struct alx_hw *hw)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun int i;
493*4882a593Smuzhiyun u32 val;
494*4882a593Smuzhiyun u16 phy_val;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /* (DSP)reset PHY core */
497*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_PHY_CTRL);
498*4882a593Smuzhiyun val &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_IDDQ |
499*4882a593Smuzhiyun ALX_PHY_CTRL_GATE_25M | ALX_PHY_CTRL_POWER_DOWN |
500*4882a593Smuzhiyun ALX_PHY_CTRL_CLS);
501*4882a593Smuzhiyun val |= ALX_PHY_CTRL_RST_ANALOG;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun val |= (ALX_PHY_CTRL_HIB_PULSE | ALX_PHY_CTRL_HIB_EN);
504*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PHY_CTRL, val);
505*4882a593Smuzhiyun udelay(10);
506*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PHY_CTRL, val | ALX_PHY_CTRL_DSPRST_OUT);
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun for (i = 0; i < ALX_PHY_CTRL_DSPRST_TO; i++)
509*4882a593Smuzhiyun udelay(10);
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /* phy power saving & hib */
512*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_LEGCYPS, ALX_LEGCYPS_DEF);
513*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_SYSMODCTRL,
514*4882a593Smuzhiyun ALX_SYSMODCTRL_IECHOADJ_DEF);
515*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_VDRVBIAS,
516*4882a593Smuzhiyun ALX_VDRVBIAS_DEF);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /* EEE advertisement */
519*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_LPI_CTRL);
520*4882a593Smuzhiyun alx_write_mem32(hw, ALX_LPI_CTRL, val & ~ALX_LPI_CTRL_EN);
521*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_LOCAL_EEEADV, 0);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /* phy power saving */
524*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_TST10BTCFG, ALX_TST10BTCFG_DEF);
525*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_SRDSYSMOD, ALX_SRDSYSMOD_DEF);
526*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_TST100BTCFG, ALX_TST100BTCFG_DEF);
527*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_ANACTRL, ALX_ANACTRL_DEF);
528*4882a593Smuzhiyun alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
529*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
530*4882a593Smuzhiyun phy_val & ~ALX_GREENCFG2_GATE_DFSE_EN);
531*4882a593Smuzhiyun /* rtl8139c, 120m issue */
532*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_NLP78,
533*4882a593Smuzhiyun ALX_MIIEXT_NLP78_120M_DEF);
534*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_S3DIG10,
535*4882a593Smuzhiyun ALX_MIIEXT_S3DIG10_DEF);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (hw->lnk_patch) {
538*4882a593Smuzhiyun /* Turn off half amplitude */
539*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
540*4882a593Smuzhiyun &phy_val);
541*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
542*4882a593Smuzhiyun phy_val | ALX_CLDCTRL3_BP_CABLE1TH_DET_GT);
543*4882a593Smuzhiyun /* Turn off Green feature */
544*4882a593Smuzhiyun alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
545*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
546*4882a593Smuzhiyun phy_val | ALX_GREENCFG2_BP_GREEN);
547*4882a593Smuzhiyun /* Turn off half Bias */
548*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
549*4882a593Smuzhiyun &phy_val);
550*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
551*4882a593Smuzhiyun phy_val | ALX_CLDCTRL5_BP_VD_HLFBIAS);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /* set phy interrupt mask */
555*4882a593Smuzhiyun alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP | ALX_IER_LINK_DOWN);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun #define ALX_PCI_CMD (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
559*4882a593Smuzhiyun
alx_reset_pcie(struct alx_hw * hw)560*4882a593Smuzhiyun void alx_reset_pcie(struct alx_hw *hw)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun u8 rev = alx_hw_revision(hw);
563*4882a593Smuzhiyun u32 val;
564*4882a593Smuzhiyun u16 val16;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */
567*4882a593Smuzhiyun pci_read_config_word(hw->pdev, PCI_COMMAND, &val16);
568*4882a593Smuzhiyun if (!(val16 & ALX_PCI_CMD) || (val16 & PCI_COMMAND_INTX_DISABLE)) {
569*4882a593Smuzhiyun val16 = (val16 | ALX_PCI_CMD) & ~PCI_COMMAND_INTX_DISABLE;
570*4882a593Smuzhiyun pci_write_config_word(hw->pdev, PCI_COMMAND, val16);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun /* clear WoL setting/status */
574*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_WOL0);
575*4882a593Smuzhiyun alx_write_mem32(hw, ALX_WOL0, 0);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
578*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PDLL_TRNS1, val & ~ALX_PDLL_TRNS1_D3PLLOFF_EN);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun /* mask some pcie error bits */
581*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_UE_SVRT);
582*4882a593Smuzhiyun val &= ~(ALX_UE_SVRT_DLPROTERR | ALX_UE_SVRT_FCPROTERR);
583*4882a593Smuzhiyun alx_write_mem32(hw, ALX_UE_SVRT, val);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun /* wol 25M & pclk */
586*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MASTER);
587*4882a593Smuzhiyun if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) {
588*4882a593Smuzhiyun if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
589*4882a593Smuzhiyun (val & ALX_MASTER_PCLKSEL_SRDS) == 0)
590*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MASTER,
591*4882a593Smuzhiyun val | ALX_MASTER_PCLKSEL_SRDS |
592*4882a593Smuzhiyun ALX_MASTER_WAKEN_25M);
593*4882a593Smuzhiyun } else {
594*4882a593Smuzhiyun if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
595*4882a593Smuzhiyun (val & ALX_MASTER_PCLKSEL_SRDS) != 0)
596*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MASTER,
597*4882a593Smuzhiyun (val & ~ALX_MASTER_PCLKSEL_SRDS) |
598*4882a593Smuzhiyun ALX_MASTER_WAKEN_25M);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* ASPM setting */
602*4882a593Smuzhiyun alx_enable_aspm(hw, true, true);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun udelay(10);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
alx_start_mac(struct alx_hw * hw)607*4882a593Smuzhiyun void alx_start_mac(struct alx_hw *hw)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun u32 mac, txq, rxq;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun rxq = alx_read_mem32(hw, ALX_RXQ0);
612*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RXQ0, rxq | ALX_RXQ0_EN);
613*4882a593Smuzhiyun txq = alx_read_mem32(hw, ALX_TXQ0);
614*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TXQ0, txq | ALX_TXQ0_EN);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun mac = hw->rx_ctrl;
617*4882a593Smuzhiyun if (hw->duplex == DUPLEX_FULL)
618*4882a593Smuzhiyun mac |= ALX_MAC_CTRL_FULLD;
619*4882a593Smuzhiyun else
620*4882a593Smuzhiyun mac &= ~ALX_MAC_CTRL_FULLD;
621*4882a593Smuzhiyun ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
622*4882a593Smuzhiyun hw->link_speed == SPEED_1000 ? ALX_MAC_CTRL_SPEED_1000 :
623*4882a593Smuzhiyun ALX_MAC_CTRL_SPEED_10_100);
624*4882a593Smuzhiyun mac |= ALX_MAC_CTRL_TX_EN | ALX_MAC_CTRL_RX_EN;
625*4882a593Smuzhiyun hw->rx_ctrl = mac;
626*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MAC_CTRL, mac);
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
alx_cfg_mac_flowcontrol(struct alx_hw * hw,u8 fc)629*4882a593Smuzhiyun void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun if (fc & ALX_FC_RX)
632*4882a593Smuzhiyun hw->rx_ctrl |= ALX_MAC_CTRL_RXFC_EN;
633*4882a593Smuzhiyun else
634*4882a593Smuzhiyun hw->rx_ctrl &= ~ALX_MAC_CTRL_RXFC_EN;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun if (fc & ALX_FC_TX)
637*4882a593Smuzhiyun hw->rx_ctrl |= ALX_MAC_CTRL_TXFC_EN;
638*4882a593Smuzhiyun else
639*4882a593Smuzhiyun hw->rx_ctrl &= ~ALX_MAC_CTRL_TXFC_EN;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
alx_enable_aspm(struct alx_hw * hw,bool l0s_en,bool l1_en)644*4882a593Smuzhiyun void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun u32 pmctrl;
647*4882a593Smuzhiyun u8 rev = alx_hw_revision(hw);
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun ALX_SET_FIELD(pmctrl, ALX_PMCTRL_LCKDET_TIMER,
652*4882a593Smuzhiyun ALX_PMCTRL_LCKDET_TIMER_DEF);
653*4882a593Smuzhiyun pmctrl |= ALX_PMCTRL_RCVR_WT_1US |
654*4882a593Smuzhiyun ALX_PMCTRL_L1_CLKSW_EN |
655*4882a593Smuzhiyun ALX_PMCTRL_L1_SRDSRX_PWD;
656*4882a593Smuzhiyun ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1REQ_TO, ALX_PMCTRL_L1REG_TO_DEF);
657*4882a593Smuzhiyun ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1_TIMER, ALX_PMCTRL_L1_TIMER_16US);
658*4882a593Smuzhiyun pmctrl &= ~(ALX_PMCTRL_L1_SRDS_EN |
659*4882a593Smuzhiyun ALX_PMCTRL_L1_SRDSPLL_EN |
660*4882a593Smuzhiyun ALX_PMCTRL_L1_BUFSRX_EN |
661*4882a593Smuzhiyun ALX_PMCTRL_SADLY_EN |
662*4882a593Smuzhiyun ALX_PMCTRL_HOTRST_WTEN|
663*4882a593Smuzhiyun ALX_PMCTRL_L0S_EN |
664*4882a593Smuzhiyun ALX_PMCTRL_L1_EN |
665*4882a593Smuzhiyun ALX_PMCTRL_ASPM_FCEN |
666*4882a593Smuzhiyun ALX_PMCTRL_TXL1_AFTER_L0S |
667*4882a593Smuzhiyun ALX_PMCTRL_RXL1_AFTER_L0S);
668*4882a593Smuzhiyun if (alx_is_rev_a(rev) && alx_hw_with_cr(hw))
669*4882a593Smuzhiyun pmctrl |= ALX_PMCTRL_L1_SRDS_EN | ALX_PMCTRL_L1_SRDSPLL_EN;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun if (l0s_en)
672*4882a593Smuzhiyun pmctrl |= (ALX_PMCTRL_L0S_EN | ALX_PMCTRL_ASPM_FCEN);
673*4882a593Smuzhiyun if (l1_en)
674*4882a593Smuzhiyun pmctrl |= (ALX_PMCTRL_L1_EN | ALX_PMCTRL_ASPM_FCEN);
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun
ethadv_to_hw_cfg(struct alx_hw * hw,u32 ethadv_cfg)680*4882a593Smuzhiyun static u32 ethadv_to_hw_cfg(struct alx_hw *hw, u32 ethadv_cfg)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun u32 cfg = 0;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_Autoneg) {
685*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_AUTO;
686*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_10baseT_Half)
687*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_10;
688*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_10baseT_Full)
689*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
690*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_100baseT_Half)
691*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_100;
692*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_100baseT_Full)
693*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
694*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_1000baseT_Half)
695*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_1000;
696*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_1000baseT_Full)
697*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
698*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_Pause)
699*4882a593Smuzhiyun cfg |= ADVERTISE_PAUSE_CAP;
700*4882a593Smuzhiyun if (ethadv_cfg & ADVERTISED_Asym_Pause)
701*4882a593Smuzhiyun cfg |= ADVERTISE_PAUSE_ASYM;
702*4882a593Smuzhiyun } else {
703*4882a593Smuzhiyun switch (ethadv_cfg) {
704*4882a593Smuzhiyun case ADVERTISED_10baseT_Half:
705*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_10;
706*4882a593Smuzhiyun break;
707*4882a593Smuzhiyun case ADVERTISED_100baseT_Half:
708*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_100;
709*4882a593Smuzhiyun break;
710*4882a593Smuzhiyun case ADVERTISED_10baseT_Full:
711*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
712*4882a593Smuzhiyun break;
713*4882a593Smuzhiyun case ADVERTISED_100baseT_Full:
714*4882a593Smuzhiyun cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
715*4882a593Smuzhiyun break;
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun return cfg;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
alx_setup_speed_duplex(struct alx_hw * hw,u32 ethadv,u8 flowctrl)722*4882a593Smuzhiyun int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun u16 adv, giga, cr;
725*4882a593Smuzhiyun u32 val;
726*4882a593Smuzhiyun int err = 0;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0);
729*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_DRV);
730*4882a593Smuzhiyun ALX_SET_FIELD(val, ALX_DRV_PHY, 0);
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun if (ethadv & ADVERTISED_Autoneg) {
733*4882a593Smuzhiyun adv = ADVERTISE_CSMA;
734*4882a593Smuzhiyun adv |= ethtool_adv_to_mii_adv_t(ethadv);
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun if (flowctrl & ALX_FC_ANEG) {
737*4882a593Smuzhiyun if (flowctrl & ALX_FC_RX) {
738*4882a593Smuzhiyun adv |= ADVERTISED_Pause;
739*4882a593Smuzhiyun if (!(flowctrl & ALX_FC_TX))
740*4882a593Smuzhiyun adv |= ADVERTISED_Asym_Pause;
741*4882a593Smuzhiyun } else if (flowctrl & ALX_FC_TX) {
742*4882a593Smuzhiyun adv |= ADVERTISED_Asym_Pause;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun giga = 0;
746*4882a593Smuzhiyun if (alx_hw_giga(hw))
747*4882a593Smuzhiyun giga = ethtool_adv_to_mii_ctrl1000_t(ethadv);
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) ||
752*4882a593Smuzhiyun alx_write_phy_reg(hw, MII_CTRL1000, giga) ||
753*4882a593Smuzhiyun alx_write_phy_reg(hw, MII_BMCR, cr))
754*4882a593Smuzhiyun err = -EBUSY;
755*4882a593Smuzhiyun } else {
756*4882a593Smuzhiyun cr = BMCR_RESET;
757*4882a593Smuzhiyun if (ethadv == ADVERTISED_100baseT_Half ||
758*4882a593Smuzhiyun ethadv == ADVERTISED_100baseT_Full)
759*4882a593Smuzhiyun cr |= BMCR_SPEED100;
760*4882a593Smuzhiyun if (ethadv == ADVERTISED_10baseT_Full ||
761*4882a593Smuzhiyun ethadv == ADVERTISED_100baseT_Full)
762*4882a593Smuzhiyun cr |= BMCR_FULLDPLX;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun err = alx_write_phy_reg(hw, MII_BMCR, cr);
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun if (!err) {
768*4882a593Smuzhiyun alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED);
769*4882a593Smuzhiyun val |= ethadv_to_hw_cfg(hw, ethadv);
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun alx_write_mem32(hw, ALX_DRV, val);
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun return err;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun
alx_post_phy_link(struct alx_hw * hw)778*4882a593Smuzhiyun void alx_post_phy_link(struct alx_hw *hw)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun u16 phy_val, len, agc;
781*4882a593Smuzhiyun u8 revid = alx_hw_revision(hw);
782*4882a593Smuzhiyun bool adj_th = revid == ALX_REV_B0;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun if (revid != ALX_REV_B0 && !alx_is_rev_a(revid))
785*4882a593Smuzhiyun return;
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun /* 1000BT/AZ, wrong cable length */
788*4882a593Smuzhiyun if (hw->link_speed != SPEED_UNKNOWN) {
789*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL6,
790*4882a593Smuzhiyun &phy_val);
791*4882a593Smuzhiyun len = ALX_GET_FIELD(phy_val, ALX_CLDCTRL6_CAB_LEN);
792*4882a593Smuzhiyun alx_read_phy_dbg(hw, ALX_MIIDBG_AGC, &phy_val);
793*4882a593Smuzhiyun agc = ALX_GET_FIELD(phy_val, ALX_AGC_2_VGA);
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun if ((hw->link_speed == SPEED_1000 &&
796*4882a593Smuzhiyun (len > ALX_CLDCTRL6_CAB_LEN_SHORT1G ||
797*4882a593Smuzhiyun (len == 0 && agc > ALX_AGC_LONG1G_LIMT))) ||
798*4882a593Smuzhiyun (hw->link_speed == SPEED_100 &&
799*4882a593Smuzhiyun (len > ALX_CLDCTRL6_CAB_LEN_SHORT100M ||
800*4882a593Smuzhiyun (len == 0 && agc > ALX_AGC_LONG100M_LIMT)))) {
801*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
802*4882a593Smuzhiyun ALX_AZ_ANADECT_LONG);
803*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
804*4882a593Smuzhiyun &phy_val);
805*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
806*4882a593Smuzhiyun phy_val | ALX_AFE_10BT_100M_TH);
807*4882a593Smuzhiyun } else {
808*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
809*4882a593Smuzhiyun ALX_AZ_ANADECT_DEF);
810*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_ANEG,
811*4882a593Smuzhiyun ALX_MIIEXT_AFE, &phy_val);
812*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
813*4882a593Smuzhiyun phy_val & ~ALX_AFE_10BT_100M_TH);
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun /* threshold adjust */
817*4882a593Smuzhiyun if (adj_th && hw->lnk_patch) {
818*4882a593Smuzhiyun if (hw->link_speed == SPEED_100) {
819*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
820*4882a593Smuzhiyun ALX_MSE16DB_UP);
821*4882a593Smuzhiyun } else if (hw->link_speed == SPEED_1000) {
822*4882a593Smuzhiyun /*
823*4882a593Smuzhiyun * Giga link threshold, raise the tolerance of
824*4882a593Smuzhiyun * noise 50%
825*4882a593Smuzhiyun */
826*4882a593Smuzhiyun alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
827*4882a593Smuzhiyun &phy_val);
828*4882a593Smuzhiyun ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
829*4882a593Smuzhiyun ALX_MSE20DB_TH_HI);
830*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
831*4882a593Smuzhiyun phy_val);
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun } else {
835*4882a593Smuzhiyun alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
836*4882a593Smuzhiyun &phy_val);
837*4882a593Smuzhiyun alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
838*4882a593Smuzhiyun phy_val & ~ALX_AFE_10BT_100M_TH);
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun if (adj_th && hw->lnk_patch) {
841*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
842*4882a593Smuzhiyun ALX_MSE16DB_DOWN);
843*4882a593Smuzhiyun alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, &phy_val);
844*4882a593Smuzhiyun ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
845*4882a593Smuzhiyun ALX_MSE20DB_TH_DEF);
846*4882a593Smuzhiyun alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, phy_val);
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
alx_phy_configured(struct alx_hw * hw)851*4882a593Smuzhiyun bool alx_phy_configured(struct alx_hw *hw)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun u32 cfg, hw_cfg;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun cfg = ethadv_to_hw_cfg(hw, hw->adv_cfg);
856*4882a593Smuzhiyun cfg = ALX_GET_FIELD(cfg, ALX_DRV_PHY);
857*4882a593Smuzhiyun hw_cfg = alx_get_phy_config(hw);
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun if (hw_cfg == ALX_DRV_PHY_UNKNOWN)
860*4882a593Smuzhiyun return false;
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun return cfg == hw_cfg;
863*4882a593Smuzhiyun }
864*4882a593Smuzhiyun
alx_read_phy_link(struct alx_hw * hw)865*4882a593Smuzhiyun int alx_read_phy_link(struct alx_hw *hw)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun struct pci_dev *pdev = hw->pdev;
868*4882a593Smuzhiyun u16 bmsr, giga;
869*4882a593Smuzhiyun int err;
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
872*4882a593Smuzhiyun if (err)
873*4882a593Smuzhiyun return err;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
876*4882a593Smuzhiyun if (err)
877*4882a593Smuzhiyun return err;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun if (!(bmsr & BMSR_LSTATUS)) {
880*4882a593Smuzhiyun hw->link_speed = SPEED_UNKNOWN;
881*4882a593Smuzhiyun hw->duplex = DUPLEX_UNKNOWN;
882*4882a593Smuzhiyun return 0;
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun /* speed/duplex result is saved in PHY Specific Status Register */
886*4882a593Smuzhiyun err = alx_read_phy_reg(hw, ALX_MII_GIGA_PSSR, &giga);
887*4882a593Smuzhiyun if (err)
888*4882a593Smuzhiyun return err;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun if (!(giga & ALX_GIGA_PSSR_SPD_DPLX_RESOLVED))
891*4882a593Smuzhiyun goto wrong_speed;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun switch (giga & ALX_GIGA_PSSR_SPEED) {
894*4882a593Smuzhiyun case ALX_GIGA_PSSR_1000MBS:
895*4882a593Smuzhiyun hw->link_speed = SPEED_1000;
896*4882a593Smuzhiyun break;
897*4882a593Smuzhiyun case ALX_GIGA_PSSR_100MBS:
898*4882a593Smuzhiyun hw->link_speed = SPEED_100;
899*4882a593Smuzhiyun break;
900*4882a593Smuzhiyun case ALX_GIGA_PSSR_10MBS:
901*4882a593Smuzhiyun hw->link_speed = SPEED_10;
902*4882a593Smuzhiyun break;
903*4882a593Smuzhiyun default:
904*4882a593Smuzhiyun goto wrong_speed;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun hw->duplex = (giga & ALX_GIGA_PSSR_DPLX) ? DUPLEX_FULL : DUPLEX_HALF;
908*4882a593Smuzhiyun return 0;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun wrong_speed:
911*4882a593Smuzhiyun dev_err(&pdev->dev, "invalid PHY speed/duplex: 0x%x\n", giga);
912*4882a593Smuzhiyun return -EINVAL;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
alx_clear_phy_intr(struct alx_hw * hw)915*4882a593Smuzhiyun int alx_clear_phy_intr(struct alx_hw *hw)
916*4882a593Smuzhiyun {
917*4882a593Smuzhiyun u16 isr;
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun /* clear interrupt status by reading it */
920*4882a593Smuzhiyun return alx_read_phy_reg(hw, ALX_MII_ISR, &isr);
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun
alx_disable_rss(struct alx_hw * hw)923*4882a593Smuzhiyun void alx_disable_rss(struct alx_hw *hw)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun u32 ctrl = alx_read_mem32(hw, ALX_RXQ0);
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun ctrl &= ~ALX_RXQ0_RSS_HASH_EN;
928*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RXQ0, ctrl);
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
alx_configure_basic(struct alx_hw * hw)931*4882a593Smuzhiyun void alx_configure_basic(struct alx_hw *hw)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun u32 val, raw_mtu, max_payload;
934*4882a593Smuzhiyun u16 val16;
935*4882a593Smuzhiyun u8 chip_rev = alx_hw_revision(hw);
936*4882a593Smuzhiyun
937*4882a593Smuzhiyun alx_set_macaddr(hw, hw->mac_addr);
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun alx_write_mem32(hw, ALX_CLK_GATE, ALX_CLK_GATE_ALL);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun /* idle timeout to switch clk_125M */
942*4882a593Smuzhiyun if (chip_rev >= ALX_REV_B0)
943*4882a593Smuzhiyun alx_write_mem32(hw, ALX_IDLE_DECISN_TIMER,
944*4882a593Smuzhiyun ALX_IDLE_DECISN_TIMER_DEF);
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun alx_write_mem32(hw, ALX_SMB_TIMER, hw->smb_timer * 500UL);
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_MASTER);
949*4882a593Smuzhiyun val |= ALX_MASTER_IRQMOD2_EN |
950*4882a593Smuzhiyun ALX_MASTER_IRQMOD1_EN |
951*4882a593Smuzhiyun ALX_MASTER_SYSALVTIMER_EN;
952*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MASTER, val);
953*4882a593Smuzhiyun alx_write_mem32(hw, ALX_IRQ_MODU_TIMER,
954*4882a593Smuzhiyun (hw->imt >> 1) << ALX_IRQ_MODU_TIMER1_SHIFT);
955*4882a593Smuzhiyun /* intr re-trig timeout */
956*4882a593Smuzhiyun alx_write_mem32(hw, ALX_INT_RETRIG, ALX_INT_RETRIG_TO);
957*4882a593Smuzhiyun /* tpd threshold to trig int */
958*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd);
959*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt);
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun raw_mtu = ALX_RAW_MTU(hw->mtu);
962*4882a593Smuzhiyun alx_write_mem32(hw, ALX_MTU, raw_mtu);
963*4882a593Smuzhiyun if (raw_mtu > (ALX_MTU_JUMBO_TH + ETH_FCS_LEN + VLAN_HLEN))
964*4882a593Smuzhiyun hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun if (raw_mtu < ALX_TXQ1_JUMBO_TSO_TH)
967*4882a593Smuzhiyun val = (raw_mtu + 7) >> 3;
968*4882a593Smuzhiyun else
969*4882a593Smuzhiyun val = ALX_TXQ1_JUMBO_TSO_TH >> 3;
970*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN);
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun max_payload = pcie_get_readrq(hw->pdev) >> 8;
973*4882a593Smuzhiyun /*
974*4882a593Smuzhiyun * if BIOS had changed the default dma read max length,
975*4882a593Smuzhiyun * restore it to default value
976*4882a593Smuzhiyun */
977*4882a593Smuzhiyun if (max_payload < ALX_DEV_CTRL_MAXRRS_MIN)
978*4882a593Smuzhiyun pcie_set_readrq(hw->pdev, 128 << ALX_DEV_CTRL_MAXRRS_MIN);
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_TXQ0_TPD_BURSTPREF_SHIFT |
981*4882a593Smuzhiyun ALX_TXQ0_MODE_ENHANCE | ALX_TXQ0_LSO_8023_EN |
982*4882a593Smuzhiyun ALX_TXQ0_SUPT_IPOPT |
983*4882a593Smuzhiyun ALX_TXQ_TXF_BURST_PREF_DEF << ALX_TXQ0_TXF_BURST_PREF_SHIFT;
984*4882a593Smuzhiyun alx_write_mem32(hw, ALX_TXQ0, val);
985*4882a593Smuzhiyun val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q1_NUMPREF_SHIFT |
986*4882a593Smuzhiyun ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q2_NUMPREF_SHIFT |
987*4882a593Smuzhiyun ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q3_NUMPREF_SHIFT |
988*4882a593Smuzhiyun ALX_HQTPD_BURST_EN;
989*4882a593Smuzhiyun alx_write_mem32(hw, ALX_HQTPD, val);
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun /* rxq, flow control */
992*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_SRAM5);
993*4882a593Smuzhiyun val = ALX_GET_FIELD(val, ALX_SRAM_RXF_LEN) << 3;
994*4882a593Smuzhiyun if (val > ALX_SRAM_RXF_LEN_8K) {
995*4882a593Smuzhiyun val16 = ALX_MTU_STD_ALGN >> 3;
996*4882a593Smuzhiyun val = (val - ALX_RXQ2_RXF_FLOW_CTRL_RSVD) >> 3;
997*4882a593Smuzhiyun } else {
998*4882a593Smuzhiyun val16 = ALX_MTU_STD_ALGN >> 3;
999*4882a593Smuzhiyun val = (val - ALX_MTU_STD_ALGN) >> 3;
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RXQ2,
1002*4882a593Smuzhiyun val16 << ALX_RXQ2_RXF_XOFF_THRESH_SHIFT |
1003*4882a593Smuzhiyun val << ALX_RXQ2_RXF_XON_THRESH_SHIFT);
1004*4882a593Smuzhiyun val = ALX_RXQ0_NUM_RFD_PREF_DEF << ALX_RXQ0_NUM_RFD_PREF_SHIFT |
1005*4882a593Smuzhiyun ALX_RXQ0_RSS_MODE_DIS << ALX_RXQ0_RSS_MODE_SHIFT |
1006*4882a593Smuzhiyun ALX_RXQ0_IDT_TBL_SIZE_DEF << ALX_RXQ0_IDT_TBL_SIZE_SHIFT |
1007*4882a593Smuzhiyun ALX_RXQ0_RSS_HSTYP_ALL | ALX_RXQ0_RSS_HASH_EN |
1008*4882a593Smuzhiyun ALX_RXQ0_IPV6_PARSE_EN;
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun if (alx_hw_giga(hw))
1011*4882a593Smuzhiyun ALX_SET_FIELD(val, ALX_RXQ0_ASPM_THRESH,
1012*4882a593Smuzhiyun ALX_RXQ0_ASPM_THRESH_100M);
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun alx_write_mem32(hw, ALX_RXQ0, val);
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun val = alx_read_mem32(hw, ALX_DMA);
1017*4882a593Smuzhiyun val = ALX_DMA_RORDER_MODE_OUT << ALX_DMA_RORDER_MODE_SHIFT |
1018*4882a593Smuzhiyun ALX_DMA_RREQ_PRI_DATA |
1019*4882a593Smuzhiyun max_payload << ALX_DMA_RREQ_BLEN_SHIFT |
1020*4882a593Smuzhiyun ALX_DMA_WDLY_CNT_DEF << ALX_DMA_WDLY_CNT_SHIFT |
1021*4882a593Smuzhiyun ALX_DMA_RDLY_CNT_DEF << ALX_DMA_RDLY_CNT_SHIFT |
1022*4882a593Smuzhiyun (hw->dma_chnl - 1) << ALX_DMA_RCHNL_SEL_SHIFT;
1023*4882a593Smuzhiyun alx_write_mem32(hw, ALX_DMA, val);
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun /* default multi-tx-q weights */
1026*4882a593Smuzhiyun val = ALX_WRR_PRI_RESTRICT_NONE << ALX_WRR_PRI_SHIFT |
1027*4882a593Smuzhiyun 4 << ALX_WRR_PRI0_SHIFT |
1028*4882a593Smuzhiyun 4 << ALX_WRR_PRI1_SHIFT |
1029*4882a593Smuzhiyun 4 << ALX_WRR_PRI2_SHIFT |
1030*4882a593Smuzhiyun 4 << ALX_WRR_PRI3_SHIFT;
1031*4882a593Smuzhiyun alx_write_mem32(hw, ALX_WRR, val);
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
alx_mask_msix(struct alx_hw * hw,int index,bool mask)1034*4882a593Smuzhiyun void alx_mask_msix(struct alx_hw *hw, int index, bool mask)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun u32 reg, val;
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun reg = ALX_MSIX_ENTRY_BASE + index * PCI_MSIX_ENTRY_SIZE +
1039*4882a593Smuzhiyun PCI_MSIX_ENTRY_VECTOR_CTRL;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun val = mask ? PCI_MSIX_ENTRY_CTRL_MASKBIT : 0;
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun alx_write_mem32(hw, reg, val);
1044*4882a593Smuzhiyun alx_post_write(hw);
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun
alx_get_phy_info(struct alx_hw * hw)1048*4882a593Smuzhiyun bool alx_get_phy_info(struct alx_hw *hw)
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun u16 devs1, devs2;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun if (alx_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id[0]) ||
1053*4882a593Smuzhiyun alx_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id[1]))
1054*4882a593Smuzhiyun return false;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun /* since we haven't PMA/PMD status2 register, we can't
1057*4882a593Smuzhiyun * use mdio45_probe function for prtad and mmds.
1058*4882a593Smuzhiyun * use fixed MMD3 to get mmds.
1059*4882a593Smuzhiyun */
1060*4882a593Smuzhiyun if (alx_read_phy_ext(hw, 3, MDIO_DEVS1, &devs1) ||
1061*4882a593Smuzhiyun alx_read_phy_ext(hw, 3, MDIO_DEVS2, &devs2))
1062*4882a593Smuzhiyun return false;
1063*4882a593Smuzhiyun hw->mdio.mmds = devs1 | devs2 << 16;
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun return true;
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun
alx_update_hw_stats(struct alx_hw * hw)1068*4882a593Smuzhiyun void alx_update_hw_stats(struct alx_hw *hw)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun /* RX stats */
1071*4882a593Smuzhiyun hw->stats.rx_ok += alx_read_mem32(hw, ALX_MIB_RX_OK);
1072*4882a593Smuzhiyun hw->stats.rx_bcast += alx_read_mem32(hw, ALX_MIB_RX_BCAST);
1073*4882a593Smuzhiyun hw->stats.rx_mcast += alx_read_mem32(hw, ALX_MIB_RX_MCAST);
1074*4882a593Smuzhiyun hw->stats.rx_pause += alx_read_mem32(hw, ALX_MIB_RX_PAUSE);
1075*4882a593Smuzhiyun hw->stats.rx_ctrl += alx_read_mem32(hw, ALX_MIB_RX_CTRL);
1076*4882a593Smuzhiyun hw->stats.rx_fcs_err += alx_read_mem32(hw, ALX_MIB_RX_FCS_ERR);
1077*4882a593Smuzhiyun hw->stats.rx_len_err += alx_read_mem32(hw, ALX_MIB_RX_LEN_ERR);
1078*4882a593Smuzhiyun hw->stats.rx_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BYTE_CNT);
1079*4882a593Smuzhiyun hw->stats.rx_runt += alx_read_mem32(hw, ALX_MIB_RX_RUNT);
1080*4882a593Smuzhiyun hw->stats.rx_frag += alx_read_mem32(hw, ALX_MIB_RX_FRAG);
1081*4882a593Smuzhiyun hw->stats.rx_sz_64B += alx_read_mem32(hw, ALX_MIB_RX_SZ_64B);
1082*4882a593Smuzhiyun hw->stats.rx_sz_127B += alx_read_mem32(hw, ALX_MIB_RX_SZ_127B);
1083*4882a593Smuzhiyun hw->stats.rx_sz_255B += alx_read_mem32(hw, ALX_MIB_RX_SZ_255B);
1084*4882a593Smuzhiyun hw->stats.rx_sz_511B += alx_read_mem32(hw, ALX_MIB_RX_SZ_511B);
1085*4882a593Smuzhiyun hw->stats.rx_sz_1023B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1023B);
1086*4882a593Smuzhiyun hw->stats.rx_sz_1518B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1518B);
1087*4882a593Smuzhiyun hw->stats.rx_sz_max += alx_read_mem32(hw, ALX_MIB_RX_SZ_MAX);
1088*4882a593Smuzhiyun hw->stats.rx_ov_sz += alx_read_mem32(hw, ALX_MIB_RX_OV_SZ);
1089*4882a593Smuzhiyun hw->stats.rx_ov_rxf += alx_read_mem32(hw, ALX_MIB_RX_OV_RXF);
1090*4882a593Smuzhiyun hw->stats.rx_ov_rrd += alx_read_mem32(hw, ALX_MIB_RX_OV_RRD);
1091*4882a593Smuzhiyun hw->stats.rx_align_err += alx_read_mem32(hw, ALX_MIB_RX_ALIGN_ERR);
1092*4882a593Smuzhiyun hw->stats.rx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BCCNT);
1093*4882a593Smuzhiyun hw->stats.rx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_MCCNT);
1094*4882a593Smuzhiyun hw->stats.rx_err_addr += alx_read_mem32(hw, ALX_MIB_RX_ERRADDR);
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun /* TX stats */
1097*4882a593Smuzhiyun hw->stats.tx_ok += alx_read_mem32(hw, ALX_MIB_TX_OK);
1098*4882a593Smuzhiyun hw->stats.tx_bcast += alx_read_mem32(hw, ALX_MIB_TX_BCAST);
1099*4882a593Smuzhiyun hw->stats.tx_mcast += alx_read_mem32(hw, ALX_MIB_TX_MCAST);
1100*4882a593Smuzhiyun hw->stats.tx_pause += alx_read_mem32(hw, ALX_MIB_TX_PAUSE);
1101*4882a593Smuzhiyun hw->stats.tx_exc_defer += alx_read_mem32(hw, ALX_MIB_TX_EXC_DEFER);
1102*4882a593Smuzhiyun hw->stats.tx_ctrl += alx_read_mem32(hw, ALX_MIB_TX_CTRL);
1103*4882a593Smuzhiyun hw->stats.tx_defer += alx_read_mem32(hw, ALX_MIB_TX_DEFER);
1104*4882a593Smuzhiyun hw->stats.tx_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BYTE_CNT);
1105*4882a593Smuzhiyun hw->stats.tx_sz_64B += alx_read_mem32(hw, ALX_MIB_TX_SZ_64B);
1106*4882a593Smuzhiyun hw->stats.tx_sz_127B += alx_read_mem32(hw, ALX_MIB_TX_SZ_127B);
1107*4882a593Smuzhiyun hw->stats.tx_sz_255B += alx_read_mem32(hw, ALX_MIB_TX_SZ_255B);
1108*4882a593Smuzhiyun hw->stats.tx_sz_511B += alx_read_mem32(hw, ALX_MIB_TX_SZ_511B);
1109*4882a593Smuzhiyun hw->stats.tx_sz_1023B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1023B);
1110*4882a593Smuzhiyun hw->stats.tx_sz_1518B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1518B);
1111*4882a593Smuzhiyun hw->stats.tx_sz_max += alx_read_mem32(hw, ALX_MIB_TX_SZ_MAX);
1112*4882a593Smuzhiyun hw->stats.tx_single_col += alx_read_mem32(hw, ALX_MIB_TX_SINGLE_COL);
1113*4882a593Smuzhiyun hw->stats.tx_multi_col += alx_read_mem32(hw, ALX_MIB_TX_MULTI_COL);
1114*4882a593Smuzhiyun hw->stats.tx_late_col += alx_read_mem32(hw, ALX_MIB_TX_LATE_COL);
1115*4882a593Smuzhiyun hw->stats.tx_abort_col += alx_read_mem32(hw, ALX_MIB_TX_ABORT_COL);
1116*4882a593Smuzhiyun hw->stats.tx_underrun += alx_read_mem32(hw, ALX_MIB_TX_UNDERRUN);
1117*4882a593Smuzhiyun hw->stats.tx_trd_eop += alx_read_mem32(hw, ALX_MIB_TX_TRD_EOP);
1118*4882a593Smuzhiyun hw->stats.tx_len_err += alx_read_mem32(hw, ALX_MIB_TX_LEN_ERR);
1119*4882a593Smuzhiyun hw->stats.tx_trunc += alx_read_mem32(hw, ALX_MIB_TX_TRUNC);
1120*4882a593Smuzhiyun hw->stats.tx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BCCNT);
1121*4882a593Smuzhiyun hw->stats.tx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_MCCNT);
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun hw->stats.update += alx_read_mem32(hw, ALX_MIB_UPDATE);
1124*4882a593Smuzhiyun }
1125