xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intel/iwlwifi/iwl-io.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * This file is provided under a dual BSD/GPLv2 license.  When using or
4*4882a593Smuzhiyun  * redistributing this file, you may do so under either license.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * GPL LICENSE SUMMARY
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
9*4882a593Smuzhiyun  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
10*4882a593Smuzhiyun  * Copyright(C) 2018 - 2019 Intel Corporation
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify it
13*4882a593Smuzhiyun  * under the terms of version 2 of the GNU General Public License as
14*4882a593Smuzhiyun  * published by the Free Software Foundation.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but WITHOUT
17*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19*4882a593Smuzhiyun  * more details.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * The full GNU General Public License is included in this distribution in the
22*4882a593Smuzhiyun  * file called COPYING.
23*4882a593Smuzhiyun  *
24*4882a593Smuzhiyun  * Contact Information:
25*4882a593Smuzhiyun  *  Intel Linux Wireless <linuxwifi@intel.com>
26*4882a593Smuzhiyun  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * BSD LICENSE
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
31*4882a593Smuzhiyun  * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
32*4882a593Smuzhiyun  * Copyright (C) 2018 - 2019 Intel Corporation
33*4882a593Smuzhiyun  * All rights reserved.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  * Redistribution and use in source and binary forms, with or without
36*4882a593Smuzhiyun  * modification, are permitted provided that the following conditions
37*4882a593Smuzhiyun  * are met:
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  *  * Redistributions of source code must retain the above copyright
40*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer.
41*4882a593Smuzhiyun  *  * Redistributions in binary form must reproduce the above copyright
42*4882a593Smuzhiyun  *    notice, this list of conditions and the following disclaimer in
43*4882a593Smuzhiyun  *    the documentation and/or other materials provided with the
44*4882a593Smuzhiyun  *    distribution.
45*4882a593Smuzhiyun  *  * Neither the name Intel Corporation nor the names of its
46*4882a593Smuzhiyun  *    contributors may be used to endorse or promote products derived
47*4882a593Smuzhiyun  *    from this software without specific prior written permission.
48*4882a593Smuzhiyun  *
49*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50*4882a593Smuzhiyun  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51*4882a593Smuzhiyun  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52*4882a593Smuzhiyun  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53*4882a593Smuzhiyun  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54*4882a593Smuzhiyun  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55*4882a593Smuzhiyun  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56*4882a593Smuzhiyun  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57*4882a593Smuzhiyun  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58*4882a593Smuzhiyun  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59*4882a593Smuzhiyun  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  *****************************************************************************/
62*4882a593Smuzhiyun #include <linux/delay.h>
63*4882a593Smuzhiyun #include <linux/device.h>
64*4882a593Smuzhiyun #include <linux/export.h>
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #include "iwl-drv.h"
67*4882a593Smuzhiyun #include "iwl-io.h"
68*4882a593Smuzhiyun #include "iwl-csr.h"
69*4882a593Smuzhiyun #include "iwl-debug.h"
70*4882a593Smuzhiyun #include "iwl-prph.h"
71*4882a593Smuzhiyun #include "iwl-fh.h"
72*4882a593Smuzhiyun 
iwl_write8(struct iwl_trans * trans,u32 ofs,u8 val)73*4882a593Smuzhiyun void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val);
76*4882a593Smuzhiyun 	iwl_trans_write8(trans, ofs, val);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write8);
79*4882a593Smuzhiyun 
iwl_write32(struct iwl_trans * trans,u32 ofs,u32 val)80*4882a593Smuzhiyun void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val);
83*4882a593Smuzhiyun 	iwl_trans_write32(trans, ofs, val);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write32);
86*4882a593Smuzhiyun 
iwl_write64(struct iwl_trans * trans,u64 ofs,u64 val)87*4882a593Smuzhiyun void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val);
90*4882a593Smuzhiyun 	iwl_trans_write32(trans, ofs, lower_32_bits(val));
91*4882a593Smuzhiyun 	iwl_trans_write32(trans, ofs + 4, upper_32_bits(val));
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write64);
94*4882a593Smuzhiyun 
iwl_read32(struct iwl_trans * trans,u32 ofs)95*4882a593Smuzhiyun u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	u32 val = iwl_trans_read32(trans, ofs);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	trace_iwlwifi_dev_ioread32(trans->dev, ofs, val);
100*4882a593Smuzhiyun 	return val;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_read32);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #define IWL_POLL_INTERVAL 10	/* microseconds */
105*4882a593Smuzhiyun 
iwl_poll_bit(struct iwl_trans * trans,u32 addr,u32 bits,u32 mask,int timeout)106*4882a593Smuzhiyun int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
107*4882a593Smuzhiyun 		 u32 bits, u32 mask, int timeout)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	int t = 0;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	do {
112*4882a593Smuzhiyun 		if ((iwl_read32(trans, addr) & mask) == (bits & mask))
113*4882a593Smuzhiyun 			return t;
114*4882a593Smuzhiyun 		udelay(IWL_POLL_INTERVAL);
115*4882a593Smuzhiyun 		t += IWL_POLL_INTERVAL;
116*4882a593Smuzhiyun 	} while (t < timeout);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	return -ETIMEDOUT;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_poll_bit);
121*4882a593Smuzhiyun 
iwl_read_direct32(struct iwl_trans * trans,u32 reg)122*4882a593Smuzhiyun u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	u32 value = 0x5a5a5a5a;
125*4882a593Smuzhiyun 	unsigned long flags;
126*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
127*4882a593Smuzhiyun 		value = iwl_read32(trans, reg);
128*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	return value;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_read_direct32);
134*4882a593Smuzhiyun 
iwl_write_direct32(struct iwl_trans * trans,u32 reg,u32 value)135*4882a593Smuzhiyun void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	unsigned long flags;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
140*4882a593Smuzhiyun 		iwl_write32(trans, reg, value);
141*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write_direct32);
145*4882a593Smuzhiyun 
iwl_write_direct64(struct iwl_trans * trans,u64 reg,u64 value)146*4882a593Smuzhiyun void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	unsigned long flags;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
151*4882a593Smuzhiyun 		iwl_write64(trans, reg, value);
152*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write_direct64);
156*4882a593Smuzhiyun 
iwl_poll_direct_bit(struct iwl_trans * trans,u32 addr,u32 mask,int timeout)157*4882a593Smuzhiyun int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
158*4882a593Smuzhiyun 			int timeout)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	int t = 0;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	do {
163*4882a593Smuzhiyun 		if ((iwl_read_direct32(trans, addr) & mask) == mask)
164*4882a593Smuzhiyun 			return t;
165*4882a593Smuzhiyun 		udelay(IWL_POLL_INTERVAL);
166*4882a593Smuzhiyun 		t += IWL_POLL_INTERVAL;
167*4882a593Smuzhiyun 	} while (t < timeout);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return -ETIMEDOUT;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
172*4882a593Smuzhiyun 
iwl_read_prph_no_grab(struct iwl_trans * trans,u32 ofs)173*4882a593Smuzhiyun u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	u32 val = iwl_trans_read_prph(trans, ofs);
176*4882a593Smuzhiyun 	trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val);
177*4882a593Smuzhiyun 	return val;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab);
180*4882a593Smuzhiyun 
iwl_write_prph_no_grab(struct iwl_trans * trans,u32 ofs,u32 val)181*4882a593Smuzhiyun void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val);
184*4882a593Smuzhiyun 	iwl_trans_write_prph(trans, ofs, val);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab);
187*4882a593Smuzhiyun 
iwl_write_prph64_no_grab(struct iwl_trans * trans,u64 ofs,u64 val)188*4882a593Smuzhiyun void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val);
191*4882a593Smuzhiyun 	iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff);
192*4882a593Smuzhiyun 	iwl_write_prph_no_grab(trans, ofs + 4, val >> 32);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab);
195*4882a593Smuzhiyun 
iwl_read_prph(struct iwl_trans * trans,u32 ofs)196*4882a593Smuzhiyun u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	unsigned long flags;
199*4882a593Smuzhiyun 	u32 val = 0x5a5a5a5a;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
202*4882a593Smuzhiyun 		val = iwl_read_prph_no_grab(trans, ofs);
203*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 	return val;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_read_prph);
208*4882a593Smuzhiyun 
iwl_write_prph(struct iwl_trans * trans,u32 ofs,u32 val)209*4882a593Smuzhiyun void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	unsigned long flags;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
214*4882a593Smuzhiyun 		iwl_write_prph_no_grab(trans, ofs, val);
215*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_write_prph);
219*4882a593Smuzhiyun 
iwl_poll_prph_bit(struct iwl_trans * trans,u32 addr,u32 bits,u32 mask,int timeout)220*4882a593Smuzhiyun int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
221*4882a593Smuzhiyun 		      u32 bits, u32 mask, int timeout)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int t = 0;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	do {
226*4882a593Smuzhiyun 		if ((iwl_read_prph(trans, addr) & mask) == (bits & mask))
227*4882a593Smuzhiyun 			return t;
228*4882a593Smuzhiyun 		udelay(IWL_POLL_INTERVAL);
229*4882a593Smuzhiyun 		t += IWL_POLL_INTERVAL;
230*4882a593Smuzhiyun 	} while (t < timeout);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return -ETIMEDOUT;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
iwl_set_bits_prph(struct iwl_trans * trans,u32 ofs,u32 mask)235*4882a593Smuzhiyun void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	unsigned long flags;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
240*4882a593Smuzhiyun 		iwl_write_prph_no_grab(trans, ofs,
241*4882a593Smuzhiyun 				       iwl_read_prph_no_grab(trans, ofs) |
242*4882a593Smuzhiyun 				       mask);
243*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
247*4882a593Smuzhiyun 
iwl_set_bits_mask_prph(struct iwl_trans * trans,u32 ofs,u32 bits,u32 mask)248*4882a593Smuzhiyun void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
249*4882a593Smuzhiyun 			    u32 bits, u32 mask)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	unsigned long flags;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
254*4882a593Smuzhiyun 		iwl_write_prph_no_grab(trans, ofs,
255*4882a593Smuzhiyun 				       (iwl_read_prph_no_grab(trans, ofs) &
256*4882a593Smuzhiyun 					mask) | bits);
257*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
261*4882a593Smuzhiyun 
iwl_clear_bits_prph(struct iwl_trans * trans,u32 ofs,u32 mask)262*4882a593Smuzhiyun void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	unsigned long flags;
265*4882a593Smuzhiyun 	u32 val;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (iwl_trans_grab_nic_access(trans, &flags)) {
268*4882a593Smuzhiyun 		val = iwl_read_prph_no_grab(trans, ofs);
269*4882a593Smuzhiyun 		iwl_write_prph_no_grab(trans, ofs, (val & ~mask));
270*4882a593Smuzhiyun 		iwl_trans_release_nic_access(trans, &flags);
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
274*4882a593Smuzhiyun 
iwl_force_nmi(struct iwl_trans * trans)275*4882a593Smuzhiyun void iwl_force_nmi(struct iwl_trans *trans)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)
278*4882a593Smuzhiyun 		iwl_write_prph(trans, DEVICE_SET_NMI_REG,
279*4882a593Smuzhiyun 			       DEVICE_SET_NMI_VAL_DRV);
280*4882a593Smuzhiyun 	else if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
281*4882a593Smuzhiyun 		iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER,
282*4882a593Smuzhiyun 				UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER_MSK);
283*4882a593Smuzhiyun 	else
284*4882a593Smuzhiyun 		iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
285*4882a593Smuzhiyun 				    UREG_DOORBELL_TO_ISR6_NMI_BIT);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_force_nmi);
288*4882a593Smuzhiyun 
get_rfh_string(int cmd)289*4882a593Smuzhiyun static const char *get_rfh_string(int cmd)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun #define IWL_CMD(x) case x: return #x
292*4882a593Smuzhiyun #define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	int i;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) {
297*4882a593Smuzhiyun 		IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i);
298*4882a593Smuzhiyun 		IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i);
299*4882a593Smuzhiyun 		IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i);
300*4882a593Smuzhiyun 		IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i);
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	switch (cmd) {
304*4882a593Smuzhiyun 	IWL_CMD(RFH_RXF_DMA_CFG);
305*4882a593Smuzhiyun 	IWL_CMD(RFH_GEN_CFG);
306*4882a593Smuzhiyun 	IWL_CMD(RFH_GEN_STATUS);
307*4882a593Smuzhiyun 	IWL_CMD(FH_TSSR_TX_STATUS_REG);
308*4882a593Smuzhiyun 	IWL_CMD(FH_TSSR_TX_ERROR_REG);
309*4882a593Smuzhiyun 	default:
310*4882a593Smuzhiyun 		return "UNKNOWN";
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun #undef IWL_CMD_MQ
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun struct reg {
316*4882a593Smuzhiyun 	u32 addr;
317*4882a593Smuzhiyun 	bool is64;
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun 
iwl_dump_rfh(struct iwl_trans * trans,char ** buf)320*4882a593Smuzhiyun static int iwl_dump_rfh(struct iwl_trans *trans, char **buf)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	int i, q;
323*4882a593Smuzhiyun 	int num_q = trans->num_rx_queues;
324*4882a593Smuzhiyun 	static const u32 rfh_tbl[] = {
325*4882a593Smuzhiyun 		RFH_RXF_DMA_CFG,
326*4882a593Smuzhiyun 		RFH_GEN_CFG,
327*4882a593Smuzhiyun 		RFH_GEN_STATUS,
328*4882a593Smuzhiyun 		FH_TSSR_TX_STATUS_REG,
329*4882a593Smuzhiyun 		FH_TSSR_TX_ERROR_REG,
330*4882a593Smuzhiyun 	};
331*4882a593Smuzhiyun 	static const struct reg rfh_mq_tbl[] = {
332*4882a593Smuzhiyun 		{ RFH_Q0_FRBDCB_BA_LSB, true },
333*4882a593Smuzhiyun 		{ RFH_Q0_FRBDCB_WIDX, false },
334*4882a593Smuzhiyun 		{ RFH_Q0_FRBDCB_RIDX, false },
335*4882a593Smuzhiyun 		{ RFH_Q0_URBD_STTS_WPTR_LSB, true },
336*4882a593Smuzhiyun 	};
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun #ifdef CONFIG_IWLWIFI_DEBUGFS
339*4882a593Smuzhiyun 	if (buf) {
340*4882a593Smuzhiyun 		int pos = 0;
341*4882a593Smuzhiyun 		/*
342*4882a593Smuzhiyun 		 * Register (up to 34 for name + 8 blank/q for MQ): 40 chars
343*4882a593Smuzhiyun 		 * Colon + space: 2 characters
344*4882a593Smuzhiyun 		 * 0X%08x: 10 characters
345*4882a593Smuzhiyun 		 * New line: 1 character
346*4882a593Smuzhiyun 		 * Total of 53 characters
347*4882a593Smuzhiyun 		 */
348*4882a593Smuzhiyun 		size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 +
349*4882a593Smuzhiyun 			       ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 		*buf = kmalloc(bufsz, GFP_KERNEL);
352*4882a593Smuzhiyun 		if (!*buf)
353*4882a593Smuzhiyun 			return -ENOMEM;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 		pos += scnprintf(*buf + pos, bufsz - pos,
356*4882a593Smuzhiyun 				"RFH register values:\n");
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++)
359*4882a593Smuzhiyun 			pos += scnprintf(*buf + pos, bufsz - pos,
360*4882a593Smuzhiyun 				"%40s: 0X%08x\n",
361*4882a593Smuzhiyun 				get_rfh_string(rfh_tbl[i]),
362*4882a593Smuzhiyun 				iwl_read_prph(trans, rfh_tbl[i]));
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++)
365*4882a593Smuzhiyun 			for (q = 0; q < num_q; q++) {
366*4882a593Smuzhiyun 				u32 addr = rfh_mq_tbl[i].addr;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 				addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4);
369*4882a593Smuzhiyun 				pos += scnprintf(*buf + pos, bufsz - pos,
370*4882a593Smuzhiyun 					"%34s(q %2d): 0X%08x\n",
371*4882a593Smuzhiyun 					get_rfh_string(addr), q,
372*4882a593Smuzhiyun 					iwl_read_prph(trans, addr));
373*4882a593Smuzhiyun 			}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 		return pos;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun #endif
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	IWL_ERR(trans, "RFH register values:\n");
380*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++)
381*4882a593Smuzhiyun 		IWL_ERR(trans, "  %34s: 0X%08x\n",
382*4882a593Smuzhiyun 			get_rfh_string(rfh_tbl[i]),
383*4882a593Smuzhiyun 			iwl_read_prph(trans, rfh_tbl[i]));
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++)
386*4882a593Smuzhiyun 		for (q = 0; q < num_q; q++) {
387*4882a593Smuzhiyun 			u32 addr = rfh_mq_tbl[i].addr;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 			addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4);
390*4882a593Smuzhiyun 			IWL_ERR(trans, "  %34s(q %d): 0X%08x\n",
391*4882a593Smuzhiyun 				get_rfh_string(addr), q,
392*4882a593Smuzhiyun 				iwl_read_prph(trans, addr));
393*4882a593Smuzhiyun 		}
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	return 0;
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun 
get_fh_string(int cmd)398*4882a593Smuzhiyun static const char *get_fh_string(int cmd)
399*4882a593Smuzhiyun {
400*4882a593Smuzhiyun 	switch (cmd) {
401*4882a593Smuzhiyun 	IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
402*4882a593Smuzhiyun 	IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
403*4882a593Smuzhiyun 	IWL_CMD(FH_RSCSR_CHNL0_WPTR);
404*4882a593Smuzhiyun 	IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
405*4882a593Smuzhiyun 	IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
406*4882a593Smuzhiyun 	IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
407*4882a593Smuzhiyun 	IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
408*4882a593Smuzhiyun 	IWL_CMD(FH_TSSR_TX_STATUS_REG);
409*4882a593Smuzhiyun 	IWL_CMD(FH_TSSR_TX_ERROR_REG);
410*4882a593Smuzhiyun 	default:
411*4882a593Smuzhiyun 		return "UNKNOWN";
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun #undef IWL_CMD
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
iwl_dump_fh(struct iwl_trans * trans,char ** buf)416*4882a593Smuzhiyun int iwl_dump_fh(struct iwl_trans *trans, char **buf)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	int i;
419*4882a593Smuzhiyun 	static const u32 fh_tbl[] = {
420*4882a593Smuzhiyun 		FH_RSCSR_CHNL0_STTS_WPTR_REG,
421*4882a593Smuzhiyun 		FH_RSCSR_CHNL0_RBDCB_BASE_REG,
422*4882a593Smuzhiyun 		FH_RSCSR_CHNL0_WPTR,
423*4882a593Smuzhiyun 		FH_MEM_RCSR_CHNL0_CONFIG_REG,
424*4882a593Smuzhiyun 		FH_MEM_RSSR_SHARED_CTRL_REG,
425*4882a593Smuzhiyun 		FH_MEM_RSSR_RX_STATUS_REG,
426*4882a593Smuzhiyun 		FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
427*4882a593Smuzhiyun 		FH_TSSR_TX_STATUS_REG,
428*4882a593Smuzhiyun 		FH_TSSR_TX_ERROR_REG
429*4882a593Smuzhiyun 	};
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (trans->trans_cfg->mq_rx_supported)
432*4882a593Smuzhiyun 		return iwl_dump_rfh(trans, buf);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun #ifdef CONFIG_IWLWIFI_DEBUGFS
435*4882a593Smuzhiyun 	if (buf) {
436*4882a593Smuzhiyun 		int pos = 0;
437*4882a593Smuzhiyun 		size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 		*buf = kmalloc(bufsz, GFP_KERNEL);
440*4882a593Smuzhiyun 		if (!*buf)
441*4882a593Smuzhiyun 			return -ENOMEM;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 		pos += scnprintf(*buf + pos, bufsz - pos,
444*4882a593Smuzhiyun 				"FH register values:\n");
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
447*4882a593Smuzhiyun 			pos += scnprintf(*buf + pos, bufsz - pos,
448*4882a593Smuzhiyun 				"  %34s: 0X%08x\n",
449*4882a593Smuzhiyun 				get_fh_string(fh_tbl[i]),
450*4882a593Smuzhiyun 				iwl_read_direct32(trans, fh_tbl[i]));
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 		return pos;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun #endif
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	IWL_ERR(trans, "FH register values:\n");
457*4882a593Smuzhiyun 	for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++)
458*4882a593Smuzhiyun 		IWL_ERR(trans, "  %34s: 0X%08x\n",
459*4882a593Smuzhiyun 			get_fh_string(fh_tbl[i]),
460*4882a593Smuzhiyun 			iwl_read_direct32(trans, fh_tbl[i]));
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
iwl_finish_nic_init(struct iwl_trans * trans,const struct iwl_cfg_trans_params * cfg_trans)465*4882a593Smuzhiyun int iwl_finish_nic_init(struct iwl_trans *trans,
466*4882a593Smuzhiyun 			const struct iwl_cfg_trans_params *cfg_trans)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	int err;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	if (cfg_trans->bisr_workaround) {
471*4882a593Smuzhiyun 		/* ensure the TOP FSM isn't still in previous reset */
472*4882a593Smuzhiyun 		mdelay(2);
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	/*
476*4882a593Smuzhiyun 	 * Set "initialization complete" bit to move adapter from
477*4882a593Smuzhiyun 	 * D0U* --> D0A* (powered-up active) state.
478*4882a593Smuzhiyun 	 */
479*4882a593Smuzhiyun 	iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (cfg_trans->device_family == IWL_DEVICE_FAMILY_8000)
482*4882a593Smuzhiyun 		udelay(2);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	/*
485*4882a593Smuzhiyun 	 * Wait for clock stabilization; once stabilized, access to
486*4882a593Smuzhiyun 	 * device-internal resources is supported, e.g. iwl_write_prph()
487*4882a593Smuzhiyun 	 * and accesses to uCode SRAM.
488*4882a593Smuzhiyun 	 */
489*4882a593Smuzhiyun 	err = iwl_poll_bit(trans, CSR_GP_CNTRL,
490*4882a593Smuzhiyun 			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
491*4882a593Smuzhiyun 			   CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
492*4882a593Smuzhiyun 			   25000);
493*4882a593Smuzhiyun 	if (err < 0)
494*4882a593Smuzhiyun 		IWL_DEBUG_INFO(trans, "Failed to wake NIC\n");
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (cfg_trans->bisr_workaround) {
497*4882a593Smuzhiyun 		/* ensure BISR shift has finished */
498*4882a593Smuzhiyun 		udelay(200);
499*4882a593Smuzhiyun 	}
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	return err < 0 ? err : 0;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun IWL_EXPORT_SYMBOL(iwl_finish_nic_init);
504