if_iwm.c revision 1.29.2.4 1 1.29.2.4 skrll /* $NetBSD: if_iwm.c,v 1.29.2.4 2015/09/22 12:05:59 skrll Exp $ */
2 1.29.2.3 skrll /* OpenBSD: if_iwm.c,v 1.41 2015/05/22 06:50:54 kettenis Exp */
3 1.29.2.2 skrll
4 1.29.2.2 skrll /*
5 1.29.2.2 skrll * Copyright (c) 2014 genua mbh <info (at) genua.de>
6 1.29.2.2 skrll * Copyright (c) 2014 Fixup Software Ltd.
7 1.29.2.2 skrll *
8 1.29.2.2 skrll * Permission to use, copy, modify, and distribute this software for any
9 1.29.2.2 skrll * purpose with or without fee is hereby granted, provided that the above
10 1.29.2.2 skrll * copyright notice and this permission notice appear in all copies.
11 1.29.2.2 skrll *
12 1.29.2.2 skrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 1.29.2.2 skrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 1.29.2.2 skrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 1.29.2.2 skrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 1.29.2.2 skrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 1.29.2.2 skrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 1.29.2.2 skrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 1.29.2.2 skrll */
20 1.29.2.2 skrll
21 1.29.2.2 skrll /*-
22 1.29.2.2 skrll * Based on BSD-licensed source modules in the Linux iwlwifi driver,
23 1.29.2.2 skrll * which were used as the reference documentation for this implementation.
24 1.29.2.2 skrll *
25 1.29.2.2 skrll * Driver version we are currently based off of is
26 1.29.2.2 skrll * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
27 1.29.2.2 skrll *
28 1.29.2.2 skrll ***********************************************************************
29 1.29.2.2 skrll *
30 1.29.2.2 skrll * This file is provided under a dual BSD/GPLv2 license. When using or
31 1.29.2.2 skrll * redistributing this file, you may do so under either license.
32 1.29.2.2 skrll *
33 1.29.2.2 skrll * GPL LICENSE SUMMARY
34 1.29.2.2 skrll *
35 1.29.2.2 skrll * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
36 1.29.2.2 skrll *
37 1.29.2.2 skrll * This program is free software; you can redistribute it and/or modify
38 1.29.2.2 skrll * it under the terms of version 2 of the GNU General Public License as
39 1.29.2.2 skrll * published by the Free Software Foundation.
40 1.29.2.2 skrll *
41 1.29.2.2 skrll * This program is distributed in the hope that it will be useful, but
42 1.29.2.2 skrll * WITHOUT ANY WARRANTY; without even the implied warranty of
43 1.29.2.2 skrll * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44 1.29.2.2 skrll * General Public License for more details.
45 1.29.2.2 skrll *
46 1.29.2.2 skrll * You should have received a copy of the GNU General Public License
47 1.29.2.2 skrll * along with this program; if not, write to the Free Software
48 1.29.2.2 skrll * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
49 1.29.2.2 skrll * USA
50 1.29.2.2 skrll *
51 1.29.2.2 skrll * The full GNU General Public License is included in this distribution
52 1.29.2.2 skrll * in the file called COPYING.
53 1.29.2.2 skrll *
54 1.29.2.2 skrll * Contact Information:
55 1.29.2.2 skrll * Intel Linux Wireless <ilw (at) linux.intel.com>
56 1.29.2.2 skrll * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
57 1.29.2.2 skrll *
58 1.29.2.2 skrll *
59 1.29.2.2 skrll * BSD LICENSE
60 1.29.2.2 skrll *
61 1.29.2.2 skrll * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
62 1.29.2.2 skrll * All rights reserved.
63 1.29.2.2 skrll *
64 1.29.2.2 skrll * Redistribution and use in source and binary forms, with or without
65 1.29.2.2 skrll * modification, are permitted provided that the following conditions
66 1.29.2.2 skrll * are met:
67 1.29.2.2 skrll *
68 1.29.2.2 skrll * * Redistributions of source code must retain the above copyright
69 1.29.2.2 skrll * notice, this list of conditions and the following disclaimer.
70 1.29.2.2 skrll * * Redistributions in binary form must reproduce the above copyright
71 1.29.2.2 skrll * notice, this list of conditions and the following disclaimer in
72 1.29.2.2 skrll * the documentation and/or other materials provided with the
73 1.29.2.2 skrll * distribution.
74 1.29.2.2 skrll * * Neither the name Intel Corporation nor the names of its
75 1.29.2.2 skrll * contributors may be used to endorse or promote products derived
76 1.29.2.2 skrll * from this software without specific prior written permission.
77 1.29.2.2 skrll *
78 1.29.2.2 skrll * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
79 1.29.2.2 skrll * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
80 1.29.2.2 skrll * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
81 1.29.2.2 skrll * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
82 1.29.2.2 skrll * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
83 1.29.2.2 skrll * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
84 1.29.2.2 skrll * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
85 1.29.2.2 skrll * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
86 1.29.2.2 skrll * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
87 1.29.2.2 skrll * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
88 1.29.2.2 skrll * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
89 1.29.2.2 skrll */
90 1.29.2.2 skrll
91 1.29.2.2 skrll /*-
92 1.29.2.2 skrll * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini (at) free.fr>
93 1.29.2.2 skrll *
94 1.29.2.2 skrll * Permission to use, copy, modify, and distribute this software for any
95 1.29.2.2 skrll * purpose with or without fee is hereby granted, provided that the above
96 1.29.2.2 skrll * copyright notice and this permission notice appear in all copies.
97 1.29.2.2 skrll *
98 1.29.2.2 skrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
99 1.29.2.2 skrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
100 1.29.2.2 skrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
101 1.29.2.2 skrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
102 1.29.2.2 skrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
103 1.29.2.2 skrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
104 1.29.2.2 skrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
105 1.29.2.2 skrll */
106 1.29.2.2 skrll
107 1.29.2.2 skrll #include <sys/cdefs.h>
108 1.29.2.4 skrll __KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.29.2.4 2015/09/22 12:05:59 skrll Exp $");
109 1.29.2.2 skrll
110 1.29.2.2 skrll #include <sys/param.h>
111 1.29.2.2 skrll #include <sys/conf.h>
112 1.29.2.2 skrll #include <sys/kernel.h>
113 1.29.2.2 skrll #include <sys/kmem.h>
114 1.29.2.2 skrll #include <sys/mbuf.h>
115 1.29.2.2 skrll #include <sys/mutex.h>
116 1.29.2.2 skrll #include <sys/proc.h>
117 1.29.2.2 skrll #include <sys/socket.h>
118 1.29.2.2 skrll #include <sys/sockio.h>
119 1.29.2.3 skrll #include <sys/sysctl.h>
120 1.29.2.2 skrll #include <sys/systm.h>
121 1.29.2.2 skrll
122 1.29.2.2 skrll #include <sys/cpu.h>
123 1.29.2.2 skrll #include <sys/bus.h>
124 1.29.2.2 skrll #include <sys/workqueue.h>
125 1.29.2.2 skrll #include <machine/endian.h>
126 1.29.2.2 skrll #include <machine/intr.h>
127 1.29.2.2 skrll
128 1.29.2.2 skrll #include <dev/pci/pcireg.h>
129 1.29.2.2 skrll #include <dev/pci/pcivar.h>
130 1.29.2.2 skrll #include <dev/pci/pcidevs.h>
131 1.29.2.2 skrll #include <dev/firmload.h>
132 1.29.2.2 skrll
133 1.29.2.2 skrll #include <net/bpf.h>
134 1.29.2.2 skrll #include <net/if.h>
135 1.29.2.2 skrll #include <net/if_arp.h>
136 1.29.2.2 skrll #include <net/if_dl.h>
137 1.29.2.2 skrll #include <net/if_media.h>
138 1.29.2.2 skrll #include <net/if_types.h>
139 1.29.2.2 skrll #include <net/if_ether.h>
140 1.29.2.2 skrll
141 1.29.2.2 skrll #include <netinet/in.h>
142 1.29.2.2 skrll #include <netinet/in_systm.h>
143 1.29.2.2 skrll #include <netinet/ip.h>
144 1.29.2.2 skrll
145 1.29.2.2 skrll #include <net80211/ieee80211_var.h>
146 1.29.2.2 skrll #include <net80211/ieee80211_amrr.h>
147 1.29.2.2 skrll #include <net80211/ieee80211_radiotap.h>
148 1.29.2.2 skrll
149 1.29.2.2 skrll #define DEVNAME(_s) device_xname((_s)->sc_dev)
150 1.29.2.2 skrll #define IC2IFP(_ic_) ((_ic_)->ic_ifp)
151 1.29.2.2 skrll
152 1.29.2.2 skrll #define le16_to_cpup(_a_) (le16toh(*(const uint16_t *)(_a_)))
153 1.29.2.2 skrll #define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_)))
154 1.29.2.2 skrll
155 1.29.2.2 skrll #ifdef IWM_DEBUG
156 1.29.2.2 skrll #define DPRINTF(x) do { if (iwm_debug > 0) printf x; } while (0)
157 1.29.2.2 skrll #define DPRINTFN(n, x) do { if (iwm_debug >= (n)) printf x; } while (0)
158 1.29.2.3 skrll int iwm_debug = 0;
159 1.29.2.2 skrll #else
160 1.29.2.2 skrll #define DPRINTF(x) do { ; } while (0)
161 1.29.2.2 skrll #define DPRINTFN(n, x) do { ; } while (0)
162 1.29.2.2 skrll #endif
163 1.29.2.2 skrll
164 1.29.2.2 skrll #include <dev/pci/if_iwmreg.h>
165 1.29.2.2 skrll #include <dev/pci/if_iwmvar.h>
166 1.29.2.2 skrll
167 1.29.2.2 skrll static const uint8_t iwm_nvm_channels[] = {
168 1.29.2.2 skrll /* 2.4 GHz */
169 1.29.2.2 skrll 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
170 1.29.2.2 skrll /* 5 GHz */
171 1.29.2.2 skrll 36, 40, 44 , 48, 52, 56, 60, 64,
172 1.29.2.2 skrll 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
173 1.29.2.2 skrll 149, 153, 157, 161, 165
174 1.29.2.2 skrll };
175 1.29.2.2 skrll #define IWM_NUM_2GHZ_CHANNELS 14
176 1.29.2.2 skrll
177 1.29.2.2 skrll static const struct iwm_rate {
178 1.29.2.2 skrll uint8_t rate;
179 1.29.2.2 skrll uint8_t plcp;
180 1.29.2.2 skrll } iwm_rates[] = {
181 1.29.2.2 skrll { 2, IWM_RATE_1M_PLCP },
182 1.29.2.2 skrll { 4, IWM_RATE_2M_PLCP },
183 1.29.2.2 skrll { 11, IWM_RATE_5M_PLCP },
184 1.29.2.2 skrll { 22, IWM_RATE_11M_PLCP },
185 1.29.2.2 skrll { 12, IWM_RATE_6M_PLCP },
186 1.29.2.2 skrll { 18, IWM_RATE_9M_PLCP },
187 1.29.2.2 skrll { 24, IWM_RATE_12M_PLCP },
188 1.29.2.2 skrll { 36, IWM_RATE_18M_PLCP },
189 1.29.2.2 skrll { 48, IWM_RATE_24M_PLCP },
190 1.29.2.2 skrll { 72, IWM_RATE_36M_PLCP },
191 1.29.2.2 skrll { 96, IWM_RATE_48M_PLCP },
192 1.29.2.2 skrll { 108, IWM_RATE_54M_PLCP },
193 1.29.2.2 skrll };
194 1.29.2.2 skrll #define IWM_RIDX_CCK 0
195 1.29.2.2 skrll #define IWM_RIDX_OFDM 4
196 1.29.2.2 skrll #define IWM_RIDX_MAX (__arraycount(iwm_rates)-1)
197 1.29.2.2 skrll #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
198 1.29.2.2 skrll #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
199 1.29.2.2 skrll
200 1.29.2.2 skrll struct iwm_newstate_state {
201 1.29.2.2 skrll struct work ns_wk;
202 1.29.2.2 skrll enum ieee80211_state ns_nstate;
203 1.29.2.2 skrll int ns_arg;
204 1.29.2.2 skrll int ns_generation;
205 1.29.2.2 skrll };
206 1.29.2.2 skrll
207 1.29.2.2 skrll static int iwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t);
208 1.29.2.2 skrll static int iwm_firmware_store_section(struct iwm_softc *,
209 1.29.2.2 skrll enum iwm_ucode_type, uint8_t *, size_t);
210 1.29.2.2 skrll static int iwm_set_default_calib(struct iwm_softc *, const void *);
211 1.29.2.2 skrll static int iwm_read_firmware(struct iwm_softc *);
212 1.29.2.2 skrll static uint32_t iwm_read_prph(struct iwm_softc *, uint32_t);
213 1.29.2.2 skrll static void iwm_write_prph(struct iwm_softc *, uint32_t, uint32_t);
214 1.29.2.2 skrll #ifdef IWM_DEBUG
215 1.29.2.2 skrll static int iwm_read_mem(struct iwm_softc *, uint32_t, void *, int);
216 1.29.2.2 skrll #endif
217 1.29.2.2 skrll static int iwm_write_mem(struct iwm_softc *, uint32_t, const void *, int);
218 1.29.2.2 skrll static int iwm_write_mem32(struct iwm_softc *, uint32_t, uint32_t);
219 1.29.2.2 skrll static int iwm_poll_bit(struct iwm_softc *, int, uint32_t, uint32_t, int);
220 1.29.2.2 skrll static int iwm_nic_lock(struct iwm_softc *);
221 1.29.2.2 skrll static void iwm_nic_unlock(struct iwm_softc *);
222 1.29.2.2 skrll static void iwm_set_bits_mask_prph(struct iwm_softc *, uint32_t, uint32_t,
223 1.29.2.2 skrll uint32_t);
224 1.29.2.2 skrll static void iwm_set_bits_prph(struct iwm_softc *, uint32_t, uint32_t);
225 1.29.2.2 skrll static void iwm_clear_bits_prph(struct iwm_softc *, uint32_t, uint32_t);
226 1.29.2.2 skrll static int iwm_dma_contig_alloc(bus_dma_tag_t, struct iwm_dma_info *,
227 1.29.2.2 skrll bus_size_t, bus_size_t);
228 1.29.2.2 skrll static void iwm_dma_contig_free(struct iwm_dma_info *);
229 1.29.2.2 skrll static int iwm_alloc_fwmem(struct iwm_softc *);
230 1.29.2.2 skrll static void iwm_free_fwmem(struct iwm_softc *);
231 1.29.2.2 skrll static int iwm_alloc_sched(struct iwm_softc *);
232 1.29.2.2 skrll static void iwm_free_sched(struct iwm_softc *);
233 1.29.2.2 skrll static int iwm_alloc_kw(struct iwm_softc *);
234 1.29.2.2 skrll static void iwm_free_kw(struct iwm_softc *);
235 1.29.2.2 skrll static int iwm_alloc_ict(struct iwm_softc *);
236 1.29.2.2 skrll static void iwm_free_ict(struct iwm_softc *);
237 1.29.2.2 skrll static int iwm_alloc_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
238 1.29.2.2 skrll static void iwm_reset_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
239 1.29.2.2 skrll static void iwm_free_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
240 1.29.2.2 skrll static int iwm_alloc_tx_ring(struct iwm_softc *, struct iwm_tx_ring *,
241 1.29.2.2 skrll int);
242 1.29.2.2 skrll static void iwm_reset_tx_ring(struct iwm_softc *, struct iwm_tx_ring *);
243 1.29.2.2 skrll static void iwm_free_tx_ring(struct iwm_softc *, struct iwm_tx_ring *);
244 1.29.2.2 skrll static void iwm_enable_rfkill_int(struct iwm_softc *);
245 1.29.2.2 skrll static int iwm_check_rfkill(struct iwm_softc *);
246 1.29.2.2 skrll static void iwm_enable_interrupts(struct iwm_softc *);
247 1.29.2.2 skrll static void iwm_restore_interrupts(struct iwm_softc *);
248 1.29.2.2 skrll static void iwm_disable_interrupts(struct iwm_softc *);
249 1.29.2.2 skrll static void iwm_ict_reset(struct iwm_softc *);
250 1.29.2.2 skrll static int iwm_set_hw_ready(struct iwm_softc *);
251 1.29.2.2 skrll static int iwm_prepare_card_hw(struct iwm_softc *);
252 1.29.2.2 skrll static void iwm_apm_config(struct iwm_softc *);
253 1.29.2.2 skrll static int iwm_apm_init(struct iwm_softc *);
254 1.29.2.2 skrll static void iwm_apm_stop(struct iwm_softc *);
255 1.29.2.2 skrll static int iwm_allow_mcast(struct iwm_softc *);
256 1.29.2.2 skrll static int iwm_start_hw(struct iwm_softc *);
257 1.29.2.2 skrll static void iwm_stop_device(struct iwm_softc *);
258 1.29.2.2 skrll static void iwm_set_pwr(struct iwm_softc *);
259 1.29.2.2 skrll static void iwm_mvm_nic_config(struct iwm_softc *);
260 1.29.2.2 skrll static int iwm_nic_rx_init(struct iwm_softc *);
261 1.29.2.2 skrll static int iwm_nic_tx_init(struct iwm_softc *);
262 1.29.2.2 skrll static int iwm_nic_init(struct iwm_softc *);
263 1.29.2.2 skrll static void iwm_enable_txq(struct iwm_softc *, int, int);
264 1.29.2.2 skrll static int iwm_post_alive(struct iwm_softc *);
265 1.29.2.2 skrll static int iwm_is_valid_channel(uint16_t);
266 1.29.2.2 skrll static uint8_t iwm_ch_id_to_ch_index(uint16_t);
267 1.29.2.2 skrll static uint16_t iwm_channel_id_to_papd(uint16_t);
268 1.29.2.2 skrll static uint16_t iwm_channel_id_to_txp(struct iwm_softc *, uint16_t);
269 1.29.2.2 skrll static int iwm_phy_db_get_section_data(struct iwm_softc *, uint32_t,
270 1.29.2.2 skrll uint8_t **, uint16_t *, uint16_t);
271 1.29.2.2 skrll static int iwm_send_phy_db_cmd(struct iwm_softc *, uint16_t, uint16_t,
272 1.29.2.2 skrll void *);
273 1.29.2.2 skrll static int iwm_send_phy_db_data(struct iwm_softc *);
274 1.29.2.2 skrll static int iwm_send_phy_db_data(struct iwm_softc *);
275 1.29.2.2 skrll static void iwm_mvm_te_v2_to_v1(const struct iwm_time_event_cmd_v2 *,
276 1.29.2.2 skrll struct iwm_time_event_cmd_v1 *);
277 1.29.2.2 skrll static int iwm_mvm_send_time_event_cmd(struct iwm_softc *,
278 1.29.2.2 skrll const struct iwm_time_event_cmd_v2 *);
279 1.29.2.2 skrll static int iwm_mvm_time_event_send_add(struct iwm_softc *,
280 1.29.2.2 skrll struct iwm_node *, void *, struct iwm_time_event_cmd_v2 *);
281 1.29.2.2 skrll static void iwm_mvm_protect_session(struct iwm_softc *, struct iwm_node *,
282 1.29.2.2 skrll uint32_t, uint32_t, uint32_t);
283 1.29.2.2 skrll static int iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t,
284 1.29.2.2 skrll uint16_t, uint8_t *, uint16_t *);
285 1.29.2.2 skrll static int iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *,
286 1.29.2.2 skrll uint16_t *);
287 1.29.2.2 skrll static void iwm_init_channel_map(struct iwm_softc *,
288 1.29.2.2 skrll const uint16_t * const);
289 1.29.2.2 skrll static int iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
290 1.29.2.2 skrll const uint16_t *, const uint16_t *, uint8_t, uint8_t);
291 1.29.2.2 skrll static int iwm_nvm_init(struct iwm_softc *);
292 1.29.2.2 skrll static int iwm_firmware_load_chunk(struct iwm_softc *, uint32_t,
293 1.29.2.2 skrll const uint8_t *, uint32_t);
294 1.29.2.2 skrll static int iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type);
295 1.29.2.2 skrll static int iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type);
296 1.29.2.2 skrll static int iwm_fw_alive(struct iwm_softc *, uint32_t);
297 1.29.2.2 skrll static int iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t);
298 1.29.2.2 skrll static int iwm_send_phy_cfg_cmd(struct iwm_softc *);
299 1.29.2.2 skrll static int iwm_mvm_load_ucode_wait_alive(struct iwm_softc *,
300 1.29.2.2 skrll enum iwm_ucode_type);
301 1.29.2.2 skrll static int iwm_run_init_mvm_ucode(struct iwm_softc *, int);
302 1.29.2.2 skrll static int iwm_rx_addbuf(struct iwm_softc *, int, int);
303 1.29.2.2 skrll static int iwm_mvm_calc_rssi(struct iwm_softc *, struct iwm_rx_phy_info *);
304 1.29.2.2 skrll static int iwm_mvm_get_signal_strength(struct iwm_softc *,
305 1.29.2.2 skrll struct iwm_rx_phy_info *);
306 1.29.2.2 skrll static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *,
307 1.29.2.2 skrll struct iwm_rx_packet *, struct iwm_rx_data *);
308 1.29.2.2 skrll static int iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *);
309 1.29.2.2 skrll static void iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
310 1.29.2.2 skrll struct iwm_rx_data *);
311 1.29.2.2 skrll static void iwm_mvm_rx_tx_cmd_single(struct iwm_softc *,
312 1.29.2.2 skrll struct iwm_rx_packet *, struct iwm_node *);
313 1.29.2.2 skrll static void iwm_mvm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
314 1.29.2.2 skrll struct iwm_rx_data *);
315 1.29.2.2 skrll static int iwm_mvm_binding_cmd(struct iwm_softc *, struct iwm_node *,
316 1.29.2.2 skrll uint32_t);
317 1.29.2.2 skrll static int iwm_mvm_binding_update(struct iwm_softc *, struct iwm_node *,
318 1.29.2.2 skrll int);
319 1.29.2.2 skrll static int iwm_mvm_binding_add_vif(struct iwm_softc *, struct iwm_node *);
320 1.29.2.2 skrll static void iwm_mvm_phy_ctxt_cmd_hdr(struct iwm_softc *,
321 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *, struct iwm_phy_context_cmd *,
322 1.29.2.2 skrll uint32_t, uint32_t);
323 1.29.2.2 skrll static void iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *,
324 1.29.2.2 skrll struct iwm_phy_context_cmd *, struct ieee80211_channel *,
325 1.29.2.2 skrll uint8_t, uint8_t);
326 1.29.2.2 skrll static int iwm_mvm_phy_ctxt_apply(struct iwm_softc *,
327 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *, uint8_t, uint8_t, uint32_t,
328 1.29.2.2 skrll uint32_t);
329 1.29.2.2 skrll static int iwm_mvm_phy_ctxt_add(struct iwm_softc *,
330 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *, struct ieee80211_channel *,
331 1.29.2.2 skrll uint8_t, uint8_t);
332 1.29.2.2 skrll static int iwm_mvm_phy_ctxt_changed(struct iwm_softc *,
333 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *, struct ieee80211_channel *,
334 1.29.2.2 skrll uint8_t, uint8_t);
335 1.29.2.2 skrll static int iwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
336 1.29.2.2 skrll static int iwm_mvm_send_cmd_pdu(struct iwm_softc *, uint8_t, uint32_t,
337 1.29.2.2 skrll uint16_t, const void *);
338 1.29.2.2 skrll static int iwm_mvm_send_cmd_status(struct iwm_softc *,
339 1.29.2.2 skrll struct iwm_host_cmd *, uint32_t *);
340 1.29.2.2 skrll static int iwm_mvm_send_cmd_pdu_status(struct iwm_softc *, uint8_t,
341 1.29.2.2 skrll uint16_t, const void *, uint32_t *);
342 1.29.2.2 skrll static void iwm_free_resp(struct iwm_softc *, struct iwm_host_cmd *);
343 1.29.2.2 skrll static void iwm_cmd_done(struct iwm_softc *, struct iwm_rx_packet *);
344 1.29.2.2 skrll #if 0
345 1.29.2.2 skrll static void iwm_update_sched(struct iwm_softc *, int, int, uint8_t,
346 1.29.2.2 skrll uint16_t);
347 1.29.2.2 skrll #endif
348 1.29.2.2 skrll static const struct iwm_rate *iwm_tx_fill_cmd(struct iwm_softc *,
349 1.29.2.2 skrll struct iwm_node *, struct ieee80211_frame *,
350 1.29.2.2 skrll struct iwm_tx_cmd *);
351 1.29.2.2 skrll static int iwm_tx(struct iwm_softc *, struct mbuf *,
352 1.29.2.2 skrll struct ieee80211_node *, int);
353 1.29.2.2 skrll static int iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *,
354 1.29.2.2 skrll struct iwm_beacon_filter_cmd *);
355 1.29.2.2 skrll static void iwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *,
356 1.29.2.2 skrll struct iwm_node *, struct iwm_beacon_filter_cmd *);
357 1.29.2.2 skrll static int iwm_mvm_update_beacon_abort(struct iwm_softc *,
358 1.29.2.2 skrll struct iwm_node *, int);
359 1.29.2.2 skrll static void iwm_mvm_power_log(struct iwm_softc *,
360 1.29.2.2 skrll struct iwm_mac_power_cmd *);
361 1.29.2.2 skrll static void iwm_mvm_power_build_cmd(struct iwm_softc *, struct iwm_node *,
362 1.29.2.2 skrll struct iwm_mac_power_cmd *);
363 1.29.2.2 skrll static int iwm_mvm_power_mac_update_mode(struct iwm_softc *,
364 1.29.2.2 skrll struct iwm_node *);
365 1.29.2.2 skrll static int iwm_mvm_power_update_device(struct iwm_softc *);
366 1.29.2.2 skrll static int iwm_mvm_enable_beacon_filter(struct iwm_softc *,
367 1.29.2.2 skrll struct iwm_node *);
368 1.29.2.2 skrll static int iwm_mvm_disable_beacon_filter(struct iwm_softc *,
369 1.29.2.2 skrll struct iwm_node *);
370 1.29.2.2 skrll static void iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *,
371 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v5 *);
372 1.29.2.2 skrll static int iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *,
373 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v6 *, int *);
374 1.29.2.2 skrll static int iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *,
375 1.29.2.2 skrll int);
376 1.29.2.2 skrll static int iwm_mvm_add_sta(struct iwm_softc *, struct iwm_node *);
377 1.29.2.2 skrll static int iwm_mvm_update_sta(struct iwm_softc *, struct iwm_node *);
378 1.29.2.2 skrll static int iwm_mvm_add_int_sta_common(struct iwm_softc *,
379 1.29.2.2 skrll struct iwm_int_sta *, const uint8_t *, uint16_t, uint16_t);
380 1.29.2.2 skrll static int iwm_mvm_add_aux_sta(struct iwm_softc *);
381 1.29.2.2 skrll static uint16_t iwm_mvm_scan_rx_chain(struct iwm_softc *);
382 1.29.2.2 skrll static uint32_t iwm_mvm_scan_max_out_time(struct iwm_softc *, uint32_t, int);
383 1.29.2.2 skrll static uint32_t iwm_mvm_scan_suspend_time(struct iwm_softc *, int);
384 1.29.2.2 skrll static uint32_t iwm_mvm_scan_rxon_flags(struct iwm_softc *, int);
385 1.29.2.2 skrll static uint32_t iwm_mvm_scan_rate_n_flags(struct iwm_softc *, int, int);
386 1.29.2.2 skrll static uint16_t iwm_mvm_get_active_dwell(struct iwm_softc *, int, int);
387 1.29.2.2 skrll static uint16_t iwm_mvm_get_passive_dwell(struct iwm_softc *, int);
388 1.29.2.2 skrll static int iwm_mvm_scan_fill_channels(struct iwm_softc *,
389 1.29.2.2 skrll struct iwm_scan_cmd *, int, int, int);
390 1.29.2.2 skrll static uint16_t iwm_mvm_fill_probe_req(struct iwm_softc *,
391 1.29.2.2 skrll struct ieee80211_frame *, const uint8_t *, int,
392 1.29.2.2 skrll const uint8_t *, int, const uint8_t *, int, int);
393 1.29.2.2 skrll static int iwm_mvm_scan_request(struct iwm_softc *, int, int, uint8_t *,
394 1.29.2.2 skrll int);
395 1.29.2.2 skrll static void iwm_mvm_ack_rates(struct iwm_softc *, struct iwm_node *, int *,
396 1.29.2.2 skrll int *);
397 1.29.2.2 skrll static void iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *,
398 1.29.2.2 skrll struct iwm_node *, struct iwm_mac_ctx_cmd *, uint32_t);
399 1.29.2.2 skrll static int iwm_mvm_mac_ctxt_send_cmd(struct iwm_softc *,
400 1.29.2.2 skrll struct iwm_mac_ctx_cmd *);
401 1.29.2.2 skrll static void iwm_mvm_mac_ctxt_cmd_fill_sta(struct iwm_softc *,
402 1.29.2.2 skrll struct iwm_node *, struct iwm_mac_data_sta *, int);
403 1.29.2.2 skrll static int iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *,
404 1.29.2.2 skrll struct iwm_node *, uint32_t);
405 1.29.2.2 skrll static int iwm_mvm_mac_ctx_send(struct iwm_softc *, struct iwm_node *,
406 1.29.2.2 skrll uint32_t);
407 1.29.2.2 skrll static int iwm_mvm_mac_ctxt_add(struct iwm_softc *, struct iwm_node *);
408 1.29.2.2 skrll static int iwm_mvm_mac_ctxt_changed(struct iwm_softc *, struct iwm_node *);
409 1.29.2.2 skrll static int iwm_mvm_update_quotas(struct iwm_softc *, struct iwm_node *);
410 1.29.2.2 skrll static int iwm_auth(struct iwm_softc *);
411 1.29.2.2 skrll static int iwm_assoc(struct iwm_softc *);
412 1.29.2.2 skrll static int iwm_release(struct iwm_softc *, struct iwm_node *);
413 1.29.2.2 skrll static void iwm_calib_timeout(void *);
414 1.29.2.2 skrll static void iwm_setrates(struct iwm_node *);
415 1.29.2.2 skrll static int iwm_media_change(struct ifnet *);
416 1.29.2.2 skrll static void iwm_newstate_cb(struct work *, void *);
417 1.29.2.2 skrll static int iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
418 1.29.2.2 skrll static void iwm_endscan_cb(struct work *, void *);
419 1.29.2.2 skrll static int iwm_init_hw(struct iwm_softc *);
420 1.29.2.2 skrll static int iwm_init(struct ifnet *);
421 1.29.2.2 skrll static void iwm_start(struct ifnet *);
422 1.29.2.2 skrll static void iwm_stop(struct ifnet *, int);
423 1.29.2.2 skrll static void iwm_watchdog(struct ifnet *);
424 1.29.2.2 skrll static int iwm_ioctl(struct ifnet *, u_long, void *);
425 1.29.2.2 skrll #ifdef IWM_DEBUG
426 1.29.2.2 skrll static const char *iwm_desc_lookup(uint32_t);
427 1.29.2.2 skrll static void iwm_nic_error(struct iwm_softc *);
428 1.29.2.2 skrll #endif
429 1.29.2.2 skrll static void iwm_notif_intr(struct iwm_softc *);
430 1.29.2.2 skrll static int iwm_intr(void *);
431 1.29.2.2 skrll static int iwm_preinit(struct iwm_softc *);
432 1.29.2.2 skrll static void iwm_attach_hook(device_t);
433 1.29.2.2 skrll static void iwm_attach(device_t, device_t, void *);
434 1.29.2.2 skrll #if 0
435 1.29.2.2 skrll static void iwm_init_task(void *);
436 1.29.2.2 skrll static int iwm_activate(device_t, enum devact);
437 1.29.2.2 skrll static void iwm_wakeup(struct iwm_softc *);
438 1.29.2.2 skrll #endif
439 1.29.2.2 skrll static void iwm_radiotap_attach(struct iwm_softc *);
440 1.29.2.4 skrll static int iwm_sysctl_fw_loaded_handler(SYSCTLFN_PROTO);
441 1.29.2.4 skrll
442 1.29.2.4 skrll static int iwm_sysctl_root_num;
443 1.29.2.2 skrll
444 1.29.2.2 skrll static int
445 1.29.2.2 skrll iwm_firmload(struct iwm_softc *sc)
446 1.29.2.2 skrll {
447 1.29.2.2 skrll struct iwm_fw_info *fw = &sc->sc_fw;
448 1.29.2.2 skrll firmware_handle_t fwh;
449 1.29.2.2 skrll int error;
450 1.29.2.2 skrll
451 1.29.2.4 skrll if (ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED))
452 1.29.2.4 skrll return 0;
453 1.29.2.4 skrll
454 1.29.2.2 skrll /* Open firmware image. */
455 1.29.2.2 skrll if ((error = firmware_open("if_iwm", sc->sc_fwname, &fwh)) != 0) {
456 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
457 1.29.2.2 skrll "could not get firmware handle %s\n", sc->sc_fwname);
458 1.29.2.2 skrll return error;
459 1.29.2.2 skrll }
460 1.29.2.2 skrll
461 1.29.2.4 skrll if (fw->fw_rawdata != NULL && fw->fw_rawsize > 0) {
462 1.29.2.4 skrll kmem_free(fw->fw_rawdata, fw->fw_rawsize);
463 1.29.2.4 skrll fw->fw_rawdata = NULL;
464 1.29.2.4 skrll }
465 1.29.2.4 skrll
466 1.29.2.2 skrll fw->fw_rawsize = firmware_get_size(fwh);
467 1.29.2.2 skrll /*
468 1.29.2.2 skrll * Well, this is how the Linux driver checks it ....
469 1.29.2.2 skrll */
470 1.29.2.2 skrll if (fw->fw_rawsize < sizeof(uint32_t)) {
471 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
472 1.29.2.2 skrll "firmware too short: %zd bytes\n", fw->fw_rawsize);
473 1.29.2.2 skrll error = EINVAL;
474 1.29.2.2 skrll goto out;
475 1.29.2.2 skrll }
476 1.29.2.2 skrll
477 1.29.2.2 skrll /* some sanity */
478 1.29.2.2 skrll if (fw->fw_rawsize > IWM_FWMAXSIZE) {
479 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
480 1.29.2.4 skrll "firmware size is ridiculous: %zd bytes\n", fw->fw_rawsize);
481 1.29.2.2 skrll error = EINVAL;
482 1.29.2.2 skrll goto out;
483 1.29.2.2 skrll }
484 1.29.2.2 skrll
485 1.29.2.2 skrll /* Read the firmware. */
486 1.29.2.2 skrll fw->fw_rawdata = kmem_alloc(fw->fw_rawsize, KM_SLEEP);
487 1.29.2.2 skrll if (fw->fw_rawdata == NULL) {
488 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
489 1.29.2.2 skrll "not enough memory to stock firmware %s\n", sc->sc_fwname);
490 1.29.2.2 skrll error = ENOMEM;
491 1.29.2.2 skrll goto out;
492 1.29.2.2 skrll }
493 1.29.2.2 skrll error = firmware_read(fwh, 0, fw->fw_rawdata, fw->fw_rawsize);
494 1.29.2.2 skrll if (error) {
495 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
496 1.29.2.2 skrll "could not read firmware %s\n", sc->sc_fwname);
497 1.29.2.2 skrll goto out;
498 1.29.2.2 skrll }
499 1.29.2.2 skrll
500 1.29.2.4 skrll SET(sc->sc_flags, IWM_FLAG_FW_LOADED);
501 1.29.2.2 skrll out:
502 1.29.2.2 skrll /* caller will release memory, if necessary */
503 1.29.2.2 skrll
504 1.29.2.2 skrll firmware_close(fwh);
505 1.29.2.2 skrll return error;
506 1.29.2.2 skrll }
507 1.29.2.2 skrll
508 1.29.2.2 skrll /*
509 1.29.2.2 skrll * just maintaining status quo.
510 1.29.2.2 skrll */
511 1.29.2.2 skrll static void
512 1.29.2.2 skrll iwm_fix_channel(struct ieee80211com *ic, struct mbuf *m)
513 1.29.2.2 skrll {
514 1.29.2.3 skrll struct iwm_softc *sc = ic->ic_ifp->if_softc;
515 1.29.2.2 skrll struct ieee80211_frame *wh;
516 1.29.2.2 skrll uint8_t subtype;
517 1.29.2.2 skrll uint8_t *frm, *efrm;
518 1.29.2.2 skrll
519 1.29.2.2 skrll wh = mtod(m, struct ieee80211_frame *);
520 1.29.2.2 skrll
521 1.29.2.2 skrll if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
522 1.29.2.2 skrll return;
523 1.29.2.2 skrll
524 1.29.2.2 skrll subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
525 1.29.2.2 skrll
526 1.29.2.2 skrll if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
527 1.29.2.2 skrll subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
528 1.29.2.2 skrll return;
529 1.29.2.2 skrll
530 1.29.2.3 skrll if (sc->sc_scanband == IEEE80211_CHAN_5GHZ) {
531 1.29.2.3 skrll int chan = le32toh(sc->sc_last_phy_info.channel);
532 1.29.2.3 skrll if (chan < __arraycount(ic->ic_channels))
533 1.29.2.3 skrll ic->ic_curchan = &ic->ic_channels[chan];
534 1.29.2.3 skrll return;
535 1.29.2.3 skrll }
536 1.29.2.3 skrll
537 1.29.2.2 skrll frm = (uint8_t *)(wh + 1);
538 1.29.2.2 skrll efrm = mtod(m, uint8_t *) + m->m_len;
539 1.29.2.2 skrll
540 1.29.2.2 skrll frm += 12; /* skip tstamp, bintval and capinfo fields */
541 1.29.2.2 skrll while (frm < efrm) {
542 1.29.2.2 skrll if (*frm == IEEE80211_ELEMID_DSPARMS) {
543 1.29.2.2 skrll #if IEEE80211_CHAN_MAX < 255
544 1.29.2.2 skrll if (frm[2] <= IEEE80211_CHAN_MAX)
545 1.29.2.2 skrll #endif
546 1.29.2.2 skrll ic->ic_curchan = &ic->ic_channels[frm[2]];
547 1.29.2.2 skrll }
548 1.29.2.2 skrll frm += frm[1] + 2;
549 1.29.2.2 skrll }
550 1.29.2.2 skrll }
551 1.29.2.2 skrll
552 1.29.2.2 skrll /*
553 1.29.2.2 skrll * Firmware parser.
554 1.29.2.2 skrll */
555 1.29.2.2 skrll
556 1.29.2.2 skrll static int
557 1.29.2.2 skrll iwm_store_cscheme(struct iwm_softc *sc, uint8_t *data, size_t dlen)
558 1.29.2.2 skrll {
559 1.29.2.2 skrll struct iwm_fw_cscheme_list *l = (void *)data;
560 1.29.2.2 skrll
561 1.29.2.2 skrll if (dlen < sizeof(*l) ||
562 1.29.2.2 skrll dlen < sizeof(l->size) + l->size * sizeof(*l->cs))
563 1.29.2.2 skrll return EINVAL;
564 1.29.2.2 skrll
565 1.29.2.2 skrll /* we don't actually store anything for now, always use s/w crypto */
566 1.29.2.2 skrll
567 1.29.2.2 skrll return 0;
568 1.29.2.2 skrll }
569 1.29.2.2 skrll
570 1.29.2.2 skrll static int
571 1.29.2.2 skrll iwm_firmware_store_section(struct iwm_softc *sc,
572 1.29.2.2 skrll enum iwm_ucode_type type, uint8_t *data, size_t dlen)
573 1.29.2.2 skrll {
574 1.29.2.2 skrll struct iwm_fw_sects *fws;
575 1.29.2.2 skrll struct iwm_fw_onesect *fwone;
576 1.29.2.2 skrll
577 1.29.2.2 skrll if (type >= IWM_UCODE_TYPE_MAX)
578 1.29.2.2 skrll return EINVAL;
579 1.29.2.2 skrll if (dlen < sizeof(uint32_t))
580 1.29.2.2 skrll return EINVAL;
581 1.29.2.2 skrll
582 1.29.2.2 skrll fws = &sc->sc_fw.fw_sects[type];
583 1.29.2.2 skrll if (fws->fw_count >= IWM_UCODE_SECT_MAX)
584 1.29.2.2 skrll return EINVAL;
585 1.29.2.2 skrll
586 1.29.2.2 skrll fwone = &fws->fw_sect[fws->fw_count];
587 1.29.2.2 skrll
588 1.29.2.2 skrll /* first 32bit are device load offset */
589 1.29.2.2 skrll memcpy(&fwone->fws_devoff, data, sizeof(uint32_t));
590 1.29.2.2 skrll
591 1.29.2.2 skrll /* rest is data */
592 1.29.2.2 skrll fwone->fws_data = data + sizeof(uint32_t);
593 1.29.2.2 skrll fwone->fws_len = dlen - sizeof(uint32_t);
594 1.29.2.2 skrll
595 1.29.2.2 skrll /* for freeing the buffer during driver unload */
596 1.29.2.2 skrll fwone->fws_alloc = data;
597 1.29.2.2 skrll fwone->fws_allocsize = dlen;
598 1.29.2.2 skrll
599 1.29.2.2 skrll fws->fw_count++;
600 1.29.2.2 skrll fws->fw_totlen += fwone->fws_len;
601 1.29.2.2 skrll
602 1.29.2.2 skrll return 0;
603 1.29.2.2 skrll }
604 1.29.2.2 skrll
605 1.29.2.2 skrll /* iwlwifi: iwl-drv.c */
606 1.29.2.2 skrll struct iwm_tlv_calib_data {
607 1.29.2.2 skrll uint32_t ucode_type;
608 1.29.2.2 skrll struct iwm_tlv_calib_ctrl calib;
609 1.29.2.2 skrll } __packed;
610 1.29.2.2 skrll
611 1.29.2.2 skrll static int
612 1.29.2.2 skrll iwm_set_default_calib(struct iwm_softc *sc, const void *data)
613 1.29.2.2 skrll {
614 1.29.2.2 skrll const struct iwm_tlv_calib_data *def_calib = data;
615 1.29.2.2 skrll uint32_t ucode_type = le32toh(def_calib->ucode_type);
616 1.29.2.2 skrll
617 1.29.2.2 skrll if (ucode_type >= IWM_UCODE_TYPE_MAX) {
618 1.29.2.2 skrll DPRINTF(("%s: Wrong ucode_type %u for default "
619 1.29.2.2 skrll "calibration.\n", DEVNAME(sc), ucode_type));
620 1.29.2.2 skrll return EINVAL;
621 1.29.2.2 skrll }
622 1.29.2.2 skrll
623 1.29.2.2 skrll sc->sc_default_calib[ucode_type].flow_trigger =
624 1.29.2.2 skrll def_calib->calib.flow_trigger;
625 1.29.2.2 skrll sc->sc_default_calib[ucode_type].event_trigger =
626 1.29.2.2 skrll def_calib->calib.event_trigger;
627 1.29.2.2 skrll
628 1.29.2.2 skrll return 0;
629 1.29.2.2 skrll }
630 1.29.2.2 skrll
631 1.29.2.2 skrll static int
632 1.29.2.2 skrll iwm_read_firmware(struct iwm_softc *sc)
633 1.29.2.2 skrll {
634 1.29.2.2 skrll struct iwm_fw_info *fw = &sc->sc_fw;
635 1.29.2.2 skrll struct iwm_tlv_ucode_header *uhdr;
636 1.29.2.2 skrll struct iwm_ucode_tlv tlv;
637 1.29.2.2 skrll enum iwm_ucode_tlv_type tlv_type;
638 1.29.2.2 skrll uint8_t *data;
639 1.29.2.2 skrll int error, status;
640 1.29.2.2 skrll size_t len;
641 1.29.2.2 skrll
642 1.29.2.2 skrll if (fw->fw_status == IWM_FW_STATUS_NONE) {
643 1.29.2.2 skrll fw->fw_status = IWM_FW_STATUS_INPROGRESS;
644 1.29.2.2 skrll } else {
645 1.29.2.2 skrll while (fw->fw_status == IWM_FW_STATUS_INPROGRESS)
646 1.29.2.2 skrll tsleep(&sc->sc_fw, 0, "iwmfwp", 0);
647 1.29.2.2 skrll }
648 1.29.2.2 skrll status = fw->fw_status;
649 1.29.2.2 skrll
650 1.29.2.2 skrll if (status == IWM_FW_STATUS_DONE)
651 1.29.2.2 skrll return 0;
652 1.29.2.2 skrll
653 1.29.2.2 skrll /*
654 1.29.2.2 skrll * Load firmware into driver memory.
655 1.29.2.2 skrll * fw_rawdata and fw_rawsize will be set.
656 1.29.2.2 skrll */
657 1.29.2.2 skrll error = iwm_firmload(sc);
658 1.29.2.2 skrll if (error != 0) {
659 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
660 1.29.2.2 skrll "could not read firmware %s (error %d)\n",
661 1.29.2.2 skrll sc->sc_fwname, error);
662 1.29.2.2 skrll goto out;
663 1.29.2.2 skrll }
664 1.29.2.2 skrll
665 1.29.2.2 skrll /*
666 1.29.2.2 skrll * Parse firmware contents
667 1.29.2.2 skrll */
668 1.29.2.2 skrll
669 1.29.2.2 skrll uhdr = (void *)fw->fw_rawdata;
670 1.29.2.2 skrll if (*(uint32_t *)fw->fw_rawdata != 0
671 1.29.2.2 skrll || le32toh(uhdr->magic) != IWM_TLV_UCODE_MAGIC) {
672 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "invalid firmware %s\n",
673 1.29.2.2 skrll sc->sc_fwname);
674 1.29.2.2 skrll error = EINVAL;
675 1.29.2.2 skrll goto out;
676 1.29.2.2 skrll }
677 1.29.2.2 skrll
678 1.29.2.2 skrll sc->sc_fwver = le32toh(uhdr->ver);
679 1.29.2.2 skrll data = uhdr->data;
680 1.29.2.2 skrll len = fw->fw_rawsize - sizeof(*uhdr);
681 1.29.2.2 skrll
682 1.29.2.2 skrll while (len >= sizeof(tlv)) {
683 1.29.2.2 skrll size_t tlv_len;
684 1.29.2.2 skrll void *tlv_data;
685 1.29.2.2 skrll
686 1.29.2.2 skrll memcpy(&tlv, data, sizeof(tlv));
687 1.29.2.2 skrll tlv_len = le32toh(tlv.length);
688 1.29.2.2 skrll tlv_type = le32toh(tlv.type);
689 1.29.2.2 skrll
690 1.29.2.2 skrll len -= sizeof(tlv);
691 1.29.2.2 skrll data += sizeof(tlv);
692 1.29.2.2 skrll tlv_data = data;
693 1.29.2.2 skrll
694 1.29.2.2 skrll if (len < tlv_len) {
695 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
696 1.29.2.2 skrll "firmware too short: %zu bytes\n", len);
697 1.29.2.2 skrll error = EINVAL;
698 1.29.2.2 skrll goto parse_out;
699 1.29.2.2 skrll }
700 1.29.2.2 skrll
701 1.29.2.2 skrll switch ((int)tlv_type) {
702 1.29.2.2 skrll case IWM_UCODE_TLV_PROBE_MAX_LEN:
703 1.29.2.2 skrll if (tlv_len < sizeof(uint32_t)) {
704 1.29.2.2 skrll error = EINVAL;
705 1.29.2.2 skrll goto parse_out;
706 1.29.2.2 skrll }
707 1.29.2.2 skrll sc->sc_capa_max_probe_len
708 1.29.2.2 skrll = le32toh(*(uint32_t *)tlv_data);
709 1.29.2.2 skrll /* limit it to something sensible */
710 1.29.2.2 skrll if (sc->sc_capa_max_probe_len > (1<<16)) {
711 1.29.2.2 skrll DPRINTF(("%s: IWM_UCODE_TLV_PROBE_MAX_LEN "
712 1.29.2.2 skrll "ridiculous\n", DEVNAME(sc)));
713 1.29.2.2 skrll error = EINVAL;
714 1.29.2.2 skrll goto parse_out;
715 1.29.2.2 skrll }
716 1.29.2.2 skrll break;
717 1.29.2.2 skrll case IWM_UCODE_TLV_PAN:
718 1.29.2.2 skrll if (tlv_len) {
719 1.29.2.2 skrll error = EINVAL;
720 1.29.2.2 skrll goto parse_out;
721 1.29.2.2 skrll }
722 1.29.2.2 skrll sc->sc_capaflags |= IWM_UCODE_TLV_FLAGS_PAN;
723 1.29.2.2 skrll break;
724 1.29.2.2 skrll case IWM_UCODE_TLV_FLAGS:
725 1.29.2.2 skrll if (tlv_len < sizeof(uint32_t)) {
726 1.29.2.2 skrll error = EINVAL;
727 1.29.2.2 skrll goto parse_out;
728 1.29.2.2 skrll }
729 1.29.2.2 skrll /*
730 1.29.2.2 skrll * Apparently there can be many flags, but Linux driver
731 1.29.2.2 skrll * parses only the first one, and so do we.
732 1.29.2.2 skrll *
733 1.29.2.2 skrll * XXX: why does this override IWM_UCODE_TLV_PAN?
734 1.29.2.2 skrll * Intentional or a bug? Observations from
735 1.29.2.2 skrll * current firmware file:
736 1.29.2.2 skrll * 1) TLV_PAN is parsed first
737 1.29.2.2 skrll * 2) TLV_FLAGS contains TLV_FLAGS_PAN
738 1.29.2.2 skrll * ==> this resets TLV_PAN to itself... hnnnk
739 1.29.2.2 skrll */
740 1.29.2.2 skrll sc->sc_capaflags = le32toh(*(uint32_t *)tlv_data);
741 1.29.2.2 skrll break;
742 1.29.2.2 skrll case IWM_UCODE_TLV_CSCHEME:
743 1.29.2.2 skrll if ((error = iwm_store_cscheme(sc,
744 1.29.2.2 skrll tlv_data, tlv_len)) != 0)
745 1.29.2.2 skrll goto parse_out;
746 1.29.2.2 skrll break;
747 1.29.2.2 skrll case IWM_UCODE_TLV_NUM_OF_CPU:
748 1.29.2.2 skrll if (tlv_len != sizeof(uint32_t)) {
749 1.29.2.2 skrll error = EINVAL;
750 1.29.2.2 skrll goto parse_out;
751 1.29.2.2 skrll }
752 1.29.2.2 skrll if (le32toh(*(uint32_t*)tlv_data) != 1) {
753 1.29.2.2 skrll DPRINTF(("%s: driver supports "
754 1.29.2.2 skrll "only TLV_NUM_OF_CPU == 1", DEVNAME(sc)));
755 1.29.2.2 skrll error = EINVAL;
756 1.29.2.2 skrll goto parse_out;
757 1.29.2.2 skrll }
758 1.29.2.2 skrll break;
759 1.29.2.2 skrll case IWM_UCODE_TLV_SEC_RT:
760 1.29.2.2 skrll if ((error = iwm_firmware_store_section(sc,
761 1.29.2.2 skrll IWM_UCODE_TYPE_REGULAR, tlv_data, tlv_len)) != 0)
762 1.29.2.2 skrll goto parse_out;
763 1.29.2.2 skrll break;
764 1.29.2.2 skrll case IWM_UCODE_TLV_SEC_INIT:
765 1.29.2.2 skrll if ((error = iwm_firmware_store_section(sc,
766 1.29.2.2 skrll IWM_UCODE_TYPE_INIT, tlv_data, tlv_len)) != 0)
767 1.29.2.2 skrll goto parse_out;
768 1.29.2.2 skrll break;
769 1.29.2.2 skrll case IWM_UCODE_TLV_SEC_WOWLAN:
770 1.29.2.2 skrll if ((error = iwm_firmware_store_section(sc,
771 1.29.2.2 skrll IWM_UCODE_TYPE_WOW, tlv_data, tlv_len)) != 0)
772 1.29.2.2 skrll goto parse_out;
773 1.29.2.2 skrll break;
774 1.29.2.2 skrll case IWM_UCODE_TLV_DEF_CALIB:
775 1.29.2.2 skrll if (tlv_len != sizeof(struct iwm_tlv_calib_data)) {
776 1.29.2.2 skrll error = EINVAL;
777 1.29.2.2 skrll goto parse_out;
778 1.29.2.2 skrll }
779 1.29.2.2 skrll if ((error = iwm_set_default_calib(sc, tlv_data)) != 0)
780 1.29.2.2 skrll goto parse_out;
781 1.29.2.2 skrll break;
782 1.29.2.2 skrll case IWM_UCODE_TLV_PHY_SKU:
783 1.29.2.2 skrll if (tlv_len != sizeof(uint32_t)) {
784 1.29.2.2 skrll error = EINVAL;
785 1.29.2.2 skrll goto parse_out;
786 1.29.2.2 skrll }
787 1.29.2.2 skrll sc->sc_fw_phy_config = le32toh(*(uint32_t *)tlv_data);
788 1.29.2.2 skrll break;
789 1.29.2.2 skrll
790 1.29.2.2 skrll case IWM_UCODE_TLV_API_CHANGES_SET:
791 1.29.2.2 skrll case IWM_UCODE_TLV_ENABLED_CAPABILITIES:
792 1.29.2.2 skrll /* ignore, not used by current driver */
793 1.29.2.2 skrll break;
794 1.29.2.2 skrll
795 1.29.2.2 skrll default:
796 1.29.2.2 skrll DPRINTF(("%s: unknown firmware section %d, abort\n",
797 1.29.2.2 skrll DEVNAME(sc), tlv_type));
798 1.29.2.2 skrll error = EINVAL;
799 1.29.2.2 skrll goto parse_out;
800 1.29.2.2 skrll }
801 1.29.2.2 skrll
802 1.29.2.2 skrll len -= roundup(tlv_len, 4);
803 1.29.2.2 skrll data += roundup(tlv_len, 4);
804 1.29.2.2 skrll }
805 1.29.2.2 skrll
806 1.29.2.2 skrll KASSERT(error == 0);
807 1.29.2.2 skrll
808 1.29.2.2 skrll parse_out:
809 1.29.2.2 skrll if (error) {
810 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
811 1.29.2.2 skrll "firmware parse error, section type %d\n", tlv_type);
812 1.29.2.2 skrll }
813 1.29.2.2 skrll
814 1.29.2.2 skrll if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
815 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
816 1.29.2.2 skrll "device uses unsupported power ops\n");
817 1.29.2.2 skrll error = ENOTSUP;
818 1.29.2.2 skrll }
819 1.29.2.2 skrll
820 1.29.2.2 skrll out:
821 1.29.2.2 skrll if (error)
822 1.29.2.2 skrll fw->fw_status = IWM_FW_STATUS_NONE;
823 1.29.2.2 skrll else
824 1.29.2.2 skrll fw->fw_status = IWM_FW_STATUS_DONE;
825 1.29.2.2 skrll wakeup(&sc->sc_fw);
826 1.29.2.2 skrll
827 1.29.2.2 skrll if (error && fw->fw_rawdata != NULL) {
828 1.29.2.2 skrll kmem_free(fw->fw_rawdata, fw->fw_rawsize);
829 1.29.2.2 skrll fw->fw_rawdata = NULL;
830 1.29.2.4 skrll CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
831 1.29.2.2 skrll }
832 1.29.2.2 skrll return error;
833 1.29.2.2 skrll }
834 1.29.2.2 skrll
835 1.29.2.2 skrll /*
836 1.29.2.2 skrll * basic device access
837 1.29.2.2 skrll */
838 1.29.2.2 skrll
839 1.29.2.2 skrll static uint32_t
840 1.29.2.2 skrll iwm_read_prph(struct iwm_softc *sc, uint32_t addr)
841 1.29.2.2 skrll {
842 1.29.2.2 skrll IWM_WRITE(sc,
843 1.29.2.2 skrll IWM_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24)));
844 1.29.2.2 skrll IWM_BARRIER_READ_WRITE(sc);
845 1.29.2.2 skrll return IWM_READ(sc, IWM_HBUS_TARG_PRPH_RDAT);
846 1.29.2.2 skrll }
847 1.29.2.2 skrll
848 1.29.2.2 skrll static void
849 1.29.2.2 skrll iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val)
850 1.29.2.2 skrll {
851 1.29.2.2 skrll IWM_WRITE(sc,
852 1.29.2.2 skrll IWM_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24)));
853 1.29.2.2 skrll IWM_BARRIER_WRITE(sc);
854 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val);
855 1.29.2.2 skrll }
856 1.29.2.2 skrll
857 1.29.2.2 skrll #ifdef IWM_DEBUG
858 1.29.2.2 skrll /* iwlwifi: pcie/trans.c */
859 1.29.2.2 skrll static int
860 1.29.2.2 skrll iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords)
861 1.29.2.2 skrll {
862 1.29.2.2 skrll int offs, ret = 0;
863 1.29.2.2 skrll uint32_t *vals = buf;
864 1.29.2.2 skrll
865 1.29.2.2 skrll if (iwm_nic_lock(sc)) {
866 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_MEM_RADDR, addr);
867 1.29.2.2 skrll for (offs = 0; offs < dwords; offs++)
868 1.29.2.2 skrll vals[offs] = IWM_READ(sc, IWM_HBUS_TARG_MEM_RDAT);
869 1.29.2.2 skrll iwm_nic_unlock(sc);
870 1.29.2.2 skrll } else {
871 1.29.2.2 skrll ret = EBUSY;
872 1.29.2.2 skrll }
873 1.29.2.2 skrll return ret;
874 1.29.2.2 skrll }
875 1.29.2.2 skrll #endif
876 1.29.2.2 skrll
877 1.29.2.2 skrll /* iwlwifi: pcie/trans.c */
878 1.29.2.2 skrll static int
879 1.29.2.2 skrll iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords)
880 1.29.2.2 skrll {
881 1.29.2.2 skrll int offs;
882 1.29.2.2 skrll const uint32_t *vals = buf;
883 1.29.2.2 skrll
884 1.29.2.2 skrll if (iwm_nic_lock(sc)) {
885 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr);
886 1.29.2.2 skrll /* WADDR auto-increments */
887 1.29.2.2 skrll for (offs = 0; offs < dwords; offs++) {
888 1.29.2.2 skrll uint32_t val = vals ? vals[offs] : 0;
889 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val);
890 1.29.2.2 skrll }
891 1.29.2.2 skrll iwm_nic_unlock(sc);
892 1.29.2.2 skrll } else {
893 1.29.2.2 skrll DPRINTF(("%s: write_mem failed\n", DEVNAME(sc)));
894 1.29.2.2 skrll return EBUSY;
895 1.29.2.2 skrll }
896 1.29.2.2 skrll return 0;
897 1.29.2.2 skrll }
898 1.29.2.2 skrll
899 1.29.2.2 skrll static int
900 1.29.2.2 skrll iwm_write_mem32(struct iwm_softc *sc, uint32_t addr, uint32_t val)
901 1.29.2.2 skrll {
902 1.29.2.2 skrll return iwm_write_mem(sc, addr, &val, 1);
903 1.29.2.2 skrll }
904 1.29.2.2 skrll
905 1.29.2.2 skrll static int
906 1.29.2.2 skrll iwm_poll_bit(struct iwm_softc *sc, int reg,
907 1.29.2.2 skrll uint32_t bits, uint32_t mask, int timo)
908 1.29.2.2 skrll {
909 1.29.2.2 skrll for (;;) {
910 1.29.2.2 skrll if ((IWM_READ(sc, reg) & mask) == (bits & mask)) {
911 1.29.2.2 skrll return 1;
912 1.29.2.2 skrll }
913 1.29.2.2 skrll if (timo < 10) {
914 1.29.2.2 skrll return 0;
915 1.29.2.2 skrll }
916 1.29.2.2 skrll timo -= 10;
917 1.29.2.2 skrll DELAY(10);
918 1.29.2.2 skrll }
919 1.29.2.2 skrll }
920 1.29.2.2 skrll
921 1.29.2.2 skrll static int
922 1.29.2.2 skrll iwm_nic_lock(struct iwm_softc *sc)
923 1.29.2.2 skrll {
924 1.29.2.2 skrll int rv = 0;
925 1.29.2.2 skrll
926 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
927 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
928 1.29.2.2 skrll
929 1.29.2.2 skrll if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
930 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
931 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY
932 1.29.2.2 skrll | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) {
933 1.29.2.2 skrll rv = 1;
934 1.29.2.2 skrll } else {
935 1.29.2.2 skrll /* jolt */
936 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI);
937 1.29.2.2 skrll }
938 1.29.2.2 skrll
939 1.29.2.2 skrll return rv;
940 1.29.2.2 skrll }
941 1.29.2.2 skrll
942 1.29.2.2 skrll static void
943 1.29.2.2 skrll iwm_nic_unlock(struct iwm_softc *sc)
944 1.29.2.2 skrll {
945 1.29.2.2 skrll IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
946 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
947 1.29.2.2 skrll }
948 1.29.2.2 skrll
949 1.29.2.2 skrll static void
950 1.29.2.2 skrll iwm_set_bits_mask_prph(struct iwm_softc *sc,
951 1.29.2.2 skrll uint32_t reg, uint32_t bits, uint32_t mask)
952 1.29.2.2 skrll {
953 1.29.2.2 skrll uint32_t val;
954 1.29.2.2 skrll
955 1.29.2.2 skrll /* XXX: no error path? */
956 1.29.2.2 skrll if (iwm_nic_lock(sc)) {
957 1.29.2.2 skrll val = iwm_read_prph(sc, reg) & mask;
958 1.29.2.2 skrll val |= bits;
959 1.29.2.2 skrll iwm_write_prph(sc, reg, val);
960 1.29.2.2 skrll iwm_nic_unlock(sc);
961 1.29.2.2 skrll }
962 1.29.2.2 skrll }
963 1.29.2.2 skrll
964 1.29.2.2 skrll static void
965 1.29.2.2 skrll iwm_set_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
966 1.29.2.2 skrll {
967 1.29.2.2 skrll iwm_set_bits_mask_prph(sc, reg, bits, ~0);
968 1.29.2.2 skrll }
969 1.29.2.2 skrll
970 1.29.2.2 skrll static void
971 1.29.2.2 skrll iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
972 1.29.2.2 skrll {
973 1.29.2.2 skrll iwm_set_bits_mask_prph(sc, reg, 0, ~bits);
974 1.29.2.2 skrll }
975 1.29.2.2 skrll
976 1.29.2.2 skrll /*
977 1.29.2.2 skrll * DMA resource routines
978 1.29.2.2 skrll */
979 1.29.2.2 skrll
980 1.29.2.2 skrll static int
981 1.29.2.2 skrll iwm_dma_contig_alloc(bus_dma_tag_t tag, struct iwm_dma_info *dma,
982 1.29.2.2 skrll bus_size_t size, bus_size_t alignment)
983 1.29.2.2 skrll {
984 1.29.2.2 skrll int nsegs, error;
985 1.29.2.2 skrll void *va;
986 1.29.2.2 skrll
987 1.29.2.2 skrll dma->tag = tag;
988 1.29.2.2 skrll dma->size = size;
989 1.29.2.2 skrll
990 1.29.2.2 skrll error = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT,
991 1.29.2.2 skrll &dma->map);
992 1.29.2.2 skrll if (error != 0)
993 1.29.2.2 skrll goto fail;
994 1.29.2.2 skrll
995 1.29.2.2 skrll error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs,
996 1.29.2.2 skrll BUS_DMA_NOWAIT);
997 1.29.2.2 skrll if (error != 0)
998 1.29.2.2 skrll goto fail;
999 1.29.2.2 skrll
1000 1.29.2.2 skrll error = bus_dmamem_map(tag, &dma->seg, 1, size, &va,
1001 1.29.2.2 skrll BUS_DMA_NOWAIT);
1002 1.29.2.2 skrll if (error != 0)
1003 1.29.2.2 skrll goto fail;
1004 1.29.2.2 skrll dma->vaddr = va;
1005 1.29.2.2 skrll
1006 1.29.2.2 skrll error = bus_dmamap_load(tag, dma->map, dma->vaddr, size, NULL,
1007 1.29.2.2 skrll BUS_DMA_NOWAIT);
1008 1.29.2.2 skrll if (error != 0)
1009 1.29.2.2 skrll goto fail;
1010 1.29.2.2 skrll
1011 1.29.2.2 skrll memset(dma->vaddr, 0, size);
1012 1.29.2.2 skrll bus_dmamap_sync(tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE);
1013 1.29.2.2 skrll dma->paddr = dma->map->dm_segs[0].ds_addr;
1014 1.29.2.2 skrll
1015 1.29.2.2 skrll return 0;
1016 1.29.2.2 skrll
1017 1.29.2.2 skrll fail: iwm_dma_contig_free(dma);
1018 1.29.2.2 skrll return error;
1019 1.29.2.2 skrll }
1020 1.29.2.2 skrll
1021 1.29.2.2 skrll static void
1022 1.29.2.2 skrll iwm_dma_contig_free(struct iwm_dma_info *dma)
1023 1.29.2.2 skrll {
1024 1.29.2.2 skrll if (dma->map != NULL) {
1025 1.29.2.2 skrll if (dma->vaddr != NULL) {
1026 1.29.2.2 skrll bus_dmamap_sync(dma->tag, dma->map, 0, dma->size,
1027 1.29.2.2 skrll BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1028 1.29.2.2 skrll bus_dmamap_unload(dma->tag, dma->map);
1029 1.29.2.2 skrll bus_dmamem_unmap(dma->tag, dma->vaddr, dma->size);
1030 1.29.2.2 skrll bus_dmamem_free(dma->tag, &dma->seg, 1);
1031 1.29.2.2 skrll dma->vaddr = NULL;
1032 1.29.2.2 skrll }
1033 1.29.2.2 skrll bus_dmamap_destroy(dma->tag, dma->map);
1034 1.29.2.2 skrll dma->map = NULL;
1035 1.29.2.2 skrll }
1036 1.29.2.2 skrll }
1037 1.29.2.2 skrll
1038 1.29.2.2 skrll /* fwmem is used to load firmware onto the card */
1039 1.29.2.2 skrll static int
1040 1.29.2.2 skrll iwm_alloc_fwmem(struct iwm_softc *sc)
1041 1.29.2.2 skrll {
1042 1.29.2.2 skrll /* Must be aligned on a 16-byte boundary. */
1043 1.29.2.2 skrll return iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma,
1044 1.29.2.2 skrll sc->sc_fwdmasegsz, 16);
1045 1.29.2.2 skrll }
1046 1.29.2.2 skrll
1047 1.29.2.2 skrll static void
1048 1.29.2.2 skrll iwm_free_fwmem(struct iwm_softc *sc)
1049 1.29.2.2 skrll {
1050 1.29.2.2 skrll iwm_dma_contig_free(&sc->fw_dma);
1051 1.29.2.2 skrll }
1052 1.29.2.2 skrll
1053 1.29.2.2 skrll /* tx scheduler rings. not used? */
1054 1.29.2.2 skrll static int
1055 1.29.2.2 skrll iwm_alloc_sched(struct iwm_softc *sc)
1056 1.29.2.2 skrll {
1057 1.29.2.2 skrll int rv;
1058 1.29.2.2 skrll
1059 1.29.2.2 skrll /* TX scheduler rings must be aligned on a 1KB boundary. */
1060 1.29.2.2 skrll rv = iwm_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma,
1061 1.29.2.2 skrll __arraycount(sc->txq) * sizeof(struct iwm_agn_scd_bc_tbl), 1024);
1062 1.29.2.2 skrll return rv;
1063 1.29.2.2 skrll }
1064 1.29.2.2 skrll
1065 1.29.2.2 skrll static void
1066 1.29.2.2 skrll iwm_free_sched(struct iwm_softc *sc)
1067 1.29.2.2 skrll {
1068 1.29.2.2 skrll iwm_dma_contig_free(&sc->sched_dma);
1069 1.29.2.2 skrll }
1070 1.29.2.2 skrll
1071 1.29.2.2 skrll /* keep-warm page is used internally by the card. see iwl-fh.h for more info */
1072 1.29.2.2 skrll static int
1073 1.29.2.2 skrll iwm_alloc_kw(struct iwm_softc *sc)
1074 1.29.2.2 skrll {
1075 1.29.2.2 skrll return iwm_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, 4096, 4096);
1076 1.29.2.2 skrll }
1077 1.29.2.2 skrll
1078 1.29.2.2 skrll static void
1079 1.29.2.2 skrll iwm_free_kw(struct iwm_softc *sc)
1080 1.29.2.2 skrll {
1081 1.29.2.2 skrll iwm_dma_contig_free(&sc->kw_dma);
1082 1.29.2.2 skrll }
1083 1.29.2.2 skrll
1084 1.29.2.2 skrll /* interrupt cause table */
1085 1.29.2.2 skrll static int
1086 1.29.2.2 skrll iwm_alloc_ict(struct iwm_softc *sc)
1087 1.29.2.2 skrll {
1088 1.29.2.2 skrll return iwm_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma,
1089 1.29.2.2 skrll IWM_ICT_SIZE, 1<<IWM_ICT_PADDR_SHIFT);
1090 1.29.2.2 skrll }
1091 1.29.2.2 skrll
1092 1.29.2.2 skrll static void
1093 1.29.2.2 skrll iwm_free_ict(struct iwm_softc *sc)
1094 1.29.2.2 skrll {
1095 1.29.2.2 skrll iwm_dma_contig_free(&sc->ict_dma);
1096 1.29.2.2 skrll }
1097 1.29.2.2 skrll
1098 1.29.2.2 skrll static int
1099 1.29.2.2 skrll iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
1100 1.29.2.2 skrll {
1101 1.29.2.2 skrll bus_size_t size;
1102 1.29.2.2 skrll int i, error;
1103 1.29.2.2 skrll
1104 1.29.2.2 skrll ring->cur = 0;
1105 1.29.2.2 skrll
1106 1.29.2.2 skrll /* Allocate RX descriptors (256-byte aligned). */
1107 1.29.2.2 skrll size = IWM_RX_RING_COUNT * sizeof(uint32_t);
1108 1.29.2.2 skrll error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256);
1109 1.29.2.2 skrll if (error != 0) {
1110 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1111 1.29.2.2 skrll "could not allocate RX ring DMA memory\n");
1112 1.29.2.2 skrll goto fail;
1113 1.29.2.2 skrll }
1114 1.29.2.2 skrll ring->desc = ring->desc_dma.vaddr;
1115 1.29.2.2 skrll
1116 1.29.2.2 skrll /* Allocate RX status area (16-byte aligned). */
1117 1.29.2.2 skrll error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma,
1118 1.29.2.2 skrll sizeof(*ring->stat), 16);
1119 1.29.2.2 skrll if (error != 0) {
1120 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1121 1.29.2.2 skrll "could not allocate RX status DMA memory\n");
1122 1.29.2.2 skrll goto fail;
1123 1.29.2.2 skrll }
1124 1.29.2.2 skrll ring->stat = ring->stat_dma.vaddr;
1125 1.29.2.2 skrll
1126 1.29.2.2 skrll /*
1127 1.29.2.2 skrll * Allocate and map RX buffers.
1128 1.29.2.2 skrll */
1129 1.29.2.2 skrll for (i = 0; i < IWM_RX_RING_COUNT; i++) {
1130 1.29.2.2 skrll struct iwm_rx_data *data = &ring->data[i];
1131 1.29.2.2 skrll
1132 1.29.2.2 skrll memset(data, 0, sizeof(*data));
1133 1.29.2.2 skrll error = bus_dmamap_create(sc->sc_dmat, IWM_RBUF_SIZE, 1,
1134 1.29.2.2 skrll IWM_RBUF_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1135 1.29.2.2 skrll &data->map);
1136 1.29.2.2 skrll if (error != 0) {
1137 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1138 1.29.2.2 skrll "could not create RX buf DMA map\n");
1139 1.29.2.2 skrll goto fail;
1140 1.29.2.2 skrll }
1141 1.29.2.2 skrll
1142 1.29.2.2 skrll if ((error = iwm_rx_addbuf(sc, IWM_RBUF_SIZE, i)) != 0) {
1143 1.29.2.2 skrll goto fail;
1144 1.29.2.2 skrll }
1145 1.29.2.2 skrll }
1146 1.29.2.2 skrll return 0;
1147 1.29.2.2 skrll
1148 1.29.2.2 skrll fail: iwm_free_rx_ring(sc, ring);
1149 1.29.2.2 skrll return error;
1150 1.29.2.2 skrll }
1151 1.29.2.2 skrll
1152 1.29.2.2 skrll static void
1153 1.29.2.2 skrll iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
1154 1.29.2.2 skrll {
1155 1.29.2.2 skrll int ntries;
1156 1.29.2.2 skrll
1157 1.29.2.2 skrll if (iwm_nic_lock(sc)) {
1158 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1159 1.29.2.2 skrll for (ntries = 0; ntries < 1000; ntries++) {
1160 1.29.2.2 skrll if (IWM_READ(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG) &
1161 1.29.2.2 skrll IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE)
1162 1.29.2.2 skrll break;
1163 1.29.2.2 skrll DELAY(10);
1164 1.29.2.2 skrll }
1165 1.29.2.2 skrll iwm_nic_unlock(sc);
1166 1.29.2.2 skrll }
1167 1.29.2.2 skrll ring->cur = 0;
1168 1.29.2.2 skrll }
1169 1.29.2.2 skrll
1170 1.29.2.2 skrll static void
1171 1.29.2.2 skrll iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
1172 1.29.2.2 skrll {
1173 1.29.2.2 skrll int i;
1174 1.29.2.2 skrll
1175 1.29.2.2 skrll iwm_dma_contig_free(&ring->desc_dma);
1176 1.29.2.2 skrll iwm_dma_contig_free(&ring->stat_dma);
1177 1.29.2.2 skrll
1178 1.29.2.2 skrll for (i = 0; i < IWM_RX_RING_COUNT; i++) {
1179 1.29.2.2 skrll struct iwm_rx_data *data = &ring->data[i];
1180 1.29.2.2 skrll
1181 1.29.2.2 skrll if (data->m != NULL) {
1182 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
1183 1.29.2.2 skrll data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1184 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, data->map);
1185 1.29.2.2 skrll m_freem(data->m);
1186 1.29.2.2 skrll }
1187 1.29.2.2 skrll if (data->map != NULL)
1188 1.29.2.2 skrll bus_dmamap_destroy(sc->sc_dmat, data->map);
1189 1.29.2.2 skrll }
1190 1.29.2.2 skrll }
1191 1.29.2.2 skrll
1192 1.29.2.2 skrll static int
1193 1.29.2.2 skrll iwm_alloc_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring, int qid)
1194 1.29.2.2 skrll {
1195 1.29.2.2 skrll bus_addr_t paddr;
1196 1.29.2.2 skrll bus_size_t size;
1197 1.29.2.2 skrll int i, error;
1198 1.29.2.2 skrll
1199 1.29.2.2 skrll ring->qid = qid;
1200 1.29.2.2 skrll ring->queued = 0;
1201 1.29.2.2 skrll ring->cur = 0;
1202 1.29.2.2 skrll
1203 1.29.2.2 skrll /* Allocate TX descriptors (256-byte aligned). */
1204 1.29.2.2 skrll size = IWM_TX_RING_COUNT * sizeof (struct iwm_tfd);
1205 1.29.2.2 skrll error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256);
1206 1.29.2.2 skrll if (error != 0) {
1207 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1208 1.29.2.2 skrll "could not allocate TX ring DMA memory\n");
1209 1.29.2.2 skrll goto fail;
1210 1.29.2.2 skrll }
1211 1.29.2.2 skrll ring->desc = ring->desc_dma.vaddr;
1212 1.29.2.2 skrll
1213 1.29.2.2 skrll /*
1214 1.29.2.2 skrll * We only use rings 0 through 9 (4 EDCA + cmd) so there is no need
1215 1.29.2.2 skrll * to allocate commands space for other rings.
1216 1.29.2.2 skrll */
1217 1.29.2.2 skrll if (qid > IWM_MVM_CMD_QUEUE)
1218 1.29.2.2 skrll return 0;
1219 1.29.2.2 skrll
1220 1.29.2.2 skrll size = IWM_TX_RING_COUNT * sizeof(struct iwm_device_cmd);
1221 1.29.2.2 skrll error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, size, 4);
1222 1.29.2.2 skrll if (error != 0) {
1223 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1224 1.29.2.2 skrll "could not allocate TX cmd DMA memory\n");
1225 1.29.2.2 skrll goto fail;
1226 1.29.2.2 skrll }
1227 1.29.2.2 skrll ring->cmd = ring->cmd_dma.vaddr;
1228 1.29.2.2 skrll
1229 1.29.2.2 skrll paddr = ring->cmd_dma.paddr;
1230 1.29.2.2 skrll for (i = 0; i < IWM_TX_RING_COUNT; i++) {
1231 1.29.2.2 skrll struct iwm_tx_data *data = &ring->data[i];
1232 1.29.2.2 skrll
1233 1.29.2.2 skrll data->cmd_paddr = paddr;
1234 1.29.2.2 skrll data->scratch_paddr = paddr + sizeof(struct iwm_cmd_header)
1235 1.29.2.2 skrll + offsetof(struct iwm_tx_cmd, scratch);
1236 1.29.2.2 skrll paddr += sizeof(struct iwm_device_cmd);
1237 1.29.2.2 skrll
1238 1.29.2.2 skrll error = bus_dmamap_create(sc->sc_dmat, IWM_RBUF_SIZE,
1239 1.29.2.3 skrll IWM_NUM_OF_TBS - 2, IWM_RBUF_SIZE, 0, BUS_DMA_NOWAIT,
1240 1.29.2.2 skrll &data->map);
1241 1.29.2.2 skrll if (error != 0) {
1242 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1243 1.29.2.2 skrll "could not create TX buf DMA map\n");
1244 1.29.2.2 skrll goto fail;
1245 1.29.2.2 skrll }
1246 1.29.2.2 skrll }
1247 1.29.2.2 skrll KASSERT(paddr == ring->cmd_dma.paddr + size);
1248 1.29.2.2 skrll return 0;
1249 1.29.2.2 skrll
1250 1.29.2.2 skrll fail: iwm_free_tx_ring(sc, ring);
1251 1.29.2.2 skrll return error;
1252 1.29.2.2 skrll }
1253 1.29.2.2 skrll
1254 1.29.2.2 skrll static void
1255 1.29.2.2 skrll iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
1256 1.29.2.2 skrll {
1257 1.29.2.2 skrll int i;
1258 1.29.2.2 skrll
1259 1.29.2.2 skrll for (i = 0; i < IWM_TX_RING_COUNT; i++) {
1260 1.29.2.2 skrll struct iwm_tx_data *data = &ring->data[i];
1261 1.29.2.2 skrll
1262 1.29.2.2 skrll if (data->m != NULL) {
1263 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
1264 1.29.2.2 skrll data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1265 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, data->map);
1266 1.29.2.2 skrll m_freem(data->m);
1267 1.29.2.2 skrll data->m = NULL;
1268 1.29.2.2 skrll }
1269 1.29.2.2 skrll }
1270 1.29.2.2 skrll /* Clear TX descriptors. */
1271 1.29.2.2 skrll memset(ring->desc, 0, ring->desc_dma.size);
1272 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0,
1273 1.29.2.2 skrll ring->desc_dma.size, BUS_DMASYNC_PREWRITE);
1274 1.29.2.2 skrll sc->qfullmsk &= ~(1 << ring->qid);
1275 1.29.2.2 skrll ring->queued = 0;
1276 1.29.2.2 skrll ring->cur = 0;
1277 1.29.2.2 skrll }
1278 1.29.2.2 skrll
1279 1.29.2.2 skrll static void
1280 1.29.2.2 skrll iwm_free_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
1281 1.29.2.2 skrll {
1282 1.29.2.2 skrll int i;
1283 1.29.2.2 skrll
1284 1.29.2.2 skrll iwm_dma_contig_free(&ring->desc_dma);
1285 1.29.2.2 skrll iwm_dma_contig_free(&ring->cmd_dma);
1286 1.29.2.2 skrll
1287 1.29.2.2 skrll for (i = 0; i < IWM_TX_RING_COUNT; i++) {
1288 1.29.2.2 skrll struct iwm_tx_data *data = &ring->data[i];
1289 1.29.2.2 skrll
1290 1.29.2.2 skrll if (data->m != NULL) {
1291 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
1292 1.29.2.2 skrll data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1293 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, data->map);
1294 1.29.2.2 skrll m_freem(data->m);
1295 1.29.2.2 skrll }
1296 1.29.2.2 skrll if (data->map != NULL)
1297 1.29.2.2 skrll bus_dmamap_destroy(sc->sc_dmat, data->map);
1298 1.29.2.2 skrll }
1299 1.29.2.2 skrll }
1300 1.29.2.2 skrll
1301 1.29.2.2 skrll /*
1302 1.29.2.2 skrll * High-level hardware frobbing routines
1303 1.29.2.2 skrll */
1304 1.29.2.2 skrll
1305 1.29.2.2 skrll static void
1306 1.29.2.2 skrll iwm_enable_rfkill_int(struct iwm_softc *sc)
1307 1.29.2.2 skrll {
1308 1.29.2.2 skrll sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL;
1309 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
1310 1.29.2.2 skrll }
1311 1.29.2.2 skrll
1312 1.29.2.2 skrll static int
1313 1.29.2.2 skrll iwm_check_rfkill(struct iwm_softc *sc)
1314 1.29.2.2 skrll {
1315 1.29.2.2 skrll uint32_t v;
1316 1.29.2.2 skrll int s;
1317 1.29.2.2 skrll int rv;
1318 1.29.2.2 skrll
1319 1.29.2.2 skrll s = splnet();
1320 1.29.2.2 skrll
1321 1.29.2.2 skrll /*
1322 1.29.2.2 skrll * "documentation" is not really helpful here:
1323 1.29.2.2 skrll * 27: HW_RF_KILL_SW
1324 1.29.2.2 skrll * Indicates state of (platform's) hardware RF-Kill switch
1325 1.29.2.2 skrll *
1326 1.29.2.2 skrll * But apparently when it's off, it's on ...
1327 1.29.2.2 skrll */
1328 1.29.2.2 skrll v = IWM_READ(sc, IWM_CSR_GP_CNTRL);
1329 1.29.2.2 skrll rv = (v & IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0;
1330 1.29.2.2 skrll if (rv) {
1331 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_RFKILL;
1332 1.29.2.2 skrll } else {
1333 1.29.2.2 skrll sc->sc_flags &= ~IWM_FLAG_RFKILL;
1334 1.29.2.2 skrll }
1335 1.29.2.2 skrll
1336 1.29.2.2 skrll splx(s);
1337 1.29.2.2 skrll return rv;
1338 1.29.2.2 skrll }
1339 1.29.2.2 skrll
1340 1.29.2.2 skrll static void
1341 1.29.2.2 skrll iwm_enable_interrupts(struct iwm_softc *sc)
1342 1.29.2.2 skrll {
1343 1.29.2.2 skrll sc->sc_intmask = IWM_CSR_INI_SET_MASK;
1344 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
1345 1.29.2.2 skrll }
1346 1.29.2.2 skrll
1347 1.29.2.2 skrll static void
1348 1.29.2.2 skrll iwm_restore_interrupts(struct iwm_softc *sc)
1349 1.29.2.2 skrll {
1350 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
1351 1.29.2.2 skrll }
1352 1.29.2.2 skrll
1353 1.29.2.2 skrll static void
1354 1.29.2.2 skrll iwm_disable_interrupts(struct iwm_softc *sc)
1355 1.29.2.2 skrll {
1356 1.29.2.2 skrll int s = splnet();
1357 1.29.2.2 skrll
1358 1.29.2.2 skrll /* disable interrupts */
1359 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
1360 1.29.2.2 skrll
1361 1.29.2.2 skrll /* acknowledge all interrupts */
1362 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, ~0);
1363 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0);
1364 1.29.2.2 skrll
1365 1.29.2.2 skrll splx(s);
1366 1.29.2.2 skrll }
1367 1.29.2.2 skrll
1368 1.29.2.2 skrll static void
1369 1.29.2.2 skrll iwm_ict_reset(struct iwm_softc *sc)
1370 1.29.2.2 skrll {
1371 1.29.2.2 skrll iwm_disable_interrupts(sc);
1372 1.29.2.2 skrll
1373 1.29.2.2 skrll /* Reset ICT table. */
1374 1.29.2.2 skrll memset(sc->ict_dma.vaddr, 0, IWM_ICT_SIZE);
1375 1.29.2.2 skrll sc->ict_cur = 0;
1376 1.29.2.2 skrll
1377 1.29.2.2 skrll /* Set physical address of ICT table (4KB aligned). */
1378 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG,
1379 1.29.2.2 skrll IWM_CSR_DRAM_INT_TBL_ENABLE
1380 1.29.2.2 skrll | IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK
1381 1.29.2.2 skrll | sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT);
1382 1.29.2.2 skrll
1383 1.29.2.2 skrll /* Switch to ICT interrupt mode in driver. */
1384 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_USE_ICT;
1385 1.29.2.2 skrll
1386 1.29.2.2 skrll /* Re-enable interrupts. */
1387 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, ~0);
1388 1.29.2.2 skrll iwm_enable_interrupts(sc);
1389 1.29.2.2 skrll }
1390 1.29.2.2 skrll
1391 1.29.2.2 skrll #define IWM_HW_READY_TIMEOUT 50
1392 1.29.2.2 skrll static int
1393 1.29.2.2 skrll iwm_set_hw_ready(struct iwm_softc *sc)
1394 1.29.2.2 skrll {
1395 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
1396 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
1397 1.29.2.2 skrll
1398 1.29.2.2 skrll return iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
1399 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
1400 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
1401 1.29.2.2 skrll IWM_HW_READY_TIMEOUT);
1402 1.29.2.2 skrll }
1403 1.29.2.2 skrll #undef IWM_HW_READY_TIMEOUT
1404 1.29.2.2 skrll
1405 1.29.2.2 skrll static int
1406 1.29.2.2 skrll iwm_prepare_card_hw(struct iwm_softc *sc)
1407 1.29.2.2 skrll {
1408 1.29.2.2 skrll int rv = 0;
1409 1.29.2.2 skrll int t = 0;
1410 1.29.2.2 skrll
1411 1.29.2.2 skrll if (iwm_set_hw_ready(sc))
1412 1.29.2.2 skrll goto out;
1413 1.29.2.2 skrll
1414 1.29.2.2 skrll /* If HW is not ready, prepare the conditions to check again */
1415 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
1416 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_PREPARE);
1417 1.29.2.2 skrll
1418 1.29.2.2 skrll do {
1419 1.29.2.2 skrll if (iwm_set_hw_ready(sc))
1420 1.29.2.2 skrll goto out;
1421 1.29.2.2 skrll DELAY(200);
1422 1.29.2.2 skrll t += 200;
1423 1.29.2.2 skrll } while (t < 150000);
1424 1.29.2.2 skrll
1425 1.29.2.2 skrll rv = ETIMEDOUT;
1426 1.29.2.2 skrll
1427 1.29.2.2 skrll out:
1428 1.29.2.2 skrll return rv;
1429 1.29.2.2 skrll }
1430 1.29.2.2 skrll
1431 1.29.2.2 skrll static void
1432 1.29.2.2 skrll iwm_apm_config(struct iwm_softc *sc)
1433 1.29.2.2 skrll {
1434 1.29.2.2 skrll pcireg_t reg;
1435 1.29.2.2 skrll
1436 1.29.2.2 skrll reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
1437 1.29.2.2 skrll sc->sc_cap_off + PCIE_LCSR);
1438 1.29.2.2 skrll if (reg & PCIE_LCSR_ASPM_L1) {
1439 1.29.2.2 skrll /* Um the Linux driver prints "Disabling L0S for this one ... */
1440 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GIO_REG,
1441 1.29.2.2 skrll IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
1442 1.29.2.2 skrll } else {
1443 1.29.2.2 skrll /* ... and "Enabling" here */
1444 1.29.2.2 skrll IWM_CLRBITS(sc, IWM_CSR_GIO_REG,
1445 1.29.2.2 skrll IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
1446 1.29.2.2 skrll }
1447 1.29.2.2 skrll }
1448 1.29.2.2 skrll
1449 1.29.2.2 skrll /*
1450 1.29.2.2 skrll * Start up NIC's basic functionality after it has been reset
1451 1.29.2.2 skrll * (e.g. after platform boot, or shutdown via iwm_pcie_apm_stop())
1452 1.29.2.2 skrll * NOTE: This does not load uCode nor start the embedded processor
1453 1.29.2.2 skrll */
1454 1.29.2.2 skrll static int
1455 1.29.2.2 skrll iwm_apm_init(struct iwm_softc *sc)
1456 1.29.2.2 skrll {
1457 1.29.2.2 skrll int error = 0;
1458 1.29.2.2 skrll
1459 1.29.2.2 skrll DPRINTF(("iwm apm start\n"));
1460 1.29.2.2 skrll
1461 1.29.2.2 skrll /* Disable L0S exit timer (platform NMI Work/Around) */
1462 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
1463 1.29.2.2 skrll IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
1464 1.29.2.2 skrll
1465 1.29.2.2 skrll /*
1466 1.29.2.2 skrll * Disable L0s without affecting L1;
1467 1.29.2.2 skrll * don't wait for ICH L0s (ICH bug W/A)
1468 1.29.2.2 skrll */
1469 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
1470 1.29.2.2 skrll IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
1471 1.29.2.2 skrll
1472 1.29.2.2 skrll /* Set FH wait threshold to maximum (HW error during stress W/A) */
1473 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_DBG_HPET_MEM_REG, IWM_CSR_DBG_HPET_MEM_REG_VAL);
1474 1.29.2.2 skrll
1475 1.29.2.2 skrll /*
1476 1.29.2.2 skrll * Enable HAP INTA (interrupt from management bus) to
1477 1.29.2.2 skrll * wake device's PCI Express link L1a -> L0s
1478 1.29.2.2 skrll */
1479 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
1480 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
1481 1.29.2.2 skrll
1482 1.29.2.2 skrll iwm_apm_config(sc);
1483 1.29.2.2 skrll
1484 1.29.2.2 skrll #if 0 /* not for 7k */
1485 1.29.2.2 skrll /* Configure analog phase-lock-loop before activating to D0A */
1486 1.29.2.2 skrll if (trans->cfg->base_params->pll_cfg_val)
1487 1.29.2.2 skrll IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG,
1488 1.29.2.2 skrll trans->cfg->base_params->pll_cfg_val);
1489 1.29.2.2 skrll #endif
1490 1.29.2.2 skrll
1491 1.29.2.2 skrll /*
1492 1.29.2.2 skrll * Set "initialization complete" bit to move adapter from
1493 1.29.2.2 skrll * D0U* --> D0A* (powered-up active) state.
1494 1.29.2.2 skrll */
1495 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
1496 1.29.2.2 skrll
1497 1.29.2.2 skrll /*
1498 1.29.2.2 skrll * Wait for clock stabilization; once stabilized, access to
1499 1.29.2.2 skrll * device-internal resources is supported, e.g. iwm_write_prph()
1500 1.29.2.2 skrll * and accesses to uCode SRAM.
1501 1.29.2.2 skrll */
1502 1.29.2.2 skrll if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
1503 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
1504 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) {
1505 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
1506 1.29.2.2 skrll "timeout waiting for clock stabilization\n");
1507 1.29.2.2 skrll goto out;
1508 1.29.2.2 skrll }
1509 1.29.2.2 skrll
1510 1.29.2.2 skrll if (sc->host_interrupt_operation_mode) {
1511 1.29.2.2 skrll /*
1512 1.29.2.2 skrll * This is a bit of an abuse - This is needed for 7260 / 3160
1513 1.29.2.2 skrll * only check host_interrupt_operation_mode even if this is
1514 1.29.2.2 skrll * not related to host_interrupt_operation_mode.
1515 1.29.2.2 skrll *
1516 1.29.2.2 skrll * Enable the oscillator to count wake up time for L1 exit. This
1517 1.29.2.2 skrll * consumes slightly more power (100uA) - but allows to be sure
1518 1.29.2.2 skrll * that we wake up from L1 on time.
1519 1.29.2.2 skrll *
1520 1.29.2.2 skrll * This looks weird: read twice the same register, discard the
1521 1.29.2.2 skrll * value, set a bit, and yet again, read that same register
1522 1.29.2.2 skrll * just to discard the value. But that's the way the hardware
1523 1.29.2.2 skrll * seems to like it.
1524 1.29.2.2 skrll */
1525 1.29.2.2 skrll iwm_read_prph(sc, IWM_OSC_CLK);
1526 1.29.2.2 skrll iwm_read_prph(sc, IWM_OSC_CLK);
1527 1.29.2.2 skrll iwm_set_bits_prph(sc, IWM_OSC_CLK, IWM_OSC_CLK_FORCE_CONTROL);
1528 1.29.2.2 skrll iwm_read_prph(sc, IWM_OSC_CLK);
1529 1.29.2.2 skrll iwm_read_prph(sc, IWM_OSC_CLK);
1530 1.29.2.2 skrll }
1531 1.29.2.2 skrll
1532 1.29.2.2 skrll /*
1533 1.29.2.2 skrll * Enable DMA clock and wait for it to stabilize.
1534 1.29.2.2 skrll *
1535 1.29.2.2 skrll * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
1536 1.29.2.2 skrll * do not disable clocks. This preserves any hardware bits already
1537 1.29.2.2 skrll * set by default in "CLK_CTRL_REG" after reset.
1538 1.29.2.2 skrll */
1539 1.29.2.2 skrll iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
1540 1.29.2.2 skrll //kpause("iwmapm", 0, mstohz(20), NULL);
1541 1.29.2.2 skrll DELAY(20);
1542 1.29.2.2 skrll
1543 1.29.2.2 skrll /* Disable L1-Active */
1544 1.29.2.2 skrll iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
1545 1.29.2.2 skrll IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
1546 1.29.2.2 skrll
1547 1.29.2.2 skrll /* Clear the interrupt in APMG if the NIC is in RFKILL */
1548 1.29.2.2 skrll iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
1549 1.29.2.2 skrll IWM_APMG_RTC_INT_STT_RFKILL);
1550 1.29.2.2 skrll
1551 1.29.2.2 skrll out:
1552 1.29.2.2 skrll if (error)
1553 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "apm init error %d\n", error);
1554 1.29.2.2 skrll return error;
1555 1.29.2.2 skrll }
1556 1.29.2.2 skrll
1557 1.29.2.2 skrll /* iwlwifi/pcie/trans.c */
1558 1.29.2.2 skrll static void
1559 1.29.2.2 skrll iwm_apm_stop(struct iwm_softc *sc)
1560 1.29.2.2 skrll {
1561 1.29.2.2 skrll /* stop device's busmaster DMA activity */
1562 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER);
1563 1.29.2.2 skrll
1564 1.29.2.2 skrll if (!iwm_poll_bit(sc, IWM_CSR_RESET,
1565 1.29.2.2 skrll IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED,
1566 1.29.2.2 skrll IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100))
1567 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "timeout waiting for master\n");
1568 1.29.2.2 skrll DPRINTF(("iwm apm stop\n"));
1569 1.29.2.2 skrll }
1570 1.29.2.2 skrll
1571 1.29.2.2 skrll /* iwlwifi pcie/trans.c */
1572 1.29.2.2 skrll static int
1573 1.29.2.2 skrll iwm_start_hw(struct iwm_softc *sc)
1574 1.29.2.2 skrll {
1575 1.29.2.2 skrll int error;
1576 1.29.2.2 skrll
1577 1.29.2.2 skrll if ((error = iwm_prepare_card_hw(sc)) != 0)
1578 1.29.2.2 skrll return error;
1579 1.29.2.2 skrll
1580 1.29.2.2 skrll /* Reset the entire device */
1581 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_RESET,
1582 1.29.2.2 skrll IWM_CSR_RESET_REG_FLAG_SW_RESET |
1583 1.29.2.2 skrll IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
1584 1.29.2.2 skrll DELAY(10);
1585 1.29.2.2 skrll
1586 1.29.2.2 skrll if ((error = iwm_apm_init(sc)) != 0)
1587 1.29.2.2 skrll return error;
1588 1.29.2.2 skrll
1589 1.29.2.2 skrll iwm_enable_rfkill_int(sc);
1590 1.29.2.2 skrll iwm_check_rfkill(sc);
1591 1.29.2.2 skrll
1592 1.29.2.2 skrll return 0;
1593 1.29.2.2 skrll }
1594 1.29.2.2 skrll
1595 1.29.2.2 skrll /* iwlwifi pcie/trans.c */
1596 1.29.2.2 skrll
1597 1.29.2.2 skrll static void
1598 1.29.2.2 skrll iwm_stop_device(struct iwm_softc *sc)
1599 1.29.2.2 skrll {
1600 1.29.2.2 skrll int chnl, ntries;
1601 1.29.2.2 skrll int qid;
1602 1.29.2.2 skrll
1603 1.29.2.2 skrll /* tell the device to stop sending interrupts */
1604 1.29.2.2 skrll iwm_disable_interrupts(sc);
1605 1.29.2.2 skrll
1606 1.29.2.2 skrll /* device going down, Stop using ICT table */
1607 1.29.2.2 skrll sc->sc_flags &= ~IWM_FLAG_USE_ICT;
1608 1.29.2.2 skrll
1609 1.29.2.2 skrll /* stop tx and rx. tx and rx bits, as usual, are from if_iwn */
1610 1.29.2.2 skrll
1611 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_TXFACT, 0);
1612 1.29.2.2 skrll
1613 1.29.2.2 skrll /* Stop all DMA channels. */
1614 1.29.2.2 skrll if (iwm_nic_lock(sc)) {
1615 1.29.2.2 skrll for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) {
1616 1.29.2.2 skrll IWM_WRITE(sc,
1617 1.29.2.2 skrll IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), 0);
1618 1.29.2.2 skrll for (ntries = 0; ntries < 200; ntries++) {
1619 1.29.2.2 skrll uint32_t r;
1620 1.29.2.2 skrll
1621 1.29.2.2 skrll r = IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG);
1622 1.29.2.2 skrll if (r & IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(
1623 1.29.2.2 skrll chnl))
1624 1.29.2.2 skrll break;
1625 1.29.2.2 skrll DELAY(20);
1626 1.29.2.2 skrll }
1627 1.29.2.2 skrll }
1628 1.29.2.2 skrll iwm_nic_unlock(sc);
1629 1.29.2.2 skrll }
1630 1.29.2.2 skrll
1631 1.29.2.2 skrll /* Stop RX ring. */
1632 1.29.2.2 skrll iwm_reset_rx_ring(sc, &sc->rxq);
1633 1.29.2.2 skrll
1634 1.29.2.2 skrll /* Reset all TX rings. */
1635 1.29.2.2 skrll for (qid = 0; qid < __arraycount(sc->txq); qid++)
1636 1.29.2.2 skrll iwm_reset_tx_ring(sc, &sc->txq[qid]);
1637 1.29.2.2 skrll
1638 1.29.2.2 skrll /*
1639 1.29.2.2 skrll * Power-down device's busmaster DMA clocks
1640 1.29.2.2 skrll */
1641 1.29.2.2 skrll iwm_write_prph(sc, IWM_APMG_CLK_DIS_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
1642 1.29.2.2 skrll DELAY(5);
1643 1.29.2.2 skrll
1644 1.29.2.2 skrll /* Make sure (redundant) we've released our request to stay awake */
1645 1.29.2.2 skrll IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
1646 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
1647 1.29.2.2 skrll
1648 1.29.2.2 skrll /* Stop the device, and put it in low power state */
1649 1.29.2.2 skrll iwm_apm_stop(sc);
1650 1.29.2.2 skrll
1651 1.29.2.2 skrll /* Upon stop, the APM issues an interrupt if HW RF kill is set.
1652 1.29.2.2 skrll * Clean again the interrupt here
1653 1.29.2.2 skrll */
1654 1.29.2.2 skrll iwm_disable_interrupts(sc);
1655 1.29.2.2 skrll /* stop and reset the on-board processor */
1656 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
1657 1.29.2.2 skrll
1658 1.29.2.2 skrll /*
1659 1.29.2.2 skrll * Even if we stop the HW, we still want the RF kill
1660 1.29.2.2 skrll * interrupt
1661 1.29.2.2 skrll */
1662 1.29.2.2 skrll iwm_enable_rfkill_int(sc);
1663 1.29.2.2 skrll iwm_check_rfkill(sc);
1664 1.29.2.2 skrll }
1665 1.29.2.2 skrll
1666 1.29.2.2 skrll /* iwlwifi pcie/trans.c (always main power) */
1667 1.29.2.2 skrll static void
1668 1.29.2.2 skrll iwm_set_pwr(struct iwm_softc *sc)
1669 1.29.2.2 skrll {
1670 1.29.2.2 skrll iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
1671 1.29.2.2 skrll IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~IWM_APMG_PS_CTRL_MSK_PWR_SRC);
1672 1.29.2.2 skrll }
1673 1.29.2.2 skrll
1674 1.29.2.2 skrll /* iwlwifi: mvm/ops.c */
1675 1.29.2.2 skrll static void
1676 1.29.2.2 skrll iwm_mvm_nic_config(struct iwm_softc *sc)
1677 1.29.2.2 skrll {
1678 1.29.2.2 skrll uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash;
1679 1.29.2.2 skrll uint32_t reg_val = 0;
1680 1.29.2.2 skrll
1681 1.29.2.2 skrll radio_cfg_type = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_TYPE) >>
1682 1.29.2.2 skrll IWM_FW_PHY_CFG_RADIO_TYPE_POS;
1683 1.29.2.2 skrll radio_cfg_step = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_STEP) >>
1684 1.29.2.2 skrll IWM_FW_PHY_CFG_RADIO_STEP_POS;
1685 1.29.2.2 skrll radio_cfg_dash = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_DASH) >>
1686 1.29.2.2 skrll IWM_FW_PHY_CFG_RADIO_DASH_POS;
1687 1.29.2.2 skrll
1688 1.29.2.2 skrll /* SKU control */
1689 1.29.2.2 skrll reg_val |= IWM_CSR_HW_REV_STEP(sc->sc_hw_rev) <<
1690 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP;
1691 1.29.2.2 skrll reg_val |= IWM_CSR_HW_REV_DASH(sc->sc_hw_rev) <<
1692 1.29.2.2 skrll IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH;
1693 1.29.2.2 skrll
1694 1.29.2.2 skrll /* radio configuration */
1695 1.29.2.2 skrll reg_val |= radio_cfg_type << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE;
1696 1.29.2.2 skrll reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP;
1697 1.29.2.2 skrll reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
1698 1.29.2.2 skrll
1699 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, reg_val);
1700 1.29.2.2 skrll
1701 1.29.2.2 skrll DPRINTF(("Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
1702 1.29.2.2 skrll radio_cfg_step, radio_cfg_dash));
1703 1.29.2.2 skrll
1704 1.29.2.2 skrll /*
1705 1.29.2.2 skrll * W/A : NIC is stuck in a reset state after Early PCIe power off
1706 1.29.2.2 skrll * (PCIe power is lost before PERST# is asserted), causing ME FW
1707 1.29.2.2 skrll * to lose ownership and not being able to obtain it back.
1708 1.29.2.2 skrll */
1709 1.29.2.2 skrll iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
1710 1.29.2.2 skrll IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
1711 1.29.2.2 skrll ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
1712 1.29.2.2 skrll }
1713 1.29.2.2 skrll
1714 1.29.2.2 skrll static int
1715 1.29.2.2 skrll iwm_nic_rx_init(struct iwm_softc *sc)
1716 1.29.2.2 skrll {
1717 1.29.2.2 skrll if (!iwm_nic_lock(sc))
1718 1.29.2.2 skrll return EBUSY;
1719 1.29.2.2 skrll
1720 1.29.2.2 skrll /*
1721 1.29.2.2 skrll * Initialize RX ring. This is from the iwn driver.
1722 1.29.2.2 skrll */
1723 1.29.2.2 skrll memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat));
1724 1.29.2.2 skrll
1725 1.29.2.2 skrll /* stop DMA */
1726 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
1727 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
1728 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
1729 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RDPTR, 0);
1730 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
1731 1.29.2.2 skrll
1732 1.29.2.2 skrll /* Set physical address of RX ring (256-byte aligned). */
1733 1.29.2.2 skrll IWM_WRITE(sc,
1734 1.29.2.2 skrll IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, sc->rxq.desc_dma.paddr >> 8);
1735 1.29.2.2 skrll
1736 1.29.2.2 skrll /* Set physical address of RX status (16-byte aligned). */
1737 1.29.2.2 skrll IWM_WRITE(sc,
1738 1.29.2.2 skrll IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4);
1739 1.29.2.2 skrll
1740 1.29.2.2 skrll /* Enable RX. */
1741 1.29.2.2 skrll /*
1742 1.29.2.2 skrll * Note: Linux driver also sets this:
1743 1.29.2.2 skrll * (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
1744 1.29.2.2 skrll *
1745 1.29.2.2 skrll * It causes weird behavior. YMMV.
1746 1.29.2.2 skrll */
1747 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG,
1748 1.29.2.2 skrll IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
1749 1.29.2.2 skrll IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | /* HW bug */
1750 1.29.2.2 skrll IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
1751 1.29.2.2 skrll IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
1752 1.29.2.2 skrll IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS);
1753 1.29.2.2 skrll
1754 1.29.2.2 skrll IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF);
1755 1.29.2.2 skrll
1756 1.29.2.2 skrll /* W/A for interrupt coalescing bug in 7260 and 3160 */
1757 1.29.2.2 skrll if (sc->host_interrupt_operation_mode)
1758 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_OPER_MODE);
1759 1.29.2.2 skrll
1760 1.29.2.2 skrll /*
1761 1.29.2.2 skrll * Thus sayeth el jefe (iwlwifi) via a comment:
1762 1.29.2.2 skrll *
1763 1.29.2.2 skrll * This value should initially be 0 (before preparing any
1764 1.29.2.2 skrll * RBs), should be 8 after preparing the first 8 RBs (for example)
1765 1.29.2.2 skrll */
1766 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8);
1767 1.29.2.2 skrll
1768 1.29.2.2 skrll iwm_nic_unlock(sc);
1769 1.29.2.2 skrll
1770 1.29.2.2 skrll return 0;
1771 1.29.2.2 skrll }
1772 1.29.2.2 skrll
1773 1.29.2.2 skrll static int
1774 1.29.2.2 skrll iwm_nic_tx_init(struct iwm_softc *sc)
1775 1.29.2.2 skrll {
1776 1.29.2.2 skrll int qid;
1777 1.29.2.2 skrll
1778 1.29.2.2 skrll if (!iwm_nic_lock(sc))
1779 1.29.2.2 skrll return EBUSY;
1780 1.29.2.2 skrll
1781 1.29.2.2 skrll /* Deactivate TX scheduler. */
1782 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_TXFACT, 0);
1783 1.29.2.2 skrll
1784 1.29.2.2 skrll /* Set physical address of "keep warm" page (16-byte aligned). */
1785 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_KW_MEM_ADDR_REG, sc->kw_dma.paddr >> 4);
1786 1.29.2.2 skrll
1787 1.29.2.2 skrll /* Initialize TX rings. */
1788 1.29.2.2 skrll for (qid = 0; qid < __arraycount(sc->txq); qid++) {
1789 1.29.2.2 skrll struct iwm_tx_ring *txq = &sc->txq[qid];
1790 1.29.2.2 skrll
1791 1.29.2.2 skrll /* Set physical address of TX ring (256-byte aligned). */
1792 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_MEM_CBBC_QUEUE(qid),
1793 1.29.2.2 skrll txq->desc_dma.paddr >> 8);
1794 1.29.2.2 skrll DPRINTF(("loading ring %d descriptors (%p) at %"PRIxMAX"\n",
1795 1.29.2.2 skrll qid, txq->desc, (uintmax_t)(txq->desc_dma.paddr >> 8)));
1796 1.29.2.2 skrll }
1797 1.29.2.2 skrll iwm_nic_unlock(sc);
1798 1.29.2.2 skrll
1799 1.29.2.2 skrll return 0;
1800 1.29.2.2 skrll }
1801 1.29.2.2 skrll
1802 1.29.2.2 skrll static int
1803 1.29.2.2 skrll iwm_nic_init(struct iwm_softc *sc)
1804 1.29.2.2 skrll {
1805 1.29.2.2 skrll int error;
1806 1.29.2.2 skrll
1807 1.29.2.2 skrll iwm_apm_init(sc);
1808 1.29.2.2 skrll iwm_set_pwr(sc);
1809 1.29.2.2 skrll
1810 1.29.2.2 skrll iwm_mvm_nic_config(sc);
1811 1.29.2.2 skrll
1812 1.29.2.2 skrll if ((error = iwm_nic_rx_init(sc)) != 0)
1813 1.29.2.2 skrll return error;
1814 1.29.2.2 skrll
1815 1.29.2.2 skrll /*
1816 1.29.2.2 skrll * Ditto for TX, from iwn
1817 1.29.2.2 skrll */
1818 1.29.2.2 skrll if ((error = iwm_nic_tx_init(sc)) != 0)
1819 1.29.2.2 skrll return error;
1820 1.29.2.2 skrll
1821 1.29.2.2 skrll DPRINTF(("shadow registers enabled\n"));
1822 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_MAC_SHADOW_REG_CTRL, 0x800fffff);
1823 1.29.2.2 skrll
1824 1.29.2.2 skrll return 0;
1825 1.29.2.2 skrll }
1826 1.29.2.2 skrll
1827 1.29.2.2 skrll #if 0
1828 1.29.2.2 skrll enum iwm_mvm_tx_fifo {
1829 1.29.2.2 skrll IWM_MVM_TX_FIFO_BK = 0,
1830 1.29.2.2 skrll IWM_MVM_TX_FIFO_BE,
1831 1.29.2.2 skrll IWM_MVM_TX_FIFO_VI,
1832 1.29.2.2 skrll IWM_MVM_TX_FIFO_VO,
1833 1.29.2.2 skrll IWM_MVM_TX_FIFO_MCAST = 5,
1834 1.29.2.2 skrll };
1835 1.29.2.2 skrll
1836 1.29.2.2 skrll static const uint8_t iwm_mvm_ac_to_tx_fifo[] = {
1837 1.29.2.2 skrll IWM_MVM_TX_FIFO_VO,
1838 1.29.2.2 skrll IWM_MVM_TX_FIFO_VI,
1839 1.29.2.2 skrll IWM_MVM_TX_FIFO_BE,
1840 1.29.2.2 skrll IWM_MVM_TX_FIFO_BK,
1841 1.29.2.2 skrll };
1842 1.29.2.2 skrll #endif
1843 1.29.2.2 skrll
1844 1.29.2.2 skrll static void
1845 1.29.2.2 skrll iwm_enable_txq(struct iwm_softc *sc, int qid, int fifo)
1846 1.29.2.2 skrll {
1847 1.29.2.2 skrll if (!iwm_nic_lock(sc)) {
1848 1.29.2.2 skrll DPRINTF(("%s: cannot enable txq %d\n", DEVNAME(sc), qid));
1849 1.29.2.2 skrll return; /* XXX return EBUSY */
1850 1.29.2.2 skrll }
1851 1.29.2.2 skrll
1852 1.29.2.2 skrll /* unactivate before configuration */
1853 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
1854 1.29.2.2 skrll (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
1855 1.29.2.2 skrll | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
1856 1.29.2.2 skrll
1857 1.29.2.2 skrll if (qid != IWM_MVM_CMD_QUEUE) {
1858 1.29.2.2 skrll iwm_set_bits_prph(sc, IWM_SCD_QUEUECHAIN_SEL, (1 << qid));
1859 1.29.2.2 skrll }
1860 1.29.2.2 skrll
1861 1.29.2.2 skrll iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
1862 1.29.2.2 skrll
1863 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
1864 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
1865 1.29.2.2 skrll
1866 1.29.2.2 skrll iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0);
1867 1.29.2.2 skrll /* Set scheduler window size and frame limit. */
1868 1.29.2.2 skrll iwm_write_mem32(sc,
1869 1.29.2.2 skrll sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
1870 1.29.2.2 skrll sizeof(uint32_t),
1871 1.29.2.2 skrll ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
1872 1.29.2.2 skrll IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
1873 1.29.2.2 skrll ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
1874 1.29.2.2 skrll IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
1875 1.29.2.2 skrll
1876 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
1877 1.29.2.2 skrll (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
1878 1.29.2.2 skrll (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
1879 1.29.2.2 skrll (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
1880 1.29.2.2 skrll IWM_SCD_QUEUE_STTS_REG_MSK);
1881 1.29.2.2 skrll
1882 1.29.2.2 skrll iwm_nic_unlock(sc);
1883 1.29.2.2 skrll
1884 1.29.2.2 skrll DPRINTF(("enabled txq %d FIFO %d\n", qid, fifo));
1885 1.29.2.2 skrll }
1886 1.29.2.2 skrll
1887 1.29.2.2 skrll static int
1888 1.29.2.2 skrll iwm_post_alive(struct iwm_softc *sc)
1889 1.29.2.2 skrll {
1890 1.29.2.2 skrll int nwords;
1891 1.29.2.2 skrll int error, chnl;
1892 1.29.2.2 skrll
1893 1.29.2.2 skrll if (!iwm_nic_lock(sc))
1894 1.29.2.2 skrll return EBUSY;
1895 1.29.2.2 skrll
1896 1.29.2.2 skrll if (sc->sched_base != iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR)) {
1897 1.29.2.2 skrll DPRINTF(("%s: sched addr mismatch\n", DEVNAME(sc)));
1898 1.29.2.2 skrll error = EINVAL;
1899 1.29.2.2 skrll goto out;
1900 1.29.2.2 skrll }
1901 1.29.2.2 skrll
1902 1.29.2.2 skrll iwm_ict_reset(sc);
1903 1.29.2.2 skrll
1904 1.29.2.2 skrll /* Clear TX scheduler state in SRAM. */
1905 1.29.2.2 skrll nwords = (IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND -
1906 1.29.2.2 skrll IWM_SCD_CONTEXT_MEM_LOWER_BOUND)
1907 1.29.2.2 skrll / sizeof(uint32_t);
1908 1.29.2.2 skrll error = iwm_write_mem(sc,
1909 1.29.2.2 skrll sc->sched_base + IWM_SCD_CONTEXT_MEM_LOWER_BOUND,
1910 1.29.2.2 skrll NULL, nwords);
1911 1.29.2.2 skrll if (error)
1912 1.29.2.2 skrll goto out;
1913 1.29.2.2 skrll
1914 1.29.2.2 skrll /* Set physical address of TX scheduler rings (1KB aligned). */
1915 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_DRAM_BASE_ADDR, sc->sched_dma.paddr >> 10);
1916 1.29.2.2 skrll
1917 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_CHAINEXT_EN, 0);
1918 1.29.2.2 skrll
1919 1.29.2.2 skrll /* enable command channel */
1920 1.29.2.2 skrll iwm_enable_txq(sc, IWM_MVM_CMD_QUEUE, 7);
1921 1.29.2.2 skrll
1922 1.29.2.2 skrll iwm_write_prph(sc, IWM_SCD_TXFACT, 0xff);
1923 1.29.2.2 skrll
1924 1.29.2.2 skrll /* Enable DMA channels. */
1925 1.29.2.2 skrll for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) {
1926 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl),
1927 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
1928 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
1929 1.29.2.2 skrll }
1930 1.29.2.2 skrll
1931 1.29.2.2 skrll IWM_SETBITS(sc, IWM_FH_TX_CHICKEN_BITS_REG,
1932 1.29.2.2 skrll IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
1933 1.29.2.2 skrll
1934 1.29.2.2 skrll /* Enable L1-Active */
1935 1.29.2.2 skrll iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
1936 1.29.2.2 skrll IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
1937 1.29.2.2 skrll
1938 1.29.2.2 skrll out:
1939 1.29.2.2 skrll iwm_nic_unlock(sc);
1940 1.29.2.2 skrll return error;
1941 1.29.2.2 skrll }
1942 1.29.2.2 skrll
1943 1.29.2.2 skrll /*
1944 1.29.2.2 skrll * PHY db
1945 1.29.2.2 skrll * iwlwifi/iwl-phy-db.c
1946 1.29.2.2 skrll */
1947 1.29.2.2 skrll
1948 1.29.2.2 skrll /*
1949 1.29.2.2 skrll * BEGIN iwl-phy-db.c
1950 1.29.2.2 skrll */
1951 1.29.2.2 skrll
1952 1.29.2.2 skrll enum iwm_phy_db_section_type {
1953 1.29.2.2 skrll IWM_PHY_DB_CFG = 1,
1954 1.29.2.2 skrll IWM_PHY_DB_CALIB_NCH,
1955 1.29.2.2 skrll IWM_PHY_DB_UNUSED,
1956 1.29.2.2 skrll IWM_PHY_DB_CALIB_CHG_PAPD,
1957 1.29.2.2 skrll IWM_PHY_DB_CALIB_CHG_TXP,
1958 1.29.2.2 skrll IWM_PHY_DB_MAX
1959 1.29.2.2 skrll };
1960 1.29.2.2 skrll
1961 1.29.2.2 skrll #define IWM_PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */
1962 1.29.2.2 skrll
1963 1.29.2.2 skrll /*
1964 1.29.2.2 skrll * phy db - configure operational ucode
1965 1.29.2.2 skrll */
1966 1.29.2.2 skrll struct iwm_phy_db_cmd {
1967 1.29.2.2 skrll uint16_t type;
1968 1.29.2.2 skrll uint16_t length;
1969 1.29.2.2 skrll uint8_t data[];
1970 1.29.2.2 skrll } __packed;
1971 1.29.2.2 skrll
1972 1.29.2.2 skrll /* for parsing of tx power channel group data that comes from the firmware*/
1973 1.29.2.2 skrll struct iwm_phy_db_chg_txp {
1974 1.29.2.2 skrll uint32_t space;
1975 1.29.2.2 skrll uint16_t max_channel_idx;
1976 1.29.2.2 skrll } __packed;
1977 1.29.2.2 skrll
1978 1.29.2.2 skrll /*
1979 1.29.2.2 skrll * phy db - Receive phy db chunk after calibrations
1980 1.29.2.2 skrll */
1981 1.29.2.2 skrll struct iwm_calib_res_notif_phy_db {
1982 1.29.2.2 skrll uint16_t type;
1983 1.29.2.2 skrll uint16_t length;
1984 1.29.2.2 skrll uint8_t data[];
1985 1.29.2.2 skrll } __packed;
1986 1.29.2.2 skrll
1987 1.29.2.2 skrll /*
1988 1.29.2.2 skrll * get phy db section: returns a pointer to a phy db section specified by
1989 1.29.2.2 skrll * type and channel group id.
1990 1.29.2.2 skrll */
1991 1.29.2.2 skrll static struct iwm_phy_db_entry *
1992 1.29.2.2 skrll iwm_phy_db_get_section(struct iwm_softc *sc,
1993 1.29.2.2 skrll enum iwm_phy_db_section_type type, uint16_t chg_id)
1994 1.29.2.2 skrll {
1995 1.29.2.2 skrll struct iwm_phy_db *phy_db = &sc->sc_phy_db;
1996 1.29.2.2 skrll
1997 1.29.2.2 skrll if (type >= IWM_PHY_DB_MAX)
1998 1.29.2.2 skrll return NULL;
1999 1.29.2.2 skrll
2000 1.29.2.2 skrll switch (type) {
2001 1.29.2.2 skrll case IWM_PHY_DB_CFG:
2002 1.29.2.2 skrll return &phy_db->cfg;
2003 1.29.2.2 skrll case IWM_PHY_DB_CALIB_NCH:
2004 1.29.2.2 skrll return &phy_db->calib_nch;
2005 1.29.2.2 skrll case IWM_PHY_DB_CALIB_CHG_PAPD:
2006 1.29.2.2 skrll if (chg_id >= IWM_NUM_PAPD_CH_GROUPS)
2007 1.29.2.2 skrll return NULL;
2008 1.29.2.2 skrll return &phy_db->calib_ch_group_papd[chg_id];
2009 1.29.2.2 skrll case IWM_PHY_DB_CALIB_CHG_TXP:
2010 1.29.2.2 skrll if (chg_id >= IWM_NUM_TXP_CH_GROUPS)
2011 1.29.2.2 skrll return NULL;
2012 1.29.2.2 skrll return &phy_db->calib_ch_group_txp[chg_id];
2013 1.29.2.2 skrll default:
2014 1.29.2.2 skrll return NULL;
2015 1.29.2.2 skrll }
2016 1.29.2.2 skrll return NULL;
2017 1.29.2.2 skrll }
2018 1.29.2.2 skrll
2019 1.29.2.2 skrll static int
2020 1.29.2.2 skrll iwm_phy_db_set_section(struct iwm_softc *sc,
2021 1.29.2.2 skrll struct iwm_calib_res_notif_phy_db *phy_db_notif, uint16_t size)
2022 1.29.2.2 skrll {
2023 1.29.2.2 skrll enum iwm_phy_db_section_type type = le16toh(phy_db_notif->type);
2024 1.29.2.2 skrll struct iwm_phy_db_entry *entry;
2025 1.29.2.2 skrll uint16_t chg_id = 0;
2026 1.29.2.2 skrll
2027 1.29.2.2 skrll if (type == IWM_PHY_DB_CALIB_CHG_PAPD ||
2028 1.29.2.2 skrll type == IWM_PHY_DB_CALIB_CHG_TXP)
2029 1.29.2.2 skrll chg_id = le16toh(*(uint16_t *)phy_db_notif->data);
2030 1.29.2.2 skrll
2031 1.29.2.2 skrll entry = iwm_phy_db_get_section(sc, type, chg_id);
2032 1.29.2.2 skrll if (!entry)
2033 1.29.2.2 skrll return EINVAL;
2034 1.29.2.2 skrll
2035 1.29.2.2 skrll if (entry->data)
2036 1.29.2.2 skrll kmem_intr_free(entry->data, entry->size);
2037 1.29.2.2 skrll entry->data = kmem_intr_alloc(size, KM_NOSLEEP);
2038 1.29.2.2 skrll if (!entry->data) {
2039 1.29.2.2 skrll entry->size = 0;
2040 1.29.2.2 skrll return ENOMEM;
2041 1.29.2.2 skrll }
2042 1.29.2.2 skrll memcpy(entry->data, phy_db_notif->data, size);
2043 1.29.2.2 skrll entry->size = size;
2044 1.29.2.2 skrll
2045 1.29.2.2 skrll DPRINTFN(10, ("%s(%d): [PHYDB]SET: Type %d, Size: %d, data: %p\n",
2046 1.29.2.2 skrll __func__, __LINE__, type, size, entry->data));
2047 1.29.2.2 skrll
2048 1.29.2.2 skrll return 0;
2049 1.29.2.2 skrll }
2050 1.29.2.2 skrll
2051 1.29.2.2 skrll static int
2052 1.29.2.2 skrll iwm_is_valid_channel(uint16_t ch_id)
2053 1.29.2.2 skrll {
2054 1.29.2.2 skrll if (ch_id <= 14 ||
2055 1.29.2.2 skrll (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) ||
2056 1.29.2.2 skrll (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) ||
2057 1.29.2.2 skrll (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1))
2058 1.29.2.2 skrll return 1;
2059 1.29.2.2 skrll return 0;
2060 1.29.2.2 skrll }
2061 1.29.2.2 skrll
2062 1.29.2.2 skrll static uint8_t
2063 1.29.2.2 skrll iwm_ch_id_to_ch_index(uint16_t ch_id)
2064 1.29.2.2 skrll {
2065 1.29.2.2 skrll if (!iwm_is_valid_channel(ch_id))
2066 1.29.2.2 skrll return 0xff;
2067 1.29.2.2 skrll
2068 1.29.2.2 skrll if (ch_id <= 14)
2069 1.29.2.2 skrll return ch_id - 1;
2070 1.29.2.2 skrll if (ch_id <= 64)
2071 1.29.2.2 skrll return (ch_id + 20) / 4;
2072 1.29.2.2 skrll if (ch_id <= 140)
2073 1.29.2.2 skrll return (ch_id - 12) / 4;
2074 1.29.2.2 skrll return (ch_id - 13) / 4;
2075 1.29.2.2 skrll }
2076 1.29.2.2 skrll
2077 1.29.2.2 skrll
2078 1.29.2.2 skrll static uint16_t
2079 1.29.2.2 skrll iwm_channel_id_to_papd(uint16_t ch_id)
2080 1.29.2.2 skrll {
2081 1.29.2.2 skrll if (!iwm_is_valid_channel(ch_id))
2082 1.29.2.2 skrll return 0xff;
2083 1.29.2.2 skrll
2084 1.29.2.2 skrll if (1 <= ch_id && ch_id <= 14)
2085 1.29.2.2 skrll return 0;
2086 1.29.2.2 skrll if (36 <= ch_id && ch_id <= 64)
2087 1.29.2.2 skrll return 1;
2088 1.29.2.2 skrll if (100 <= ch_id && ch_id <= 140)
2089 1.29.2.2 skrll return 2;
2090 1.29.2.2 skrll return 3;
2091 1.29.2.2 skrll }
2092 1.29.2.2 skrll
2093 1.29.2.2 skrll static uint16_t
2094 1.29.2.2 skrll iwm_channel_id_to_txp(struct iwm_softc *sc, uint16_t ch_id)
2095 1.29.2.2 skrll {
2096 1.29.2.2 skrll struct iwm_phy_db *phy_db = &sc->sc_phy_db;
2097 1.29.2.2 skrll struct iwm_phy_db_chg_txp *txp_chg;
2098 1.29.2.2 skrll int i;
2099 1.29.2.2 skrll uint8_t ch_index = iwm_ch_id_to_ch_index(ch_id);
2100 1.29.2.2 skrll
2101 1.29.2.2 skrll if (ch_index == 0xff)
2102 1.29.2.2 skrll return 0xff;
2103 1.29.2.2 skrll
2104 1.29.2.2 skrll for (i = 0; i < IWM_NUM_TXP_CH_GROUPS; i++) {
2105 1.29.2.2 skrll txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
2106 1.29.2.2 skrll if (!txp_chg)
2107 1.29.2.2 skrll return 0xff;
2108 1.29.2.2 skrll /*
2109 1.29.2.2 skrll * Looking for the first channel group that its max channel is
2110 1.29.2.2 skrll * higher then wanted channel.
2111 1.29.2.2 skrll */
2112 1.29.2.2 skrll if (le16toh(txp_chg->max_channel_idx) >= ch_index)
2113 1.29.2.2 skrll return i;
2114 1.29.2.2 skrll }
2115 1.29.2.2 skrll return 0xff;
2116 1.29.2.2 skrll }
2117 1.29.2.2 skrll
2118 1.29.2.2 skrll static int
2119 1.29.2.2 skrll iwm_phy_db_get_section_data(struct iwm_softc *sc,
2120 1.29.2.2 skrll uint32_t type, uint8_t **data, uint16_t *size, uint16_t ch_id)
2121 1.29.2.2 skrll {
2122 1.29.2.2 skrll struct iwm_phy_db_entry *entry;
2123 1.29.2.2 skrll uint16_t ch_group_id = 0;
2124 1.29.2.2 skrll
2125 1.29.2.2 skrll /* find wanted channel group */
2126 1.29.2.2 skrll if (type == IWM_PHY_DB_CALIB_CHG_PAPD)
2127 1.29.2.2 skrll ch_group_id = iwm_channel_id_to_papd(ch_id);
2128 1.29.2.2 skrll else if (type == IWM_PHY_DB_CALIB_CHG_TXP)
2129 1.29.2.2 skrll ch_group_id = iwm_channel_id_to_txp(sc, ch_id);
2130 1.29.2.2 skrll
2131 1.29.2.2 skrll entry = iwm_phy_db_get_section(sc, type, ch_group_id);
2132 1.29.2.2 skrll if (!entry)
2133 1.29.2.2 skrll return EINVAL;
2134 1.29.2.2 skrll
2135 1.29.2.2 skrll *data = entry->data;
2136 1.29.2.2 skrll *size = entry->size;
2137 1.29.2.2 skrll
2138 1.29.2.2 skrll DPRINTFN(10, ("%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
2139 1.29.2.2 skrll __func__, __LINE__, type, *size));
2140 1.29.2.2 skrll
2141 1.29.2.2 skrll return 0;
2142 1.29.2.2 skrll }
2143 1.29.2.2 skrll
2144 1.29.2.2 skrll static int
2145 1.29.2.2 skrll iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type,
2146 1.29.2.2 skrll uint16_t length, void *data)
2147 1.29.2.2 skrll {
2148 1.29.2.2 skrll struct iwm_phy_db_cmd phy_db_cmd;
2149 1.29.2.2 skrll struct iwm_host_cmd cmd = {
2150 1.29.2.2 skrll .id = IWM_PHY_DB_CMD,
2151 1.29.2.2 skrll .flags = IWM_CMD_SYNC,
2152 1.29.2.2 skrll };
2153 1.29.2.2 skrll
2154 1.29.2.2 skrll DPRINTFN(10, ("Sending PHY-DB hcmd of type %d, of length %d\n",
2155 1.29.2.2 skrll type, length));
2156 1.29.2.2 skrll
2157 1.29.2.2 skrll /* Set phy db cmd variables */
2158 1.29.2.2 skrll phy_db_cmd.type = le16toh(type);
2159 1.29.2.2 skrll phy_db_cmd.length = le16toh(length);
2160 1.29.2.2 skrll
2161 1.29.2.2 skrll /* Set hcmd variables */
2162 1.29.2.2 skrll cmd.data[0] = &phy_db_cmd;
2163 1.29.2.2 skrll cmd.len[0] = sizeof(struct iwm_phy_db_cmd);
2164 1.29.2.2 skrll cmd.data[1] = data;
2165 1.29.2.2 skrll cmd.len[1] = length;
2166 1.29.2.2 skrll cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY;
2167 1.29.2.2 skrll
2168 1.29.2.2 skrll return iwm_send_cmd(sc, &cmd);
2169 1.29.2.2 skrll }
2170 1.29.2.2 skrll
2171 1.29.2.2 skrll static int
2172 1.29.2.2 skrll iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc,
2173 1.29.2.2 skrll enum iwm_phy_db_section_type type, uint8_t max_ch_groups)
2174 1.29.2.2 skrll {
2175 1.29.2.2 skrll uint16_t i;
2176 1.29.2.2 skrll int err;
2177 1.29.2.2 skrll struct iwm_phy_db_entry *entry;
2178 1.29.2.2 skrll
2179 1.29.2.2 skrll /* Send all the channel-specific groups to operational fw */
2180 1.29.2.2 skrll for (i = 0; i < max_ch_groups; i++) {
2181 1.29.2.2 skrll entry = iwm_phy_db_get_section(sc, type, i);
2182 1.29.2.2 skrll if (!entry)
2183 1.29.2.2 skrll return EINVAL;
2184 1.29.2.2 skrll
2185 1.29.2.2 skrll if (!entry->size)
2186 1.29.2.2 skrll continue;
2187 1.29.2.2 skrll
2188 1.29.2.2 skrll /* Send the requested PHY DB section */
2189 1.29.2.2 skrll err = iwm_send_phy_db_cmd(sc, type, entry->size, entry->data);
2190 1.29.2.2 skrll if (err) {
2191 1.29.2.2 skrll DPRINTF(("%s: Can't SEND phy_db section %d (%d), "
2192 1.29.2.2 skrll "err %d\n", DEVNAME(sc), type, i, err));
2193 1.29.2.2 skrll return err;
2194 1.29.2.2 skrll }
2195 1.29.2.2 skrll
2196 1.29.2.2 skrll DPRINTFN(10, ("Sent PHY_DB HCMD, type = %d num = %d\n", type, i));
2197 1.29.2.2 skrll }
2198 1.29.2.2 skrll
2199 1.29.2.2 skrll return 0;
2200 1.29.2.2 skrll }
2201 1.29.2.2 skrll
2202 1.29.2.2 skrll static int
2203 1.29.2.2 skrll iwm_send_phy_db_data(struct iwm_softc *sc)
2204 1.29.2.2 skrll {
2205 1.29.2.2 skrll uint8_t *data = NULL;
2206 1.29.2.2 skrll uint16_t size = 0;
2207 1.29.2.2 skrll int err;
2208 1.29.2.2 skrll
2209 1.29.2.2 skrll DPRINTF(("Sending phy db data and configuration to runtime image\n"));
2210 1.29.2.2 skrll
2211 1.29.2.2 skrll /* Send PHY DB CFG section */
2212 1.29.2.2 skrll err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CFG, &data, &size, 0);
2213 1.29.2.2 skrll if (err) {
2214 1.29.2.2 skrll DPRINTF(("%s: Cannot get Phy DB cfg section, %d\n",
2215 1.29.2.2 skrll DEVNAME(sc), err));
2216 1.29.2.2 skrll return err;
2217 1.29.2.2 skrll }
2218 1.29.2.2 skrll
2219 1.29.2.2 skrll err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CFG, size, data);
2220 1.29.2.2 skrll if (err) {
2221 1.29.2.2 skrll DPRINTF(("%s: Cannot send HCMD of Phy DB cfg section, %d\n",
2222 1.29.2.2 skrll DEVNAME(sc), err));
2223 1.29.2.2 skrll return err;
2224 1.29.2.2 skrll }
2225 1.29.2.2 skrll
2226 1.29.2.2 skrll err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CALIB_NCH,
2227 1.29.2.2 skrll &data, &size, 0);
2228 1.29.2.2 skrll if (err) {
2229 1.29.2.2 skrll DPRINTF(("%s: Cannot get Phy DB non specific channel section, "
2230 1.29.2.2 skrll "%d\n", DEVNAME(sc), err));
2231 1.29.2.2 skrll return err;
2232 1.29.2.2 skrll }
2233 1.29.2.2 skrll
2234 1.29.2.2 skrll err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CALIB_NCH, size, data);
2235 1.29.2.2 skrll if (err) {
2236 1.29.2.2 skrll DPRINTF(("%s: Cannot send HCMD of Phy DB non specific channel "
2237 1.29.2.2 skrll "sect, %d\n", DEVNAME(sc), err));
2238 1.29.2.2 skrll return err;
2239 1.29.2.2 skrll }
2240 1.29.2.2 skrll
2241 1.29.2.2 skrll /* Send all the TXP channel specific data */
2242 1.29.2.2 skrll err = iwm_phy_db_send_all_channel_groups(sc,
2243 1.29.2.2 skrll IWM_PHY_DB_CALIB_CHG_PAPD, IWM_NUM_PAPD_CH_GROUPS);
2244 1.29.2.2 skrll if (err) {
2245 1.29.2.2 skrll DPRINTF(("%s: Cannot send channel specific PAPD groups, %d\n",
2246 1.29.2.2 skrll DEVNAME(sc), err));
2247 1.29.2.2 skrll return err;
2248 1.29.2.2 skrll }
2249 1.29.2.2 skrll
2250 1.29.2.2 skrll /* Send all the TXP channel specific data */
2251 1.29.2.2 skrll err = iwm_phy_db_send_all_channel_groups(sc,
2252 1.29.2.2 skrll IWM_PHY_DB_CALIB_CHG_TXP, IWM_NUM_TXP_CH_GROUPS);
2253 1.29.2.2 skrll if (err) {
2254 1.29.2.2 skrll DPRINTF(("%s: Cannot send channel specific TX power groups, "
2255 1.29.2.2 skrll "%d\n", DEVNAME(sc), err));
2256 1.29.2.2 skrll return err;
2257 1.29.2.2 skrll }
2258 1.29.2.2 skrll
2259 1.29.2.2 skrll DPRINTF(("Finished sending phy db non channel data\n"));
2260 1.29.2.2 skrll return 0;
2261 1.29.2.2 skrll }
2262 1.29.2.2 skrll
2263 1.29.2.2 skrll /*
2264 1.29.2.2 skrll * END iwl-phy-db.c
2265 1.29.2.2 skrll */
2266 1.29.2.2 skrll
2267 1.29.2.2 skrll /*
2268 1.29.2.2 skrll * BEGIN iwlwifi/mvm/time-event.c
2269 1.29.2.2 skrll */
2270 1.29.2.2 skrll
2271 1.29.2.2 skrll /*
2272 1.29.2.2 skrll * For the high priority TE use a time event type that has similar priority to
2273 1.29.2.2 skrll * the FW's action scan priority.
2274 1.29.2.2 skrll */
2275 1.29.2.2 skrll #define IWM_MVM_ROC_TE_TYPE_NORMAL IWM_TE_P2P_DEVICE_DISCOVERABLE
2276 1.29.2.2 skrll #define IWM_MVM_ROC_TE_TYPE_MGMT_TX IWM_TE_P2P_CLIENT_ASSOC
2277 1.29.2.2 skrll
2278 1.29.2.2 skrll /* used to convert from time event API v2 to v1 */
2279 1.29.2.2 skrll #define IWM_TE_V2_DEP_POLICY_MSK (IWM_TE_V2_DEP_OTHER | IWM_TE_V2_DEP_TSF |\
2280 1.29.2.2 skrll IWM_TE_V2_EVENT_SOCIOPATHIC)
2281 1.29.2.2 skrll static inline uint16_t
2282 1.29.2.2 skrll iwm_te_v2_get_notify(uint16_t policy)
2283 1.29.2.2 skrll {
2284 1.29.2.2 skrll return le16toh(policy) & IWM_TE_V2_NOTIF_MSK;
2285 1.29.2.2 skrll }
2286 1.29.2.2 skrll
2287 1.29.2.2 skrll static inline uint16_t
2288 1.29.2.2 skrll iwm_te_v2_get_dep_policy(uint16_t policy)
2289 1.29.2.2 skrll {
2290 1.29.2.2 skrll return (le16toh(policy) & IWM_TE_V2_DEP_POLICY_MSK) >>
2291 1.29.2.2 skrll IWM_TE_V2_PLACEMENT_POS;
2292 1.29.2.2 skrll }
2293 1.29.2.2 skrll
2294 1.29.2.2 skrll static inline uint16_t
2295 1.29.2.2 skrll iwm_te_v2_get_absence(uint16_t policy)
2296 1.29.2.2 skrll {
2297 1.29.2.2 skrll return (le16toh(policy) & IWM_TE_V2_ABSENCE) >> IWM_TE_V2_ABSENCE_POS;
2298 1.29.2.2 skrll }
2299 1.29.2.2 skrll
2300 1.29.2.2 skrll static void
2301 1.29.2.2 skrll iwm_mvm_te_v2_to_v1(const struct iwm_time_event_cmd_v2 *cmd_v2,
2302 1.29.2.2 skrll struct iwm_time_event_cmd_v1 *cmd_v1)
2303 1.29.2.2 skrll {
2304 1.29.2.2 skrll cmd_v1->id_and_color = cmd_v2->id_and_color;
2305 1.29.2.2 skrll cmd_v1->action = cmd_v2->action;
2306 1.29.2.2 skrll cmd_v1->id = cmd_v2->id;
2307 1.29.2.2 skrll cmd_v1->apply_time = cmd_v2->apply_time;
2308 1.29.2.2 skrll cmd_v1->max_delay = cmd_v2->max_delay;
2309 1.29.2.2 skrll cmd_v1->depends_on = cmd_v2->depends_on;
2310 1.29.2.2 skrll cmd_v1->interval = cmd_v2->interval;
2311 1.29.2.2 skrll cmd_v1->duration = cmd_v2->duration;
2312 1.29.2.2 skrll if (cmd_v2->repeat == IWM_TE_V2_REPEAT_ENDLESS)
2313 1.29.2.2 skrll cmd_v1->repeat = htole32(IWM_TE_V1_REPEAT_ENDLESS);
2314 1.29.2.2 skrll else
2315 1.29.2.2 skrll cmd_v1->repeat = htole32(cmd_v2->repeat);
2316 1.29.2.2 skrll cmd_v1->max_frags = htole32(cmd_v2->max_frags);
2317 1.29.2.2 skrll cmd_v1->interval_reciprocal = 0; /* unused */
2318 1.29.2.2 skrll
2319 1.29.2.2 skrll cmd_v1->dep_policy = htole32(iwm_te_v2_get_dep_policy(cmd_v2->policy));
2320 1.29.2.2 skrll cmd_v1->is_present = htole32(!iwm_te_v2_get_absence(cmd_v2->policy));
2321 1.29.2.2 skrll cmd_v1->notify = htole32(iwm_te_v2_get_notify(cmd_v2->policy));
2322 1.29.2.2 skrll }
2323 1.29.2.2 skrll
2324 1.29.2.2 skrll static int
2325 1.29.2.2 skrll iwm_mvm_send_time_event_cmd(struct iwm_softc *sc,
2326 1.29.2.2 skrll const struct iwm_time_event_cmd_v2 *cmd)
2327 1.29.2.2 skrll {
2328 1.29.2.2 skrll struct iwm_time_event_cmd_v1 cmd_v1;
2329 1.29.2.2 skrll
2330 1.29.2.2 skrll if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_TIME_EVENT_API_V2)
2331 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD,
2332 1.29.2.2 skrll IWM_CMD_SYNC, sizeof(*cmd), cmd);
2333 1.29.2.2 skrll
2334 1.29.2.2 skrll iwm_mvm_te_v2_to_v1(cmd, &cmd_v1);
2335 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, IWM_CMD_SYNC,
2336 1.29.2.2 skrll sizeof(cmd_v1), &cmd_v1);
2337 1.29.2.2 skrll }
2338 1.29.2.2 skrll
2339 1.29.2.2 skrll static int
2340 1.29.2.2 skrll iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_node *in,
2341 1.29.2.2 skrll void *te_data, struct iwm_time_event_cmd_v2 *te_cmd)
2342 1.29.2.2 skrll {
2343 1.29.2.2 skrll int ret;
2344 1.29.2.2 skrll
2345 1.29.2.2 skrll DPRINTF(("Add new TE, duration %d TU\n", le32toh(te_cmd->duration)));
2346 1.29.2.2 skrll
2347 1.29.2.2 skrll ret = iwm_mvm_send_time_event_cmd(sc, te_cmd);
2348 1.29.2.2 skrll if (ret) {
2349 1.29.2.2 skrll DPRINTF(("%s: Couldn't send IWM_TIME_EVENT_CMD: %d\n",
2350 1.29.2.2 skrll DEVNAME(sc), ret));
2351 1.29.2.2 skrll }
2352 1.29.2.2 skrll
2353 1.29.2.2 skrll return ret;
2354 1.29.2.2 skrll }
2355 1.29.2.2 skrll
2356 1.29.2.2 skrll static void
2357 1.29.2.2 skrll iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in,
2358 1.29.2.2 skrll uint32_t duration, uint32_t min_duration, uint32_t max_delay)
2359 1.29.2.2 skrll {
2360 1.29.2.2 skrll struct iwm_time_event_cmd_v2 time_cmd;
2361 1.29.2.2 skrll
2362 1.29.2.2 skrll memset(&time_cmd, 0, sizeof(time_cmd));
2363 1.29.2.2 skrll
2364 1.29.2.2 skrll time_cmd.action = htole32(IWM_FW_CTXT_ACTION_ADD);
2365 1.29.2.2 skrll time_cmd.id_and_color =
2366 1.29.2.2 skrll htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
2367 1.29.2.2 skrll time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC);
2368 1.29.2.2 skrll
2369 1.29.2.2 skrll time_cmd.apply_time = htole32(iwm_read_prph(sc,
2370 1.29.2.2 skrll IWM_DEVICE_SYSTEM_TIME_REG));
2371 1.29.2.2 skrll
2372 1.29.2.2 skrll time_cmd.max_frags = IWM_TE_V2_FRAG_NONE;
2373 1.29.2.2 skrll time_cmd.max_delay = htole32(max_delay);
2374 1.29.2.2 skrll /* TODO: why do we need to interval = bi if it is not periodic? */
2375 1.29.2.2 skrll time_cmd.interval = htole32(1);
2376 1.29.2.2 skrll time_cmd.duration = htole32(duration);
2377 1.29.2.2 skrll time_cmd.repeat = 1;
2378 1.29.2.2 skrll time_cmd.policy
2379 1.29.2.2 skrll = htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START |
2380 1.29.2.2 skrll IWM_TE_V2_NOTIF_HOST_EVENT_END);
2381 1.29.2.2 skrll
2382 1.29.2.2 skrll iwm_mvm_time_event_send_add(sc, in, /*te_data*/NULL, &time_cmd);
2383 1.29.2.2 skrll }
2384 1.29.2.2 skrll
2385 1.29.2.2 skrll /*
2386 1.29.2.2 skrll * END iwlwifi/mvm/time-event.c
2387 1.29.2.2 skrll */
2388 1.29.2.2 skrll
2389 1.29.2.2 skrll /*
2390 1.29.2.2 skrll * NVM read access and content parsing. We do not support
2391 1.29.2.2 skrll * external NVM or writing NVM.
2392 1.29.2.2 skrll * iwlwifi/mvm/nvm.c
2393 1.29.2.2 skrll */
2394 1.29.2.2 skrll
2395 1.29.2.2 skrll /* list of NVM sections we are allowed/need to read */
2396 1.29.2.2 skrll static const int nvm_to_read[] = {
2397 1.29.2.2 skrll IWM_NVM_SECTION_TYPE_HW,
2398 1.29.2.2 skrll IWM_NVM_SECTION_TYPE_SW,
2399 1.29.2.2 skrll IWM_NVM_SECTION_TYPE_CALIBRATION,
2400 1.29.2.2 skrll IWM_NVM_SECTION_TYPE_PRODUCTION,
2401 1.29.2.2 skrll };
2402 1.29.2.2 skrll
2403 1.29.2.2 skrll /* Default NVM size to read */
2404 1.29.2.2 skrll #define IWM_NVM_DEFAULT_CHUNK_SIZE (2*1024)
2405 1.29.2.2 skrll #define IWM_MAX_NVM_SECTION_SIZE 7000
2406 1.29.2.2 skrll
2407 1.29.2.2 skrll #define IWM_NVM_WRITE_OPCODE 1
2408 1.29.2.2 skrll #define IWM_NVM_READ_OPCODE 0
2409 1.29.2.2 skrll
2410 1.29.2.2 skrll static int
2411 1.29.2.2 skrll iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section,
2412 1.29.2.2 skrll uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len)
2413 1.29.2.2 skrll {
2414 1.29.2.2 skrll offset = 0;
2415 1.29.2.2 skrll struct iwm_nvm_access_cmd nvm_access_cmd = {
2416 1.29.2.2 skrll .offset = htole16(offset),
2417 1.29.2.2 skrll .length = htole16(length),
2418 1.29.2.2 skrll .type = htole16(section),
2419 1.29.2.2 skrll .op_code = IWM_NVM_READ_OPCODE,
2420 1.29.2.2 skrll };
2421 1.29.2.2 skrll struct iwm_nvm_access_resp *nvm_resp;
2422 1.29.2.2 skrll struct iwm_rx_packet *pkt;
2423 1.29.2.2 skrll struct iwm_host_cmd cmd = {
2424 1.29.2.2 skrll .id = IWM_NVM_ACCESS_CMD,
2425 1.29.2.2 skrll .flags = IWM_CMD_SYNC | IWM_CMD_WANT_SKB |
2426 1.29.2.2 skrll IWM_CMD_SEND_IN_RFKILL,
2427 1.29.2.2 skrll .data = { &nvm_access_cmd, },
2428 1.29.2.2 skrll };
2429 1.29.2.2 skrll int ret, bytes_read, offset_read;
2430 1.29.2.2 skrll uint8_t *resp_data;
2431 1.29.2.2 skrll
2432 1.29.2.2 skrll cmd.len[0] = sizeof(struct iwm_nvm_access_cmd);
2433 1.29.2.2 skrll
2434 1.29.2.2 skrll ret = iwm_send_cmd(sc, &cmd);
2435 1.29.2.2 skrll if (ret)
2436 1.29.2.2 skrll return ret;
2437 1.29.2.2 skrll
2438 1.29.2.2 skrll pkt = cmd.resp_pkt;
2439 1.29.2.2 skrll if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
2440 1.29.2.2 skrll DPRINTF(("%s: Bad return from IWM_NVM_ACCES_COMMAND (0x%08X)\n",
2441 1.29.2.2 skrll DEVNAME(sc), pkt->hdr.flags));
2442 1.29.2.2 skrll ret = EIO;
2443 1.29.2.2 skrll goto exit;
2444 1.29.2.2 skrll }
2445 1.29.2.2 skrll
2446 1.29.2.2 skrll /* Extract NVM response */
2447 1.29.2.2 skrll nvm_resp = (void *)pkt->data;
2448 1.29.2.2 skrll
2449 1.29.2.2 skrll ret = le16toh(nvm_resp->status);
2450 1.29.2.2 skrll bytes_read = le16toh(nvm_resp->length);
2451 1.29.2.2 skrll offset_read = le16toh(nvm_resp->offset);
2452 1.29.2.2 skrll resp_data = nvm_resp->data;
2453 1.29.2.2 skrll if (ret) {
2454 1.29.2.2 skrll DPRINTF(("%s: NVM access command failed with status %d\n",
2455 1.29.2.2 skrll DEVNAME(sc), ret));
2456 1.29.2.2 skrll ret = EINVAL;
2457 1.29.2.2 skrll goto exit;
2458 1.29.2.2 skrll }
2459 1.29.2.2 skrll
2460 1.29.2.2 skrll if (offset_read != offset) {
2461 1.29.2.2 skrll DPRINTF(("%s: NVM ACCESS response with invalid offset %d\n",
2462 1.29.2.2 skrll DEVNAME(sc), offset_read));
2463 1.29.2.2 skrll ret = EINVAL;
2464 1.29.2.2 skrll goto exit;
2465 1.29.2.2 skrll }
2466 1.29.2.2 skrll
2467 1.29.2.2 skrll memcpy(data + offset, resp_data, bytes_read);
2468 1.29.2.2 skrll *len = bytes_read;
2469 1.29.2.2 skrll
2470 1.29.2.2 skrll exit:
2471 1.29.2.2 skrll iwm_free_resp(sc, &cmd);
2472 1.29.2.2 skrll return ret;
2473 1.29.2.2 skrll }
2474 1.29.2.2 skrll
2475 1.29.2.2 skrll /*
2476 1.29.2.2 skrll * Reads an NVM section completely.
2477 1.29.2.2 skrll * NICs prior to 7000 family doesn't have a real NVM, but just read
2478 1.29.2.2 skrll * section 0 which is the EEPROM. Because the EEPROM reading is unlimited
2479 1.29.2.2 skrll * by uCode, we need to manually check in this case that we don't
2480 1.29.2.2 skrll * overflow and try to read more than the EEPROM size.
2481 1.29.2.2 skrll * For 7000 family NICs, we supply the maximal size we can read, and
2482 1.29.2.2 skrll * the uCode fills the response with as much data as we can,
2483 1.29.2.2 skrll * without overflowing, so no check is needed.
2484 1.29.2.2 skrll */
2485 1.29.2.2 skrll static int
2486 1.29.2.2 skrll iwm_nvm_read_section(struct iwm_softc *sc,
2487 1.29.2.2 skrll uint16_t section, uint8_t *data, uint16_t *len)
2488 1.29.2.2 skrll {
2489 1.29.2.2 skrll uint16_t length, seglen;
2490 1.29.2.2 skrll int error;
2491 1.29.2.2 skrll
2492 1.29.2.2 skrll /* Set nvm section read length */
2493 1.29.2.2 skrll length = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
2494 1.29.2.2 skrll *len = 0;
2495 1.29.2.2 skrll
2496 1.29.2.2 skrll /* Read the NVM until exhausted (reading less than requested) */
2497 1.29.2.2 skrll while (seglen == length) {
2498 1.29.2.2 skrll error = iwm_nvm_read_chunk(sc,
2499 1.29.2.2 skrll section, *len, length, data, &seglen);
2500 1.29.2.2 skrll if (error) {
2501 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
2502 1.29.2.2 skrll "Cannot read NVM from section %d offset %d, "
2503 1.29.2.2 skrll "length %d\n", section, *len, length);
2504 1.29.2.2 skrll return error;
2505 1.29.2.2 skrll }
2506 1.29.2.2 skrll *len += seglen;
2507 1.29.2.2 skrll }
2508 1.29.2.2 skrll
2509 1.29.2.2 skrll DPRINTFN(4, ("NVM section %d read completed\n", section));
2510 1.29.2.2 skrll return 0;
2511 1.29.2.2 skrll }
2512 1.29.2.2 skrll
2513 1.29.2.2 skrll /*
2514 1.29.2.2 skrll * BEGIN IWM_NVM_PARSE
2515 1.29.2.2 skrll */
2516 1.29.2.2 skrll
2517 1.29.2.2 skrll /* iwlwifi/iwl-nvm-parse.c */
2518 1.29.2.2 skrll
2519 1.29.2.2 skrll /* NVM offsets (in words) definitions */
2520 1.29.2.2 skrll enum wkp_nvm_offsets {
2521 1.29.2.2 skrll /* NVM HW-Section offset (in words) definitions */
2522 1.29.2.2 skrll IWM_HW_ADDR = 0x15,
2523 1.29.2.2 skrll
2524 1.29.2.2 skrll /* NVM SW-Section offset (in words) definitions */
2525 1.29.2.2 skrll IWM_NVM_SW_SECTION = 0x1C0,
2526 1.29.2.2 skrll IWM_NVM_VERSION = 0,
2527 1.29.2.2 skrll IWM_RADIO_CFG = 1,
2528 1.29.2.2 skrll IWM_SKU = 2,
2529 1.29.2.2 skrll IWM_N_HW_ADDRS = 3,
2530 1.29.2.2 skrll IWM_NVM_CHANNELS = 0x1E0 - IWM_NVM_SW_SECTION,
2531 1.29.2.2 skrll
2532 1.29.2.2 skrll /* NVM calibration section offset (in words) definitions */
2533 1.29.2.2 skrll IWM_NVM_CALIB_SECTION = 0x2B8,
2534 1.29.2.2 skrll IWM_XTAL_CALIB = 0x316 - IWM_NVM_CALIB_SECTION
2535 1.29.2.2 skrll };
2536 1.29.2.2 skrll
2537 1.29.2.2 skrll /* SKU Capabilities (actual values from NVM definition) */
2538 1.29.2.2 skrll enum nvm_sku_bits {
2539 1.29.2.2 skrll IWM_NVM_SKU_CAP_BAND_24GHZ = (1 << 0),
2540 1.29.2.2 skrll IWM_NVM_SKU_CAP_BAND_52GHZ = (1 << 1),
2541 1.29.2.2 skrll IWM_NVM_SKU_CAP_11N_ENABLE = (1 << 2),
2542 1.29.2.2 skrll IWM_NVM_SKU_CAP_11AC_ENABLE = (1 << 3),
2543 1.29.2.2 skrll };
2544 1.29.2.2 skrll
2545 1.29.2.2 skrll /* radio config bits (actual values from NVM definition) */
2546 1.29.2.2 skrll #define IWM_NVM_RF_CFG_DASH_MSK(x) (x & 0x3) /* bits 0-1 */
2547 1.29.2.2 skrll #define IWM_NVM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */
2548 1.29.2.2 skrll #define IWM_NVM_RF_CFG_TYPE_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */
2549 1.29.2.2 skrll #define IWM_NVM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */
2550 1.29.2.2 skrll #define IWM_NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
2551 1.29.2.2 skrll #define IWM_NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
2552 1.29.2.2 skrll
2553 1.29.2.2 skrll #define DEFAULT_MAX_TX_POWER 16
2554 1.29.2.2 skrll
2555 1.29.2.2 skrll /**
2556 1.29.2.2 skrll * enum iwm_nvm_channel_flags - channel flags in NVM
2557 1.29.2.2 skrll * @IWM_NVM_CHANNEL_VALID: channel is usable for this SKU/geo
2558 1.29.2.2 skrll * @IWM_NVM_CHANNEL_IBSS: usable as an IBSS channel
2559 1.29.2.2 skrll * @IWM_NVM_CHANNEL_ACTIVE: active scanning allowed
2560 1.29.2.2 skrll * @IWM_NVM_CHANNEL_RADAR: radar detection required
2561 1.29.2.2 skrll * @IWM_NVM_CHANNEL_DFS: dynamic freq selection candidate
2562 1.29.2.2 skrll * @IWM_NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
2563 1.29.2.2 skrll * @IWM_NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
2564 1.29.2.2 skrll * @IWM_NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
2565 1.29.2.2 skrll * @IWM_NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
2566 1.29.2.2 skrll */
2567 1.29.2.2 skrll enum iwm_nvm_channel_flags {
2568 1.29.2.2 skrll IWM_NVM_CHANNEL_VALID = (1 << 0),
2569 1.29.2.2 skrll IWM_NVM_CHANNEL_IBSS = (1 << 1),
2570 1.29.2.2 skrll IWM_NVM_CHANNEL_ACTIVE = (1 << 3),
2571 1.29.2.2 skrll IWM_NVM_CHANNEL_RADAR = (1 << 4),
2572 1.29.2.2 skrll IWM_NVM_CHANNEL_DFS = (1 << 7),
2573 1.29.2.2 skrll IWM_NVM_CHANNEL_WIDE = (1 << 8),
2574 1.29.2.2 skrll IWM_NVM_CHANNEL_40MHZ = (1 << 9),
2575 1.29.2.2 skrll IWM_NVM_CHANNEL_80MHZ = (1 << 10),
2576 1.29.2.2 skrll IWM_NVM_CHANNEL_160MHZ = (1 << 11),
2577 1.29.2.2 skrll };
2578 1.29.2.2 skrll
2579 1.29.2.2 skrll static void
2580 1.29.2.2 skrll iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags)
2581 1.29.2.2 skrll {
2582 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
2583 1.29.2.2 skrll struct iwm_nvm_data *data = &sc->sc_nvm;
2584 1.29.2.2 skrll int ch_idx;
2585 1.29.2.2 skrll struct ieee80211_channel *channel;
2586 1.29.2.2 skrll uint16_t ch_flags;
2587 1.29.2.2 skrll int is_5ghz;
2588 1.29.2.2 skrll int flags, hw_value;
2589 1.29.2.2 skrll
2590 1.29.2.2 skrll for (ch_idx = 0; ch_idx < __arraycount(iwm_nvm_channels); ch_idx++) {
2591 1.29.2.2 skrll ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx);
2592 1.29.2.2 skrll
2593 1.29.2.2 skrll if (ch_idx >= IWM_NUM_2GHZ_CHANNELS &&
2594 1.29.2.2 skrll !data->sku_cap_band_52GHz_enable)
2595 1.29.2.2 skrll ch_flags &= ~IWM_NVM_CHANNEL_VALID;
2596 1.29.2.2 skrll
2597 1.29.2.2 skrll if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) {
2598 1.29.2.2 skrll DPRINTF(("Ch. %d Flags %x [%sGHz] - No traffic\n",
2599 1.29.2.2 skrll iwm_nvm_channels[ch_idx],
2600 1.29.2.2 skrll ch_flags,
2601 1.29.2.2 skrll (ch_idx >= IWM_NUM_2GHZ_CHANNELS) ?
2602 1.29.2.2 skrll "5.2" : "2.4"));
2603 1.29.2.2 skrll continue;
2604 1.29.2.2 skrll }
2605 1.29.2.2 skrll
2606 1.29.2.2 skrll hw_value = iwm_nvm_channels[ch_idx];
2607 1.29.2.2 skrll channel = &ic->ic_channels[hw_value];
2608 1.29.2.2 skrll
2609 1.29.2.2 skrll is_5ghz = ch_idx >= IWM_NUM_2GHZ_CHANNELS;
2610 1.29.2.2 skrll if (!is_5ghz) {
2611 1.29.2.2 skrll flags = IEEE80211_CHAN_2GHZ;
2612 1.29.2.2 skrll channel->ic_flags
2613 1.29.2.2 skrll = IEEE80211_CHAN_CCK
2614 1.29.2.2 skrll | IEEE80211_CHAN_OFDM
2615 1.29.2.2 skrll | IEEE80211_CHAN_DYN
2616 1.29.2.2 skrll | IEEE80211_CHAN_2GHZ;
2617 1.29.2.2 skrll } else {
2618 1.29.2.2 skrll flags = IEEE80211_CHAN_5GHZ;
2619 1.29.2.2 skrll channel->ic_flags =
2620 1.29.2.2 skrll IEEE80211_CHAN_A;
2621 1.29.2.2 skrll }
2622 1.29.2.2 skrll channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags);
2623 1.29.2.2 skrll
2624 1.29.2.2 skrll if (!(ch_flags & IWM_NVM_CHANNEL_ACTIVE))
2625 1.29.2.2 skrll channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
2626 1.29.2.2 skrll }
2627 1.29.2.2 skrll }
2628 1.29.2.2 skrll
2629 1.29.2.2 skrll static int
2630 1.29.2.2 skrll iwm_parse_nvm_data(struct iwm_softc *sc,
2631 1.29.2.2 skrll const uint16_t *nvm_hw, const uint16_t *nvm_sw,
2632 1.29.2.2 skrll const uint16_t *nvm_calib, uint8_t tx_chains, uint8_t rx_chains)
2633 1.29.2.2 skrll {
2634 1.29.2.2 skrll struct iwm_nvm_data *data = &sc->sc_nvm;
2635 1.29.2.2 skrll uint8_t hw_addr[ETHER_ADDR_LEN];
2636 1.29.2.2 skrll uint16_t radio_cfg, sku;
2637 1.29.2.2 skrll
2638 1.29.2.2 skrll data->nvm_version = le16_to_cpup(nvm_sw + IWM_NVM_VERSION);
2639 1.29.2.2 skrll
2640 1.29.2.2 skrll radio_cfg = le16_to_cpup(nvm_sw + IWM_RADIO_CFG);
2641 1.29.2.2 skrll data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg);
2642 1.29.2.2 skrll data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg);
2643 1.29.2.2 skrll data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg);
2644 1.29.2.2 skrll data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg);
2645 1.29.2.2 skrll data->valid_tx_ant = IWM_NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
2646 1.29.2.2 skrll data->valid_rx_ant = IWM_NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
2647 1.29.2.2 skrll
2648 1.29.2.2 skrll sku = le16_to_cpup(nvm_sw + IWM_SKU);
2649 1.29.2.2 skrll data->sku_cap_band_24GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_24GHZ;
2650 1.29.2.2 skrll data->sku_cap_band_52GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_52GHZ;
2651 1.29.2.2 skrll data->sku_cap_11n_enable = 0;
2652 1.29.2.2 skrll
2653 1.29.2.2 skrll if (!data->valid_tx_ant || !data->valid_rx_ant) {
2654 1.29.2.2 skrll DPRINTF(("%s: invalid antennas (0x%x, 0x%x)\n", DEVNAME(sc),
2655 1.29.2.2 skrll data->valid_tx_ant, data->valid_rx_ant));
2656 1.29.2.2 skrll return EINVAL;
2657 1.29.2.2 skrll }
2658 1.29.2.2 skrll
2659 1.29.2.2 skrll data->n_hw_addrs = le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS);
2660 1.29.2.2 skrll
2661 1.29.2.2 skrll data->xtal_calib[0] = *(nvm_calib + IWM_XTAL_CALIB);
2662 1.29.2.2 skrll data->xtal_calib[1] = *(nvm_calib + IWM_XTAL_CALIB + 1);
2663 1.29.2.2 skrll
2664 1.29.2.2 skrll /* The byte order is little endian 16 bit, meaning 214365 */
2665 1.29.2.2 skrll memcpy(hw_addr, nvm_hw + IWM_HW_ADDR, ETHER_ADDR_LEN);
2666 1.29.2.2 skrll data->hw_addr[0] = hw_addr[1];
2667 1.29.2.2 skrll data->hw_addr[1] = hw_addr[0];
2668 1.29.2.2 skrll data->hw_addr[2] = hw_addr[3];
2669 1.29.2.2 skrll data->hw_addr[3] = hw_addr[2];
2670 1.29.2.2 skrll data->hw_addr[4] = hw_addr[5];
2671 1.29.2.2 skrll data->hw_addr[5] = hw_addr[4];
2672 1.29.2.2 skrll
2673 1.29.2.2 skrll iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS]);
2674 1.29.2.2 skrll data->calib_version = 255; /* TODO:
2675 1.29.2.2 skrll this value will prevent some checks from
2676 1.29.2.2 skrll failing, we need to check if this
2677 1.29.2.2 skrll field is still needed, and if it does,
2678 1.29.2.2 skrll where is it in the NVM */
2679 1.29.2.2 skrll
2680 1.29.2.2 skrll return 0;
2681 1.29.2.2 skrll }
2682 1.29.2.2 skrll
2683 1.29.2.2 skrll /*
2684 1.29.2.2 skrll * END NVM PARSE
2685 1.29.2.2 skrll */
2686 1.29.2.2 skrll
2687 1.29.2.2 skrll struct iwm_nvm_section {
2688 1.29.2.2 skrll uint16_t length;
2689 1.29.2.2 skrll const uint8_t *data;
2690 1.29.2.2 skrll };
2691 1.29.2.2 skrll
2692 1.29.2.2 skrll #define IWM_FW_VALID_TX_ANT(sc) \
2693 1.29.2.2 skrll ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) \
2694 1.29.2.2 skrll >> IWM_FW_PHY_CFG_TX_CHAIN_POS)
2695 1.29.2.2 skrll #define IWM_FW_VALID_RX_ANT(sc) \
2696 1.29.2.2 skrll ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN) \
2697 1.29.2.2 skrll >> IWM_FW_PHY_CFG_RX_CHAIN_POS)
2698 1.29.2.2 skrll
2699 1.29.2.2 skrll static int
2700 1.29.2.2 skrll iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections)
2701 1.29.2.2 skrll {
2702 1.29.2.2 skrll const uint16_t *hw, *sw, *calib;
2703 1.29.2.2 skrll
2704 1.29.2.2 skrll /* Checking for required sections */
2705 1.29.2.2 skrll if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
2706 1.29.2.2 skrll !sections[IWM_NVM_SECTION_TYPE_HW].data) {
2707 1.29.2.2 skrll DPRINTF(("%s: Can't parse empty NVM sections\n", DEVNAME(sc)));
2708 1.29.2.2 skrll return ENOENT;
2709 1.29.2.2 skrll }
2710 1.29.2.2 skrll
2711 1.29.2.2 skrll hw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_HW].data;
2712 1.29.2.2 skrll sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data;
2713 1.29.2.2 skrll calib = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
2714 1.29.2.2 skrll return iwm_parse_nvm_data(sc, hw, sw, calib,
2715 1.29.2.2 skrll IWM_FW_VALID_TX_ANT(sc), IWM_FW_VALID_RX_ANT(sc));
2716 1.29.2.2 skrll }
2717 1.29.2.2 skrll
2718 1.29.2.2 skrll static int
2719 1.29.2.2 skrll iwm_nvm_init(struct iwm_softc *sc)
2720 1.29.2.2 skrll {
2721 1.29.2.2 skrll struct iwm_nvm_section nvm_sections[IWM_NVM_NUM_OF_SECTIONS];
2722 1.29.2.2 skrll int i, section, error;
2723 1.29.2.2 skrll uint16_t len;
2724 1.29.2.2 skrll uint8_t *nvm_buffer, *temp;
2725 1.29.2.2 skrll
2726 1.29.2.2 skrll /* Read From FW NVM */
2727 1.29.2.2 skrll DPRINTF(("Read NVM\n"));
2728 1.29.2.2 skrll
2729 1.29.2.2 skrll /* TODO: find correct NVM max size for a section */
2730 1.29.2.2 skrll nvm_buffer = kmem_alloc(IWM_OTP_LOW_IMAGE_SIZE, KM_SLEEP);
2731 1.29.2.2 skrll for (i = 0; i < __arraycount(nvm_to_read); i++) {
2732 1.29.2.2 skrll section = nvm_to_read[i];
2733 1.29.2.2 skrll KASSERT(section <= __arraycount(nvm_sections));
2734 1.29.2.2 skrll
2735 1.29.2.2 skrll error = iwm_nvm_read_section(sc, section, nvm_buffer, &len);
2736 1.29.2.2 skrll if (error)
2737 1.29.2.2 skrll break;
2738 1.29.2.2 skrll
2739 1.29.2.2 skrll temp = kmem_alloc(len, KM_SLEEP);
2740 1.29.2.2 skrll memcpy(temp, nvm_buffer, len);
2741 1.29.2.2 skrll nvm_sections[section].data = temp;
2742 1.29.2.2 skrll nvm_sections[section].length = len;
2743 1.29.2.2 skrll }
2744 1.29.2.2 skrll kmem_free(nvm_buffer, IWM_OTP_LOW_IMAGE_SIZE);
2745 1.29.2.2 skrll if (error)
2746 1.29.2.2 skrll return error;
2747 1.29.2.2 skrll
2748 1.29.2.2 skrll return iwm_parse_nvm_sections(sc, nvm_sections);
2749 1.29.2.2 skrll }
2750 1.29.2.2 skrll
2751 1.29.2.2 skrll /*
2752 1.29.2.2 skrll * Firmware loading gunk. This is kind of a weird hybrid between the
2753 1.29.2.2 skrll * iwn driver and the Linux iwlwifi driver.
2754 1.29.2.2 skrll */
2755 1.29.2.2 skrll
2756 1.29.2.2 skrll static int
2757 1.29.2.2 skrll iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr,
2758 1.29.2.2 skrll const uint8_t *section, uint32_t byte_cnt)
2759 1.29.2.2 skrll {
2760 1.29.2.2 skrll struct iwm_dma_info *dma = &sc->fw_dma;
2761 1.29.2.2 skrll int error;
2762 1.29.2.2 skrll
2763 1.29.2.2 skrll /* Copy firmware section into pre-allocated DMA-safe memory. */
2764 1.29.2.2 skrll memcpy(dma->vaddr, section, byte_cnt);
2765 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat,
2766 1.29.2.2 skrll dma->map, 0, byte_cnt, BUS_DMASYNC_PREWRITE);
2767 1.29.2.2 skrll
2768 1.29.2.2 skrll if (!iwm_nic_lock(sc))
2769 1.29.2.2 skrll return EBUSY;
2770 1.29.2.2 skrll
2771 1.29.2.2 skrll sc->sc_fw_chunk_done = 0;
2772 1.29.2.2 skrll
2773 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL),
2774 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
2775 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(IWM_FH_SRVC_CHNL),
2776 1.29.2.2 skrll dst_addr);
2777 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TFDIB_CTRL0_REG(IWM_FH_SRVC_CHNL),
2778 1.29.2.2 skrll dma->paddr & IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
2779 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TFDIB_CTRL1_REG(IWM_FH_SRVC_CHNL),
2780 1.29.2.2 skrll (iwm_get_dma_hi_addr(dma->paddr)
2781 1.29.2.2 skrll << IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
2782 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(IWM_FH_SRVC_CHNL),
2783 1.29.2.2 skrll 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
2784 1.29.2.2 skrll 1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
2785 1.29.2.2 skrll IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
2786 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL),
2787 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
2788 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
2789 1.29.2.2 skrll IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
2790 1.29.2.2 skrll
2791 1.29.2.2 skrll iwm_nic_unlock(sc);
2792 1.29.2.2 skrll
2793 1.29.2.2 skrll /* wait 1s for this segment to load */
2794 1.29.2.2 skrll while (!sc->sc_fw_chunk_done)
2795 1.29.2.2 skrll if ((error = tsleep(&sc->sc_fw, 0, "iwmfw", hz)) != 0)
2796 1.29.2.2 skrll break;
2797 1.29.2.2 skrll
2798 1.29.2.2 skrll return error;
2799 1.29.2.2 skrll }
2800 1.29.2.2 skrll
2801 1.29.2.2 skrll static int
2802 1.29.2.2 skrll iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
2803 1.29.2.2 skrll {
2804 1.29.2.2 skrll struct iwm_fw_sects *fws;
2805 1.29.2.2 skrll int error, i, w;
2806 1.29.2.2 skrll void *data;
2807 1.29.2.2 skrll uint32_t dlen;
2808 1.29.2.2 skrll uint32_t offset;
2809 1.29.2.2 skrll
2810 1.29.2.2 skrll sc->sc_uc.uc_intr = 0;
2811 1.29.2.2 skrll
2812 1.29.2.2 skrll fws = &sc->sc_fw.fw_sects[ucode_type];
2813 1.29.2.2 skrll for (i = 0; i < fws->fw_count; i++) {
2814 1.29.2.2 skrll data = fws->fw_sect[i].fws_data;
2815 1.29.2.2 skrll dlen = fws->fw_sect[i].fws_len;
2816 1.29.2.2 skrll offset = fws->fw_sect[i].fws_devoff;
2817 1.29.2.2 skrll DPRINTF(("LOAD FIRMWARE type %d offset %u len %d\n",
2818 1.29.2.2 skrll ucode_type, offset, dlen));
2819 1.29.2.2 skrll error = iwm_firmware_load_chunk(sc, offset, data, dlen);
2820 1.29.2.2 skrll if (error) {
2821 1.29.2.2 skrll DPRINTF(("iwm_firmware_load_chunk() chunk %u of %u "
2822 1.29.2.2 skrll "returned error %02d\n", i, fws->fw_count, error));
2823 1.29.2.2 skrll return error;
2824 1.29.2.2 skrll }
2825 1.29.2.2 skrll }
2826 1.29.2.2 skrll
2827 1.29.2.2 skrll /* wait for the firmware to load */
2828 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_RESET, 0);
2829 1.29.2.2 skrll
2830 1.29.2.2 skrll for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) {
2831 1.29.2.2 skrll error = tsleep(&sc->sc_uc, 0, "iwmuc", hz/10);
2832 1.29.2.2 skrll }
2833 1.29.2.2 skrll
2834 1.29.2.2 skrll return error;
2835 1.29.2.2 skrll }
2836 1.29.2.2 skrll
2837 1.29.2.2 skrll /* iwlwifi: pcie/trans.c */
2838 1.29.2.2 skrll static int
2839 1.29.2.2 skrll iwm_start_fw(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
2840 1.29.2.2 skrll {
2841 1.29.2.2 skrll int error;
2842 1.29.2.2 skrll
2843 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, ~0);
2844 1.29.2.2 skrll
2845 1.29.2.2 skrll if ((error = iwm_nic_init(sc)) != 0) {
2846 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "Unable to init nic\n");
2847 1.29.2.2 skrll return error;
2848 1.29.2.2 skrll }
2849 1.29.2.2 skrll
2850 1.29.2.2 skrll /* make sure rfkill handshake bits are cleared */
2851 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
2852 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR,
2853 1.29.2.2 skrll IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
2854 1.29.2.2 skrll
2855 1.29.2.2 skrll /* clear (again), then enable host interrupts */
2856 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, ~0);
2857 1.29.2.2 skrll iwm_enable_interrupts(sc);
2858 1.29.2.2 skrll
2859 1.29.2.2 skrll /* really make sure rfkill handshake bits are cleared */
2860 1.29.2.2 skrll /* maybe we should write a few times more? just to make sure */
2861 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
2862 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
2863 1.29.2.2 skrll
2864 1.29.2.2 skrll /* Load the given image to the HW */
2865 1.29.2.2 skrll error = iwm_load_firmware(sc, ucode_type);
2866 1.29.2.2 skrll if (error) {
2867 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "failed to load firmware: %d\n",
2868 1.29.2.2 skrll error);
2869 1.29.2.2 skrll }
2870 1.29.2.2 skrll return error;
2871 1.29.2.2 skrll }
2872 1.29.2.2 skrll
2873 1.29.2.2 skrll static int
2874 1.29.2.2 skrll iwm_fw_alive(struct iwm_softc *sc, uint32_t sched_base)
2875 1.29.2.2 skrll {
2876 1.29.2.2 skrll return iwm_post_alive(sc);
2877 1.29.2.2 skrll }
2878 1.29.2.2 skrll
2879 1.29.2.2 skrll static int
2880 1.29.2.2 skrll iwm_send_tx_ant_cfg(struct iwm_softc *sc, uint8_t valid_tx_ant)
2881 1.29.2.2 skrll {
2882 1.29.2.2 skrll struct iwm_tx_ant_cfg_cmd tx_ant_cmd = {
2883 1.29.2.2 skrll .valid = htole32(valid_tx_ant),
2884 1.29.2.2 skrll };
2885 1.29.2.2 skrll
2886 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu(sc, IWM_TX_ANT_CONFIGURATION_CMD,
2887 1.29.2.2 skrll IWM_CMD_SYNC, sizeof(tx_ant_cmd), &tx_ant_cmd);
2888 1.29.2.2 skrll }
2889 1.29.2.2 skrll
2890 1.29.2.2 skrll /* iwlwifi: mvm/fw.c */
2891 1.29.2.2 skrll static int
2892 1.29.2.2 skrll iwm_send_phy_cfg_cmd(struct iwm_softc *sc)
2893 1.29.2.2 skrll {
2894 1.29.2.2 skrll struct iwm_phy_cfg_cmd phy_cfg_cmd;
2895 1.29.2.2 skrll enum iwm_ucode_type ucode_type = sc->sc_uc_current;
2896 1.29.2.2 skrll
2897 1.29.2.2 skrll /* Set parameters */
2898 1.29.2.2 skrll phy_cfg_cmd.phy_cfg = htole32(sc->sc_fw_phy_config);
2899 1.29.2.2 skrll phy_cfg_cmd.calib_control.event_trigger =
2900 1.29.2.2 skrll sc->sc_default_calib[ucode_type].event_trigger;
2901 1.29.2.2 skrll phy_cfg_cmd.calib_control.flow_trigger =
2902 1.29.2.2 skrll sc->sc_default_calib[ucode_type].flow_trigger;
2903 1.29.2.2 skrll
2904 1.29.2.2 skrll DPRINTFN(10, ("Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg));
2905 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONFIGURATION_CMD, IWM_CMD_SYNC,
2906 1.29.2.2 skrll sizeof(phy_cfg_cmd), &phy_cfg_cmd);
2907 1.29.2.2 skrll }
2908 1.29.2.2 skrll
2909 1.29.2.2 skrll static int
2910 1.29.2.2 skrll iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc,
2911 1.29.2.2 skrll enum iwm_ucode_type ucode_type)
2912 1.29.2.2 skrll {
2913 1.29.2.2 skrll enum iwm_ucode_type old_type = sc->sc_uc_current;
2914 1.29.2.2 skrll int error;
2915 1.29.2.2 skrll
2916 1.29.2.2 skrll if ((error = iwm_read_firmware(sc)) != 0)
2917 1.29.2.2 skrll return error;
2918 1.29.2.2 skrll
2919 1.29.2.2 skrll sc->sc_uc_current = ucode_type;
2920 1.29.2.2 skrll error = iwm_start_fw(sc, ucode_type);
2921 1.29.2.2 skrll if (error) {
2922 1.29.2.2 skrll sc->sc_uc_current = old_type;
2923 1.29.2.2 skrll return error;
2924 1.29.2.2 skrll }
2925 1.29.2.2 skrll
2926 1.29.2.2 skrll return iwm_fw_alive(sc, sc->sched_base);
2927 1.29.2.2 skrll }
2928 1.29.2.2 skrll
2929 1.29.2.2 skrll /*
2930 1.29.2.2 skrll * mvm misc bits
2931 1.29.2.2 skrll */
2932 1.29.2.2 skrll
2933 1.29.2.2 skrll /*
2934 1.29.2.2 skrll * follows iwlwifi/fw.c
2935 1.29.2.2 skrll */
2936 1.29.2.2 skrll static int
2937 1.29.2.2 skrll iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm)
2938 1.29.2.2 skrll {
2939 1.29.2.2 skrll int error;
2940 1.29.2.2 skrll
2941 1.29.2.2 skrll /* do not operate with rfkill switch turned on */
2942 1.29.2.2 skrll if ((sc->sc_flags & IWM_FLAG_RFKILL) && !justnvm) {
2943 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
2944 1.29.2.2 skrll "radio is disabled by hardware switch\n");
2945 1.29.2.2 skrll return EPERM;
2946 1.29.2.2 skrll }
2947 1.29.2.2 skrll
2948 1.29.2.2 skrll sc->sc_init_complete = 0;
2949 1.29.2.2 skrll if ((error = iwm_mvm_load_ucode_wait_alive(sc,
2950 1.29.2.2 skrll IWM_UCODE_TYPE_INIT)) != 0)
2951 1.29.2.2 skrll return error;
2952 1.29.2.2 skrll
2953 1.29.2.2 skrll if (justnvm) {
2954 1.29.2.2 skrll if ((error = iwm_nvm_init(sc)) != 0) {
2955 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "failed to read nvm\n");
2956 1.29.2.2 skrll return error;
2957 1.29.2.2 skrll }
2958 1.29.2.2 skrll memcpy(&sc->sc_ic.ic_myaddr,
2959 1.29.2.2 skrll &sc->sc_nvm.hw_addr, ETHER_ADDR_LEN);
2960 1.29.2.2 skrll
2961 1.29.2.2 skrll sc->sc_scan_cmd_len = sizeof(struct iwm_scan_cmd)
2962 1.29.2.2 skrll + sc->sc_capa_max_probe_len
2963 1.29.2.2 skrll + IWM_MAX_NUM_SCAN_CHANNELS
2964 1.29.2.2 skrll * sizeof(struct iwm_scan_channel);
2965 1.29.2.2 skrll sc->sc_scan_cmd = kmem_alloc(sc->sc_scan_cmd_len, KM_SLEEP);
2966 1.29.2.2 skrll
2967 1.29.2.2 skrll return 0;
2968 1.29.2.2 skrll }
2969 1.29.2.2 skrll
2970 1.29.2.2 skrll /* Send TX valid antennas before triggering calibrations */
2971 1.29.2.2 skrll if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
2972 1.29.2.2 skrll return error;
2973 1.29.2.2 skrll
2974 1.29.2.2 skrll /*
2975 1.29.2.2 skrll * Send phy configurations command to init uCode
2976 1.29.2.2 skrll * to start the 16.0 uCode init image internal calibrations.
2977 1.29.2.2 skrll */
2978 1.29.2.2 skrll if ((error = iwm_send_phy_cfg_cmd(sc)) != 0 ) {
2979 1.29.2.2 skrll DPRINTF(("%s: failed to run internal calibration: %d\n",
2980 1.29.2.2 skrll DEVNAME(sc), error));
2981 1.29.2.2 skrll return error;
2982 1.29.2.2 skrll }
2983 1.29.2.2 skrll
2984 1.29.2.2 skrll /*
2985 1.29.2.2 skrll * Nothing to do but wait for the init complete notification
2986 1.29.2.2 skrll * from the firmware
2987 1.29.2.2 skrll */
2988 1.29.2.2 skrll while (!sc->sc_init_complete)
2989 1.29.2.2 skrll if ((error = tsleep(&sc->sc_init_complete,
2990 1.29.2.2 skrll 0, "iwminit", 2*hz)) != 0)
2991 1.29.2.2 skrll break;
2992 1.29.2.2 skrll
2993 1.29.2.2 skrll return error;
2994 1.29.2.2 skrll }
2995 1.29.2.2 skrll
2996 1.29.2.2 skrll /*
2997 1.29.2.2 skrll * receive side
2998 1.29.2.2 skrll */
2999 1.29.2.2 skrll
3000 1.29.2.2 skrll /* (re)stock rx ring, called at init-time and at runtime */
3001 1.29.2.2 skrll static int
3002 1.29.2.2 skrll iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx)
3003 1.29.2.2 skrll {
3004 1.29.2.2 skrll struct iwm_rx_ring *ring = &sc->rxq;
3005 1.29.2.2 skrll struct iwm_rx_data *data = &ring->data[idx];
3006 1.29.2.2 skrll struct mbuf *m;
3007 1.29.2.2 skrll int error;
3008 1.29.2.2 skrll int fatal = 0;
3009 1.29.2.2 skrll
3010 1.29.2.2 skrll m = m_gethdr(M_DONTWAIT, MT_DATA);
3011 1.29.2.2 skrll if (m == NULL)
3012 1.29.2.2 skrll return ENOBUFS;
3013 1.29.2.2 skrll
3014 1.29.2.2 skrll if (size <= MCLBYTES) {
3015 1.29.2.2 skrll MCLGET(m, M_DONTWAIT);
3016 1.29.2.2 skrll } else {
3017 1.29.2.2 skrll MEXTMALLOC(m, IWM_RBUF_SIZE, M_DONTWAIT);
3018 1.29.2.2 skrll }
3019 1.29.2.2 skrll if ((m->m_flags & M_EXT) == 0) {
3020 1.29.2.2 skrll m_freem(m);
3021 1.29.2.2 skrll return ENOBUFS;
3022 1.29.2.2 skrll }
3023 1.29.2.2 skrll
3024 1.29.2.2 skrll if (data->m != NULL) {
3025 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, data->map);
3026 1.29.2.2 skrll fatal = 1;
3027 1.29.2.2 skrll }
3028 1.29.2.2 skrll
3029 1.29.2.2 skrll m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
3030 1.29.2.2 skrll if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
3031 1.29.2.2 skrll BUS_DMA_READ|BUS_DMA_NOWAIT)) != 0) {
3032 1.29.2.2 skrll /* XXX */
3033 1.29.2.2 skrll if (fatal)
3034 1.29.2.2 skrll panic("iwm: could not load RX mbuf");
3035 1.29.2.2 skrll m_freem(m);
3036 1.29.2.2 skrll return error;
3037 1.29.2.2 skrll }
3038 1.29.2.2 skrll data->m = m;
3039 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0, size, BUS_DMASYNC_PREREAD);
3040 1.29.2.2 skrll
3041 1.29.2.2 skrll /* Update RX descriptor. */
3042 1.29.2.2 skrll ring->desc[idx] = htole32(data->map->dm_segs[0].ds_addr >> 8);
3043 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
3044 1.29.2.2 skrll idx * sizeof(uint32_t), sizeof(uint32_t), BUS_DMASYNC_PREWRITE);
3045 1.29.2.2 skrll
3046 1.29.2.2 skrll return 0;
3047 1.29.2.2 skrll }
3048 1.29.2.2 skrll
3049 1.29.2.2 skrll /* iwlwifi: mvm/rx.c */
3050 1.29.2.2 skrll #define IWM_RSSI_OFFSET 50
3051 1.29.2.2 skrll static int
3052 1.29.2.2 skrll iwm_mvm_calc_rssi(struct iwm_softc *sc, struct iwm_rx_phy_info *phy_info)
3053 1.29.2.2 skrll {
3054 1.29.2.2 skrll int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm;
3055 1.29.2.2 skrll uint32_t agc_a, agc_b;
3056 1.29.2.2 skrll uint32_t val;
3057 1.29.2.2 skrll
3058 1.29.2.2 skrll val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_AGC_IDX]);
3059 1.29.2.2 skrll agc_a = (val & IWM_OFDM_AGC_A_MSK) >> IWM_OFDM_AGC_A_POS;
3060 1.29.2.2 skrll agc_b = (val & IWM_OFDM_AGC_B_MSK) >> IWM_OFDM_AGC_B_POS;
3061 1.29.2.2 skrll
3062 1.29.2.2 skrll val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_RSSI_AB_IDX]);
3063 1.29.2.2 skrll rssi_a = (val & IWM_OFDM_RSSI_INBAND_A_MSK) >> IWM_OFDM_RSSI_A_POS;
3064 1.29.2.2 skrll rssi_b = (val & IWM_OFDM_RSSI_INBAND_B_MSK) >> IWM_OFDM_RSSI_B_POS;
3065 1.29.2.2 skrll
3066 1.29.2.2 skrll /*
3067 1.29.2.2 skrll * dBm = rssi dB - agc dB - constant.
3068 1.29.2.2 skrll * Higher AGC (higher radio gain) means lower signal.
3069 1.29.2.2 skrll */
3070 1.29.2.2 skrll rssi_a_dbm = rssi_a - IWM_RSSI_OFFSET - agc_a;
3071 1.29.2.2 skrll rssi_b_dbm = rssi_b - IWM_RSSI_OFFSET - agc_b;
3072 1.29.2.2 skrll max_rssi_dbm = MAX(rssi_a_dbm, rssi_b_dbm);
3073 1.29.2.2 skrll
3074 1.29.2.2 skrll DPRINTF(("Rssi In A %d B %d Max %d AGCA %d AGCB %d\n",
3075 1.29.2.2 skrll rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b));
3076 1.29.2.2 skrll
3077 1.29.2.2 skrll return max_rssi_dbm;
3078 1.29.2.2 skrll }
3079 1.29.2.2 skrll
3080 1.29.2.2 skrll /* iwlwifi: mvm/rx.c */
3081 1.29.2.2 skrll /*
3082 1.29.2.2 skrll * iwm_mvm_get_signal_strength - use new rx PHY INFO API
3083 1.29.2.2 skrll * values are reported by the fw as positive values - need to negate
3084 1.29.2.2 skrll * to obtain their dBM. Account for missing antennas by replacing 0
3085 1.29.2.2 skrll * values by -256dBm: practically 0 power and a non-feasible 8 bit value.
3086 1.29.2.2 skrll */
3087 1.29.2.2 skrll static int
3088 1.29.2.2 skrll iwm_mvm_get_signal_strength(struct iwm_softc *sc,
3089 1.29.2.2 skrll struct iwm_rx_phy_info *phy_info)
3090 1.29.2.2 skrll {
3091 1.29.2.2 skrll int energy_a, energy_b, energy_c, max_energy;
3092 1.29.2.2 skrll uint32_t val;
3093 1.29.2.2 skrll
3094 1.29.2.2 skrll val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]);
3095 1.29.2.2 skrll energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >>
3096 1.29.2.2 skrll IWM_RX_INFO_ENERGY_ANT_A_POS;
3097 1.29.2.2 skrll energy_a = energy_a ? -energy_a : -256;
3098 1.29.2.2 skrll energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >>
3099 1.29.2.2 skrll IWM_RX_INFO_ENERGY_ANT_B_POS;
3100 1.29.2.2 skrll energy_b = energy_b ? -energy_b : -256;
3101 1.29.2.2 skrll energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >>
3102 1.29.2.2 skrll IWM_RX_INFO_ENERGY_ANT_C_POS;
3103 1.29.2.2 skrll energy_c = energy_c ? -energy_c : -256;
3104 1.29.2.2 skrll max_energy = MAX(energy_a, energy_b);
3105 1.29.2.2 skrll max_energy = MAX(max_energy, energy_c);
3106 1.29.2.2 skrll
3107 1.29.2.2 skrll DPRINTFN(12, ("energy In A %d B %d C %d, and max %d\n",
3108 1.29.2.2 skrll energy_a, energy_b, energy_c, max_energy));
3109 1.29.2.2 skrll
3110 1.29.2.2 skrll return max_energy;
3111 1.29.2.2 skrll }
3112 1.29.2.2 skrll
3113 1.29.2.2 skrll static void
3114 1.29.2.2 skrll iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc,
3115 1.29.2.2 skrll struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
3116 1.29.2.2 skrll {
3117 1.29.2.2 skrll struct iwm_rx_phy_info *phy_info = (void *)pkt->data;
3118 1.29.2.2 skrll
3119 1.29.2.2 skrll DPRINTFN(20, ("received PHY stats\n"));
3120 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt),
3121 1.29.2.2 skrll sizeof(*phy_info), BUS_DMASYNC_POSTREAD);
3122 1.29.2.2 skrll
3123 1.29.2.2 skrll memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info));
3124 1.29.2.2 skrll }
3125 1.29.2.2 skrll
3126 1.29.2.2 skrll /*
3127 1.29.2.2 skrll * Retrieve the average noise (in dBm) among receivers.
3128 1.29.2.2 skrll */
3129 1.29.2.2 skrll static int
3130 1.29.2.2 skrll iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *stats)
3131 1.29.2.2 skrll {
3132 1.29.2.2 skrll int i, total, nbant, noise;
3133 1.29.2.2 skrll
3134 1.29.2.2 skrll total = nbant = noise = 0;
3135 1.29.2.2 skrll for (i = 0; i < 3; i++) {
3136 1.29.2.2 skrll noise = le32toh(stats->beacon_silence_rssi[i]) & 0xff;
3137 1.29.2.2 skrll if (noise) {
3138 1.29.2.2 skrll total += noise;
3139 1.29.2.2 skrll nbant++;
3140 1.29.2.2 skrll }
3141 1.29.2.2 skrll }
3142 1.29.2.2 skrll
3143 1.29.2.2 skrll /* There should be at least one antenna but check anyway. */
3144 1.29.2.2 skrll return (nbant == 0) ? -127 : (total / nbant) - 107;
3145 1.29.2.2 skrll }
3146 1.29.2.2 skrll
3147 1.29.2.2 skrll /*
3148 1.29.2.2 skrll * iwm_mvm_rx_rx_mpdu - IWM_REPLY_RX_MPDU_CMD handler
3149 1.29.2.2 skrll *
3150 1.29.2.2 skrll * Handles the actual data of the Rx packet from the fw
3151 1.29.2.2 skrll */
3152 1.29.2.2 skrll static void
3153 1.29.2.2 skrll iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc,
3154 1.29.2.2 skrll struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
3155 1.29.2.2 skrll {
3156 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3157 1.29.2.2 skrll struct ieee80211_frame *wh;
3158 1.29.2.2 skrll struct ieee80211_node *ni;
3159 1.29.2.2 skrll struct ieee80211_channel *c = NULL;
3160 1.29.2.2 skrll struct mbuf *m;
3161 1.29.2.2 skrll struct iwm_rx_phy_info *phy_info;
3162 1.29.2.2 skrll struct iwm_rx_mpdu_res_start *rx_res;
3163 1.29.2.2 skrll int device_timestamp;
3164 1.29.2.2 skrll uint32_t len;
3165 1.29.2.2 skrll uint32_t rx_pkt_status;
3166 1.29.2.2 skrll int rssi;
3167 1.29.2.2 skrll
3168 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
3169 1.29.2.2 skrll BUS_DMASYNC_POSTREAD);
3170 1.29.2.2 skrll
3171 1.29.2.2 skrll phy_info = &sc->sc_last_phy_info;
3172 1.29.2.2 skrll rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data;
3173 1.29.2.2 skrll wh = (struct ieee80211_frame *)(pkt->data + sizeof(*rx_res));
3174 1.29.2.2 skrll len = le16toh(rx_res->byte_count);
3175 1.29.2.2 skrll rx_pkt_status = le32toh(*(uint32_t *)(pkt->data + sizeof(*rx_res) + len));
3176 1.29.2.2 skrll
3177 1.29.2.2 skrll m = data->m;
3178 1.29.2.2 skrll m->m_data = pkt->data + sizeof(*rx_res);
3179 1.29.2.2 skrll m->m_pkthdr.len = m->m_len = len;
3180 1.29.2.2 skrll
3181 1.29.2.2 skrll if (__predict_false(phy_info->cfg_phy_cnt > 20)) {
3182 1.29.2.2 skrll DPRINTF(("dsp size out of range [0,20]: %d\n",
3183 1.29.2.2 skrll phy_info->cfg_phy_cnt));
3184 1.29.2.2 skrll return;
3185 1.29.2.2 skrll }
3186 1.29.2.2 skrll
3187 1.29.2.2 skrll if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) ||
3188 1.29.2.2 skrll !(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK)) {
3189 1.29.2.2 skrll DPRINTF(("Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status));
3190 1.29.2.2 skrll return; /* drop */
3191 1.29.2.2 skrll }
3192 1.29.2.2 skrll
3193 1.29.2.2 skrll device_timestamp = le32toh(phy_info->system_timestamp);
3194 1.29.2.2 skrll
3195 1.29.2.2 skrll if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_RX_ENERGY_API) {
3196 1.29.2.2 skrll rssi = iwm_mvm_get_signal_strength(sc, phy_info);
3197 1.29.2.2 skrll } else {
3198 1.29.2.2 skrll rssi = iwm_mvm_calc_rssi(sc, phy_info);
3199 1.29.2.2 skrll }
3200 1.29.2.2 skrll rssi = -rssi;
3201 1.29.2.2 skrll
3202 1.29.2.2 skrll if (ic->ic_state == IEEE80211_S_SCAN)
3203 1.29.2.2 skrll iwm_fix_channel(ic, m);
3204 1.29.2.2 skrll
3205 1.29.2.2 skrll /* replenish ring for the buffer we're going to feed to the sharks */
3206 1.29.2.2 skrll if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0)
3207 1.29.2.2 skrll return;
3208 1.29.2.2 skrll
3209 1.29.2.2 skrll m->m_pkthdr.rcvif = IC2IFP(ic);
3210 1.29.2.2 skrll
3211 1.29.2.2 skrll if (sc->sc_scanband == IEEE80211_CHAN_5GHZ) {
3212 1.29.2.2 skrll if (le32toh(phy_info->channel) < __arraycount(ic->ic_channels))
3213 1.29.2.2 skrll c = &ic->ic_channels[le32toh(phy_info->channel)];
3214 1.29.2.2 skrll }
3215 1.29.2.2 skrll
3216 1.29.2.2 skrll ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
3217 1.29.2.2 skrll if (c)
3218 1.29.2.2 skrll ni->ni_chan = c;
3219 1.29.2.2 skrll
3220 1.29.2.2 skrll if (sc->sc_drvbpf != NULL) {
3221 1.29.2.2 skrll struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap;
3222 1.29.2.2 skrll
3223 1.29.2.2 skrll tap->wr_flags = 0;
3224 1.29.2.2 skrll if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE))
3225 1.29.2.2 skrll tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
3226 1.29.2.2 skrll tap->wr_chan_freq =
3227 1.29.2.2 skrll htole16(ic->ic_channels[phy_info->channel].ic_freq);
3228 1.29.2.2 skrll tap->wr_chan_flags =
3229 1.29.2.2 skrll htole16(ic->ic_channels[phy_info->channel].ic_flags);
3230 1.29.2.2 skrll tap->wr_dbm_antsignal = (int8_t)rssi;
3231 1.29.2.2 skrll tap->wr_dbm_antnoise = (int8_t)sc->sc_noise;
3232 1.29.2.2 skrll tap->wr_tsft = phy_info->system_timestamp;
3233 1.29.2.2 skrll switch (phy_info->rate) {
3234 1.29.2.2 skrll /* CCK rates. */
3235 1.29.2.2 skrll case 10: tap->wr_rate = 2; break;
3236 1.29.2.2 skrll case 20: tap->wr_rate = 4; break;
3237 1.29.2.2 skrll case 55: tap->wr_rate = 11; break;
3238 1.29.2.2 skrll case 110: tap->wr_rate = 22; break;
3239 1.29.2.2 skrll /* OFDM rates. */
3240 1.29.2.2 skrll case 0xd: tap->wr_rate = 12; break;
3241 1.29.2.2 skrll case 0xf: tap->wr_rate = 18; break;
3242 1.29.2.2 skrll case 0x5: tap->wr_rate = 24; break;
3243 1.29.2.2 skrll case 0x7: tap->wr_rate = 36; break;
3244 1.29.2.2 skrll case 0x9: tap->wr_rate = 48; break;
3245 1.29.2.2 skrll case 0xb: tap->wr_rate = 72; break;
3246 1.29.2.2 skrll case 0x1: tap->wr_rate = 96; break;
3247 1.29.2.2 skrll case 0x3: tap->wr_rate = 108; break;
3248 1.29.2.2 skrll /* Unknown rate: should not happen. */
3249 1.29.2.2 skrll default: tap->wr_rate = 0;
3250 1.29.2.2 skrll }
3251 1.29.2.2 skrll
3252 1.29.2.2 skrll bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
3253 1.29.2.2 skrll }
3254 1.29.2.2 skrll ieee80211_input(ic, m, ni, rssi, device_timestamp);
3255 1.29.2.2 skrll ieee80211_free_node(ni);
3256 1.29.2.2 skrll }
3257 1.29.2.2 skrll
3258 1.29.2.2 skrll static void
3259 1.29.2.2 skrll iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
3260 1.29.2.2 skrll struct iwm_node *in)
3261 1.29.2.2 skrll {
3262 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3263 1.29.2.2 skrll struct ifnet *ifp = IC2IFP(ic);
3264 1.29.2.2 skrll struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
3265 1.29.2.2 skrll int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
3266 1.29.2.2 skrll int failack = tx_resp->failure_frame;
3267 1.29.2.2 skrll
3268 1.29.2.2 skrll KASSERT(tx_resp->frame_count == 1);
3269 1.29.2.2 skrll
3270 1.29.2.2 skrll /* Update rate control statistics. */
3271 1.29.2.2 skrll in->in_amn.amn_txcnt++;
3272 1.29.2.2 skrll if (failack > 0) {
3273 1.29.2.2 skrll in->in_amn.amn_retrycnt++;
3274 1.29.2.2 skrll }
3275 1.29.2.2 skrll
3276 1.29.2.2 skrll if (status != IWM_TX_STATUS_SUCCESS &&
3277 1.29.2.2 skrll status != IWM_TX_STATUS_DIRECT_DONE)
3278 1.29.2.2 skrll ifp->if_oerrors++;
3279 1.29.2.2 skrll else
3280 1.29.2.2 skrll ifp->if_opackets++;
3281 1.29.2.2 skrll }
3282 1.29.2.2 skrll
3283 1.29.2.2 skrll static void
3284 1.29.2.2 skrll iwm_mvm_rx_tx_cmd(struct iwm_softc *sc,
3285 1.29.2.2 skrll struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
3286 1.29.2.2 skrll {
3287 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3288 1.29.2.2 skrll struct ifnet *ifp = IC2IFP(ic);
3289 1.29.2.2 skrll struct iwm_cmd_header *cmd_hdr = &pkt->hdr;
3290 1.29.2.2 skrll int idx = cmd_hdr->idx;
3291 1.29.2.2 skrll int qid = cmd_hdr->qid;
3292 1.29.2.2 skrll struct iwm_tx_ring *ring = &sc->txq[qid];
3293 1.29.2.2 skrll struct iwm_tx_data *txd = &ring->data[idx];
3294 1.29.2.2 skrll struct iwm_node *in = txd->in;
3295 1.29.2.2 skrll
3296 1.29.2.2 skrll if (txd->done) {
3297 1.29.2.2 skrll DPRINTF(("%s: got tx interrupt that's already been handled!\n",
3298 1.29.2.2 skrll DEVNAME(sc)));
3299 1.29.2.2 skrll return;
3300 1.29.2.2 skrll }
3301 1.29.2.2 skrll
3302 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
3303 1.29.2.2 skrll BUS_DMASYNC_POSTREAD);
3304 1.29.2.2 skrll
3305 1.29.2.2 skrll sc->sc_tx_timer = 0;
3306 1.29.2.2 skrll
3307 1.29.2.2 skrll iwm_mvm_rx_tx_cmd_single(sc, pkt, in);
3308 1.29.2.2 skrll
3309 1.29.2.2 skrll /* Unmap and free mbuf. */
3310 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize,
3311 1.29.2.2 skrll BUS_DMASYNC_POSTWRITE);
3312 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, txd->map);
3313 1.29.2.2 skrll m_freem(txd->m);
3314 1.29.2.2 skrll
3315 1.29.2.2 skrll DPRINTFN(8, ("free txd %p, in %p\n", txd, txd->in));
3316 1.29.2.2 skrll KASSERT(txd->done == 0);
3317 1.29.2.2 skrll txd->done = 1;
3318 1.29.2.2 skrll KASSERT(txd->in);
3319 1.29.2.2 skrll
3320 1.29.2.2 skrll txd->m = NULL;
3321 1.29.2.2 skrll txd->in = NULL;
3322 1.29.2.2 skrll ieee80211_free_node(&in->in_ni);
3323 1.29.2.2 skrll
3324 1.29.2.2 skrll if (--ring->queued < IWM_TX_RING_LOMARK) {
3325 1.29.2.2 skrll sc->qfullmsk &= ~(1 << ring->qid);
3326 1.29.2.2 skrll if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) {
3327 1.29.2.2 skrll ifp->if_flags &= ~IFF_OACTIVE;
3328 1.29.2.2 skrll /*
3329 1.29.2.2 skrll * Well, we're in interrupt context, but then again
3330 1.29.2.2 skrll * I guess net80211 does all sorts of stunts in
3331 1.29.2.2 skrll * interrupt context, so maybe this is no biggie.
3332 1.29.2.2 skrll */
3333 1.29.2.2 skrll (*ifp->if_start)(ifp);
3334 1.29.2.2 skrll }
3335 1.29.2.2 skrll }
3336 1.29.2.2 skrll }
3337 1.29.2.2 skrll
3338 1.29.2.2 skrll /*
3339 1.29.2.2 skrll * BEGIN iwlwifi/mvm/binding.c
3340 1.29.2.2 skrll */
3341 1.29.2.2 skrll
3342 1.29.2.2 skrll static int
3343 1.29.2.2 skrll iwm_mvm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action)
3344 1.29.2.2 skrll {
3345 1.29.2.2 skrll struct iwm_binding_cmd cmd;
3346 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *phyctxt = in->in_phyctxt;
3347 1.29.2.2 skrll int i, ret;
3348 1.29.2.2 skrll uint32_t status;
3349 1.29.2.2 skrll
3350 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
3351 1.29.2.2 skrll
3352 1.29.2.2 skrll cmd.id_and_color
3353 1.29.2.2 skrll = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color));
3354 1.29.2.2 skrll cmd.action = htole32(action);
3355 1.29.2.2 skrll cmd.phy = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color));
3356 1.29.2.2 skrll
3357 1.29.2.2 skrll cmd.macs[0] = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
3358 1.29.2.2 skrll for (i = 1; i < IWM_MAX_MACS_IN_BINDING; i++)
3359 1.29.2.2 skrll cmd.macs[i] = htole32(IWM_FW_CTXT_INVALID);
3360 1.29.2.2 skrll
3361 1.29.2.2 skrll status = 0;
3362 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_BINDING_CONTEXT_CMD,
3363 1.29.2.2 skrll sizeof(cmd), &cmd, &status);
3364 1.29.2.2 skrll if (ret) {
3365 1.29.2.2 skrll DPRINTF(("%s: Failed to send binding (action:%d): %d\n",
3366 1.29.2.2 skrll DEVNAME(sc), action, ret));
3367 1.29.2.2 skrll return ret;
3368 1.29.2.2 skrll }
3369 1.29.2.2 skrll
3370 1.29.2.2 skrll if (status) {
3371 1.29.2.2 skrll DPRINTF(("%s: Binding command failed: %u\n", DEVNAME(sc),
3372 1.29.2.2 skrll status));
3373 1.29.2.2 skrll ret = EIO;
3374 1.29.2.2 skrll }
3375 1.29.2.2 skrll
3376 1.29.2.2 skrll return ret;
3377 1.29.2.2 skrll }
3378 1.29.2.2 skrll
3379 1.29.2.2 skrll static int
3380 1.29.2.2 skrll iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in, int add)
3381 1.29.2.2 skrll {
3382 1.29.2.2 skrll return iwm_mvm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD);
3383 1.29.2.2 skrll }
3384 1.29.2.2 skrll
3385 1.29.2.2 skrll static int
3386 1.29.2.2 skrll iwm_mvm_binding_add_vif(struct iwm_softc *sc, struct iwm_node *in)
3387 1.29.2.2 skrll {
3388 1.29.2.2 skrll return iwm_mvm_binding_update(sc, in, IWM_FW_CTXT_ACTION_ADD);
3389 1.29.2.2 skrll }
3390 1.29.2.2 skrll
3391 1.29.2.2 skrll /*
3392 1.29.2.2 skrll * END iwlwifi/mvm/binding.c
3393 1.29.2.2 skrll */
3394 1.29.2.2 skrll
3395 1.29.2.2 skrll /*
3396 1.29.2.2 skrll * BEGIN iwlwifi/mvm/phy-ctxt.c
3397 1.29.2.2 skrll */
3398 1.29.2.2 skrll
3399 1.29.2.2 skrll /*
3400 1.29.2.2 skrll * Construct the generic fields of the PHY context command
3401 1.29.2.2 skrll */
3402 1.29.2.2 skrll static void
3403 1.29.2.2 skrll iwm_mvm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt,
3404 1.29.2.2 skrll struct iwm_phy_context_cmd *cmd, uint32_t action, uint32_t apply_time)
3405 1.29.2.2 skrll {
3406 1.29.2.2 skrll memset(cmd, 0, sizeof(struct iwm_phy_context_cmd));
3407 1.29.2.2 skrll
3408 1.29.2.2 skrll cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id,
3409 1.29.2.2 skrll ctxt->color));
3410 1.29.2.2 skrll cmd->action = htole32(action);
3411 1.29.2.2 skrll cmd->apply_time = htole32(apply_time);
3412 1.29.2.2 skrll }
3413 1.29.2.2 skrll
3414 1.29.2.2 skrll /*
3415 1.29.2.2 skrll * Add the phy configuration to the PHY context command
3416 1.29.2.2 skrll */
3417 1.29.2.2 skrll static void
3418 1.29.2.2 skrll iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc,
3419 1.29.2.2 skrll struct iwm_phy_context_cmd *cmd, struct ieee80211_channel *chan,
3420 1.29.2.2 skrll uint8_t chains_static, uint8_t chains_dynamic)
3421 1.29.2.2 skrll {
3422 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3423 1.29.2.2 skrll uint8_t active_cnt, idle_cnt;
3424 1.29.2.2 skrll
3425 1.29.2.2 skrll cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
3426 1.29.2.2 skrll IWM_PHY_BAND_24 : IWM_PHY_BAND_5;
3427 1.29.2.2 skrll
3428 1.29.2.2 skrll cmd->ci.channel = ieee80211_chan2ieee(ic, chan);
3429 1.29.2.2 skrll cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
3430 1.29.2.2 skrll cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
3431 1.29.2.2 skrll
3432 1.29.2.2 skrll /* Set rx the chains */
3433 1.29.2.2 skrll idle_cnt = chains_static;
3434 1.29.2.2 skrll active_cnt = chains_dynamic;
3435 1.29.2.2 skrll
3436 1.29.2.2 skrll cmd->rxchain_info = htole32(IWM_FW_VALID_RX_ANT(sc) <<
3437 1.29.2.2 skrll IWM_PHY_RX_CHAIN_VALID_POS);
3438 1.29.2.2 skrll cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS);
3439 1.29.2.2 skrll cmd->rxchain_info |= htole32(active_cnt <<
3440 1.29.2.2 skrll IWM_PHY_RX_CHAIN_MIMO_CNT_POS);
3441 1.29.2.2 skrll
3442 1.29.2.2 skrll cmd->txchain_info = htole32(IWM_FW_VALID_TX_ANT(sc));
3443 1.29.2.2 skrll }
3444 1.29.2.2 skrll
3445 1.29.2.2 skrll /*
3446 1.29.2.2 skrll * Send a command
3447 1.29.2.2 skrll * only if something in the configuration changed: in case that this is the
3448 1.29.2.2 skrll * first time that the phy configuration is applied or in case that the phy
3449 1.29.2.2 skrll * configuration changed from the previous apply.
3450 1.29.2.2 skrll */
3451 1.29.2.2 skrll static int
3452 1.29.2.2 skrll iwm_mvm_phy_ctxt_apply(struct iwm_softc *sc,
3453 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *ctxt,
3454 1.29.2.2 skrll uint8_t chains_static, uint8_t chains_dynamic,
3455 1.29.2.2 skrll uint32_t action, uint32_t apply_time)
3456 1.29.2.2 skrll {
3457 1.29.2.2 skrll struct iwm_phy_context_cmd cmd;
3458 1.29.2.2 skrll int ret;
3459 1.29.2.2 skrll
3460 1.29.2.2 skrll /* Set the command header fields */
3461 1.29.2.2 skrll iwm_mvm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time);
3462 1.29.2.2 skrll
3463 1.29.2.2 skrll /* Set the command data */
3464 1.29.2.2 skrll iwm_mvm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel,
3465 1.29.2.2 skrll chains_static, chains_dynamic);
3466 1.29.2.2 skrll
3467 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, IWM_CMD_SYNC,
3468 1.29.2.2 skrll sizeof(struct iwm_phy_context_cmd), &cmd);
3469 1.29.2.2 skrll if (ret) {
3470 1.29.2.2 skrll DPRINTF(("PHY ctxt cmd error. ret=%d\n", ret));
3471 1.29.2.2 skrll }
3472 1.29.2.2 skrll return ret;
3473 1.29.2.2 skrll }
3474 1.29.2.2 skrll
3475 1.29.2.2 skrll /*
3476 1.29.2.2 skrll * Send a command to add a PHY context based on the current HW configuration.
3477 1.29.2.2 skrll */
3478 1.29.2.2 skrll static int
3479 1.29.2.2 skrll iwm_mvm_phy_ctxt_add(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt,
3480 1.29.2.2 skrll struct ieee80211_channel *chan,
3481 1.29.2.2 skrll uint8_t chains_static, uint8_t chains_dynamic)
3482 1.29.2.2 skrll {
3483 1.29.2.2 skrll ctxt->channel = chan;
3484 1.29.2.2 skrll return iwm_mvm_phy_ctxt_apply(sc, ctxt,
3485 1.29.2.2 skrll chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_ADD, 0);
3486 1.29.2.2 skrll }
3487 1.29.2.2 skrll
3488 1.29.2.2 skrll /*
3489 1.29.2.2 skrll * Send a command to modify the PHY context based on the current HW
3490 1.29.2.2 skrll * configuration. Note that the function does not check that the configuration
3491 1.29.2.2 skrll * changed.
3492 1.29.2.2 skrll */
3493 1.29.2.2 skrll static int
3494 1.29.2.2 skrll iwm_mvm_phy_ctxt_changed(struct iwm_softc *sc,
3495 1.29.2.2 skrll struct iwm_mvm_phy_ctxt *ctxt, struct ieee80211_channel *chan,
3496 1.29.2.2 skrll uint8_t chains_static, uint8_t chains_dynamic)
3497 1.29.2.2 skrll {
3498 1.29.2.2 skrll ctxt->channel = chan;
3499 1.29.2.2 skrll return iwm_mvm_phy_ctxt_apply(sc, ctxt,
3500 1.29.2.2 skrll chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, 0);
3501 1.29.2.2 skrll }
3502 1.29.2.2 skrll
3503 1.29.2.2 skrll /*
3504 1.29.2.2 skrll * END iwlwifi/mvm/phy-ctxt.c
3505 1.29.2.2 skrll */
3506 1.29.2.2 skrll
3507 1.29.2.2 skrll /*
3508 1.29.2.2 skrll * transmit side
3509 1.29.2.2 skrll */
3510 1.29.2.2 skrll
3511 1.29.2.2 skrll /*
3512 1.29.2.2 skrll * Send a command to the firmware. We try to implement the Linux
3513 1.29.2.2 skrll * driver interface for the routine.
3514 1.29.2.2 skrll * mostly from if_iwn (iwn_cmd()).
3515 1.29.2.2 skrll *
3516 1.29.2.2 skrll * For now, we always copy the first part and map the second one (if it exists).
3517 1.29.2.2 skrll */
3518 1.29.2.2 skrll static int
3519 1.29.2.2 skrll iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
3520 1.29.2.2 skrll {
3521 1.29.2.2 skrll struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
3522 1.29.2.2 skrll struct iwm_tfd *desc;
3523 1.29.2.2 skrll struct iwm_tx_data *data;
3524 1.29.2.2 skrll struct iwm_device_cmd *cmd;
3525 1.29.2.2 skrll struct mbuf *m;
3526 1.29.2.2 skrll bus_addr_t paddr;
3527 1.29.2.2 skrll uint32_t addr_lo;
3528 1.29.2.2 skrll int error = 0, i, paylen, off, s;
3529 1.29.2.2 skrll int code;
3530 1.29.2.2 skrll int async, wantresp;
3531 1.29.2.2 skrll
3532 1.29.2.2 skrll code = hcmd->id;
3533 1.29.2.2 skrll async = hcmd->flags & IWM_CMD_ASYNC;
3534 1.29.2.2 skrll wantresp = hcmd->flags & IWM_CMD_WANT_SKB;
3535 1.29.2.2 skrll
3536 1.29.2.2 skrll for (i = 0, paylen = 0; i < __arraycount(hcmd->len); i++) {
3537 1.29.2.2 skrll paylen += hcmd->len[i];
3538 1.29.2.2 skrll }
3539 1.29.2.2 skrll
3540 1.29.2.2 skrll /* if the command wants an answer, busy sc_cmd_resp */
3541 1.29.2.2 skrll if (wantresp) {
3542 1.29.2.2 skrll KASSERT(!async);
3543 1.29.2.2 skrll while (sc->sc_wantresp != -1)
3544 1.29.2.2 skrll tsleep(&sc->sc_wantresp, 0, "iwmcmdsl", 0);
3545 1.29.2.2 skrll sc->sc_wantresp = ring->qid << 16 | ring->cur;
3546 1.29.2.2 skrll DPRINTFN(12, ("wantresp is %x\n", sc->sc_wantresp));
3547 1.29.2.2 skrll }
3548 1.29.2.2 skrll
3549 1.29.2.2 skrll /*
3550 1.29.2.2 skrll * Is the hardware still available? (after e.g. above wait).
3551 1.29.2.2 skrll */
3552 1.29.2.2 skrll s = splnet();
3553 1.29.2.2 skrll if (sc->sc_flags & IWM_FLAG_STOPPED) {
3554 1.29.2.2 skrll error = ENXIO;
3555 1.29.2.2 skrll goto out;
3556 1.29.2.2 skrll }
3557 1.29.2.2 skrll
3558 1.29.2.2 skrll desc = &ring->desc[ring->cur];
3559 1.29.2.2 skrll data = &ring->data[ring->cur];
3560 1.29.2.2 skrll
3561 1.29.2.2 skrll if (paylen > sizeof(cmd->data)) {
3562 1.29.2.2 skrll /* Command is too large */
3563 1.29.2.2 skrll if (sizeof(cmd->hdr) + paylen > IWM_RBUF_SIZE) {
3564 1.29.2.2 skrll error = EINVAL;
3565 1.29.2.2 skrll goto out;
3566 1.29.2.2 skrll }
3567 1.29.2.2 skrll m = m_gethdr(M_DONTWAIT, MT_DATA);
3568 1.29.2.2 skrll if (m == NULL) {
3569 1.29.2.2 skrll error = ENOMEM;
3570 1.29.2.2 skrll goto out;
3571 1.29.2.2 skrll }
3572 1.29.2.2 skrll MEXTMALLOC(m, IWM_RBUF_SIZE, M_DONTWAIT);
3573 1.29.2.2 skrll if (!(m->m_flags & M_EXT)) {
3574 1.29.2.2 skrll m_freem(m);
3575 1.29.2.2 skrll error = ENOMEM;
3576 1.29.2.2 skrll goto out;
3577 1.29.2.2 skrll }
3578 1.29.2.2 skrll cmd = mtod(m, struct iwm_device_cmd *);
3579 1.29.2.2 skrll error = bus_dmamap_load(sc->sc_dmat, data->map, cmd,
3580 1.29.2.2 skrll IWM_RBUF_SIZE, NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
3581 1.29.2.2 skrll if (error != 0) {
3582 1.29.2.2 skrll m_freem(m);
3583 1.29.2.2 skrll goto out;
3584 1.29.2.2 skrll }
3585 1.29.2.2 skrll data->m = m;
3586 1.29.2.2 skrll paddr = data->map->dm_segs[0].ds_addr;
3587 1.29.2.2 skrll } else {
3588 1.29.2.2 skrll cmd = &ring->cmd[ring->cur];
3589 1.29.2.2 skrll paddr = data->cmd_paddr;
3590 1.29.2.2 skrll }
3591 1.29.2.2 skrll
3592 1.29.2.2 skrll cmd->hdr.code = code;
3593 1.29.2.2 skrll cmd->hdr.flags = 0;
3594 1.29.2.2 skrll cmd->hdr.qid = ring->qid;
3595 1.29.2.2 skrll cmd->hdr.idx = ring->cur;
3596 1.29.2.2 skrll
3597 1.29.2.2 skrll for (i = 0, off = 0; i < __arraycount(hcmd->data); i++) {
3598 1.29.2.2 skrll if (hcmd->len[i] == 0)
3599 1.29.2.2 skrll continue;
3600 1.29.2.2 skrll memcpy(cmd->data + off, hcmd->data[i], hcmd->len[i]);
3601 1.29.2.2 skrll off += hcmd->len[i];
3602 1.29.2.2 skrll }
3603 1.29.2.2 skrll KASSERT(off == paylen);
3604 1.29.2.2 skrll
3605 1.29.2.2 skrll /* lo field is not aligned */
3606 1.29.2.2 skrll addr_lo = htole32((uint32_t)paddr);
3607 1.29.2.2 skrll memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t));
3608 1.29.2.2 skrll desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(paddr)
3609 1.29.2.2 skrll | ((sizeof(cmd->hdr) + paylen) << 4));
3610 1.29.2.2 skrll desc->num_tbs = 1;
3611 1.29.2.2 skrll
3612 1.29.2.2 skrll DPRINTFN(8, ("iwm_send_cmd 0x%x size=%zu %s\n",
3613 1.29.2.2 skrll code, sizeof(cmd->hdr) + paylen, async ? " (async)" : ""));
3614 1.29.2.2 skrll
3615 1.29.2.2 skrll if (paylen > sizeof(cmd->data)) {
3616 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
3617 1.29.2.2 skrll sizeof(cmd->hdr) + paylen, BUS_DMASYNC_PREWRITE);
3618 1.29.2.2 skrll } else {
3619 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
3620 1.29.2.2 skrll (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr,
3621 1.29.2.2 skrll sizeof(cmd->hdr) + paylen, BUS_DMASYNC_PREWRITE);
3622 1.29.2.2 skrll }
3623 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
3624 1.29.2.2 skrll (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
3625 1.29.2.2 skrll sizeof (*desc), BUS_DMASYNC_PREWRITE);
3626 1.29.2.2 skrll
3627 1.29.2.2 skrll IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
3628 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
3629 1.29.2.2 skrll if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
3630 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
3631 1.29.2.2 skrll (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
3632 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000)) {
3633 1.29.2.2 skrll DPRINTF(("%s: acquiring device failed\n", DEVNAME(sc)));
3634 1.29.2.2 skrll error = EBUSY;
3635 1.29.2.2 skrll goto out;
3636 1.29.2.2 skrll }
3637 1.29.2.2 skrll
3638 1.29.2.2 skrll #if 0
3639 1.29.2.2 skrll iwm_update_sched(sc, ring->qid, ring->cur, 0, 0);
3640 1.29.2.2 skrll #endif
3641 1.29.2.2 skrll DPRINTF(("sending command 0x%x qid %d, idx %d\n",
3642 1.29.2.2 skrll code, ring->qid, ring->cur));
3643 1.29.2.2 skrll
3644 1.29.2.2 skrll /* Kick command ring. */
3645 1.29.2.2 skrll ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT;
3646 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
3647 1.29.2.2 skrll
3648 1.29.2.2 skrll if (!async) {
3649 1.29.2.2 skrll /* m..m-mmyy-mmyyyy-mym-ym m-my generation */
3650 1.29.2.2 skrll int generation = sc->sc_generation;
3651 1.29.2.2 skrll error = tsleep(desc, PCATCH, "iwmcmd", hz);
3652 1.29.2.2 skrll if (error == 0) {
3653 1.29.2.2 skrll /* if hardware is no longer up, return error */
3654 1.29.2.2 skrll if (generation != sc->sc_generation) {
3655 1.29.2.2 skrll error = ENXIO;
3656 1.29.2.2 skrll } else {
3657 1.29.2.2 skrll hcmd->resp_pkt = (void *)sc->sc_cmd_resp;
3658 1.29.2.2 skrll }
3659 1.29.2.2 skrll }
3660 1.29.2.2 skrll }
3661 1.29.2.2 skrll out:
3662 1.29.2.2 skrll if (wantresp && error != 0) {
3663 1.29.2.2 skrll iwm_free_resp(sc, hcmd);
3664 1.29.2.2 skrll }
3665 1.29.2.2 skrll splx(s);
3666 1.29.2.2 skrll
3667 1.29.2.2 skrll return error;
3668 1.29.2.2 skrll }
3669 1.29.2.2 skrll
3670 1.29.2.2 skrll /* iwlwifi: mvm/utils.c */
3671 1.29.2.2 skrll static int
3672 1.29.2.2 skrll iwm_mvm_send_cmd_pdu(struct iwm_softc *sc, uint8_t id,
3673 1.29.2.2 skrll uint32_t flags, uint16_t len, const void *data)
3674 1.29.2.2 skrll {
3675 1.29.2.2 skrll struct iwm_host_cmd cmd = {
3676 1.29.2.2 skrll .id = id,
3677 1.29.2.2 skrll .len = { len, },
3678 1.29.2.2 skrll .data = { data, },
3679 1.29.2.2 skrll .flags = flags,
3680 1.29.2.2 skrll };
3681 1.29.2.2 skrll
3682 1.29.2.2 skrll return iwm_send_cmd(sc, &cmd);
3683 1.29.2.2 skrll }
3684 1.29.2.2 skrll
3685 1.29.2.2 skrll /* iwlwifi: mvm/utils.c */
3686 1.29.2.2 skrll static int
3687 1.29.2.2 skrll iwm_mvm_send_cmd_status(struct iwm_softc *sc,
3688 1.29.2.2 skrll struct iwm_host_cmd *cmd, uint32_t *status)
3689 1.29.2.2 skrll {
3690 1.29.2.2 skrll struct iwm_rx_packet *pkt;
3691 1.29.2.2 skrll struct iwm_cmd_response *resp;
3692 1.29.2.2 skrll int error, resp_len;
3693 1.29.2.2 skrll
3694 1.29.2.2 skrll //lockdep_assert_held(&mvm->mutex);
3695 1.29.2.2 skrll
3696 1.29.2.2 skrll KASSERT((cmd->flags & IWM_CMD_WANT_SKB) == 0);
3697 1.29.2.2 skrll cmd->flags |= IWM_CMD_SYNC | IWM_CMD_WANT_SKB;
3698 1.29.2.2 skrll
3699 1.29.2.2 skrll if ((error = iwm_send_cmd(sc, cmd)) != 0)
3700 1.29.2.2 skrll return error;
3701 1.29.2.2 skrll pkt = cmd->resp_pkt;
3702 1.29.2.2 skrll
3703 1.29.2.2 skrll /* Can happen if RFKILL is asserted */
3704 1.29.2.2 skrll if (!pkt) {
3705 1.29.2.2 skrll error = 0;
3706 1.29.2.2 skrll goto out_free_resp;
3707 1.29.2.2 skrll }
3708 1.29.2.2 skrll
3709 1.29.2.2 skrll if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
3710 1.29.2.2 skrll error = EIO;
3711 1.29.2.2 skrll goto out_free_resp;
3712 1.29.2.2 skrll }
3713 1.29.2.2 skrll
3714 1.29.2.2 skrll resp_len = iwm_rx_packet_payload_len(pkt);
3715 1.29.2.2 skrll if (resp_len != sizeof(*resp)) {
3716 1.29.2.2 skrll error = EIO;
3717 1.29.2.2 skrll goto out_free_resp;
3718 1.29.2.2 skrll }
3719 1.29.2.2 skrll
3720 1.29.2.2 skrll resp = (void *)pkt->data;
3721 1.29.2.2 skrll *status = le32toh(resp->status);
3722 1.29.2.2 skrll out_free_resp:
3723 1.29.2.2 skrll iwm_free_resp(sc, cmd);
3724 1.29.2.2 skrll return error;
3725 1.29.2.2 skrll }
3726 1.29.2.2 skrll
3727 1.29.2.2 skrll /* iwlwifi/mvm/utils.c */
3728 1.29.2.2 skrll static int
3729 1.29.2.2 skrll iwm_mvm_send_cmd_pdu_status(struct iwm_softc *sc, uint8_t id,
3730 1.29.2.2 skrll uint16_t len, const void *data, uint32_t *status)
3731 1.29.2.2 skrll {
3732 1.29.2.2 skrll struct iwm_host_cmd cmd = {
3733 1.29.2.2 skrll .id = id,
3734 1.29.2.2 skrll .len = { len, },
3735 1.29.2.2 skrll .data = { data, },
3736 1.29.2.2 skrll };
3737 1.29.2.2 skrll
3738 1.29.2.2 skrll return iwm_mvm_send_cmd_status(sc, &cmd, status);
3739 1.29.2.2 skrll }
3740 1.29.2.2 skrll
3741 1.29.2.2 skrll static void
3742 1.29.2.2 skrll iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
3743 1.29.2.2 skrll {
3744 1.29.2.2 skrll KASSERT(sc->sc_wantresp != -1);
3745 1.29.2.2 skrll KASSERT((hcmd->flags & (IWM_CMD_WANT_SKB|IWM_CMD_SYNC))
3746 1.29.2.2 skrll == (IWM_CMD_WANT_SKB|IWM_CMD_SYNC));
3747 1.29.2.2 skrll sc->sc_wantresp = -1;
3748 1.29.2.2 skrll wakeup(&sc->sc_wantresp);
3749 1.29.2.2 skrll }
3750 1.29.2.2 skrll
3751 1.29.2.2 skrll /*
3752 1.29.2.2 skrll * Process a "command done" firmware notification. This is where we wakeup
3753 1.29.2.2 skrll * processes waiting for a synchronous command completion.
3754 1.29.2.2 skrll * from if_iwn
3755 1.29.2.2 skrll */
3756 1.29.2.2 skrll static void
3757 1.29.2.2 skrll iwm_cmd_done(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
3758 1.29.2.2 skrll {
3759 1.29.2.2 skrll struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
3760 1.29.2.2 skrll struct iwm_tx_data *data;
3761 1.29.2.2 skrll
3762 1.29.2.2 skrll if (pkt->hdr.qid != IWM_MVM_CMD_QUEUE) {
3763 1.29.2.2 skrll return; /* Not a command ack. */
3764 1.29.2.2 skrll }
3765 1.29.2.2 skrll
3766 1.29.2.2 skrll data = &ring->data[pkt->hdr.idx];
3767 1.29.2.2 skrll
3768 1.29.2.2 skrll /* If the command was mapped in an mbuf, free it. */
3769 1.29.2.2 skrll if (data->m != NULL) {
3770 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
3771 1.29.2.2 skrll data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
3772 1.29.2.2 skrll bus_dmamap_unload(sc->sc_dmat, data->map);
3773 1.29.2.2 skrll m_freem(data->m);
3774 1.29.2.2 skrll data->m = NULL;
3775 1.29.2.2 skrll }
3776 1.29.2.2 skrll wakeup(&ring->desc[pkt->hdr.idx]);
3777 1.29.2.2 skrll }
3778 1.29.2.2 skrll
3779 1.29.2.2 skrll #if 0
3780 1.29.2.2 skrll /*
3781 1.29.2.2 skrll * necessary only for block ack mode
3782 1.29.2.2 skrll */
3783 1.29.2.2 skrll void
3784 1.29.2.2 skrll iwm_update_sched(struct iwm_softc *sc, int qid, int idx, uint8_t sta_id,
3785 1.29.2.2 skrll uint16_t len)
3786 1.29.2.2 skrll {
3787 1.29.2.2 skrll struct iwm_agn_scd_bc_tbl *scd_bc_tbl;
3788 1.29.2.2 skrll uint16_t w_val;
3789 1.29.2.2 skrll
3790 1.29.2.2 skrll scd_bc_tbl = sc->sched_dma.vaddr;
3791 1.29.2.2 skrll
3792 1.29.2.2 skrll len += 8; /* magic numbers came naturally from paris */
3793 1.29.2.2 skrll if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DW_BC_TABLE)
3794 1.29.2.2 skrll len = roundup(len, 4) / 4;
3795 1.29.2.2 skrll
3796 1.29.2.2 skrll w_val = htole16(sta_id << 12 | len);
3797 1.29.2.2 skrll
3798 1.29.2.2 skrll /* Update TX scheduler. */
3799 1.29.2.2 skrll scd_bc_tbl[qid].tfd_offset[idx] = w_val;
3800 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
3801 1.29.2.2 skrll (char *)(void *)w - (char *)(void *)sc->sched_dma.vaddr,
3802 1.29.2.2 skrll sizeof(uint16_t), BUS_DMASYNC_PREWRITE);
3803 1.29.2.2 skrll
3804 1.29.2.2 skrll /* I really wonder what this is ?!? */
3805 1.29.2.2 skrll if (idx < IWM_TFD_QUEUE_SIZE_BC_DUP) {
3806 1.29.2.2 skrll scd_bc_tbl[qid].tfd_offset[IWM_TFD_QUEUE_SIZE_MAX + idx] = w_val;
3807 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
3808 1.29.2.2 skrll (char *)(void *)(w + IWM_TFD_QUEUE_SIZE_MAX) -
3809 1.29.2.2 skrll (char *)(void *)sc->sched_dma.vaddr,
3810 1.29.2.2 skrll sizeof (uint16_t), BUS_DMASYNC_PREWRITE);
3811 1.29.2.2 skrll }
3812 1.29.2.2 skrll }
3813 1.29.2.2 skrll #endif
3814 1.29.2.2 skrll
3815 1.29.2.2 skrll /*
3816 1.29.2.2 skrll * Fill in various bit for management frames, and leave them
3817 1.29.2.2 skrll * unfilled for data frames (firmware takes care of that).
3818 1.29.2.2 skrll * Return the selected TX rate.
3819 1.29.2.2 skrll */
3820 1.29.2.2 skrll static const struct iwm_rate *
3821 1.29.2.2 skrll iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
3822 1.29.2.2 skrll struct ieee80211_frame *wh, struct iwm_tx_cmd *tx)
3823 1.29.2.2 skrll {
3824 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3825 1.29.2.2 skrll struct ieee80211_node *ni = &in->in_ni;
3826 1.29.2.2 skrll const struct iwm_rate *rinfo;
3827 1.29.2.2 skrll int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3828 1.29.2.2 skrll int ridx, rate_flags;
3829 1.29.2.2 skrll int nrates = ni->ni_rates.rs_nrates;
3830 1.29.2.2 skrll
3831 1.29.2.2 skrll tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT;
3832 1.29.2.2 skrll tx->data_retry_limit = IWM_DEFAULT_TX_RETRY;
3833 1.29.2.2 skrll
3834 1.29.2.2 skrll if (type != IEEE80211_FC0_TYPE_DATA) {
3835 1.29.2.2 skrll /* for non-data, use the lowest supported rate */
3836 1.29.2.2 skrll ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
3837 1.29.2.2 skrll IWM_RIDX_OFDM : IWM_RIDX_CCK;
3838 1.29.2.2 skrll } else if (ic->ic_fixed_rate != -1) {
3839 1.29.2.2 skrll ridx = sc->sc_fixed_ridx;
3840 1.29.2.2 skrll } else {
3841 1.29.2.2 skrll /* for data frames, use RS table */
3842 1.29.2.2 skrll tx->initial_rate_index = (nrates - 1) - ni->ni_txrate;
3843 1.29.2.2 skrll tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
3844 1.29.2.2 skrll DPRINTFN(12, ("start with txrate %d\n", tx->initial_rate_index));
3845 1.29.2.2 skrll ridx = in->in_ridx[ni->ni_txrate];
3846 1.29.2.2 skrll return &iwm_rates[ridx];
3847 1.29.2.2 skrll }
3848 1.29.2.2 skrll
3849 1.29.2.2 skrll rinfo = &iwm_rates[ridx];
3850 1.29.2.2 skrll rate_flags = 1 << IWM_RATE_MCS_ANT_POS;
3851 1.29.2.2 skrll if (IWM_RIDX_IS_CCK(ridx))
3852 1.29.2.2 skrll rate_flags |= IWM_RATE_MCS_CCK_MSK;
3853 1.29.2.2 skrll tx->rate_n_flags = htole32(rate_flags | rinfo->plcp);
3854 1.29.2.2 skrll
3855 1.29.2.2 skrll return rinfo;
3856 1.29.2.2 skrll }
3857 1.29.2.2 skrll
3858 1.29.2.2 skrll #define TB0_SIZE 16
3859 1.29.2.2 skrll static int
3860 1.29.2.2 skrll iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
3861 1.29.2.2 skrll {
3862 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
3863 1.29.2.2 skrll struct iwm_node *in = (void *)ni;
3864 1.29.2.2 skrll struct iwm_tx_ring *ring;
3865 1.29.2.2 skrll struct iwm_tx_data *data;
3866 1.29.2.2 skrll struct iwm_tfd *desc;
3867 1.29.2.2 skrll struct iwm_device_cmd *cmd;
3868 1.29.2.2 skrll struct iwm_tx_cmd *tx;
3869 1.29.2.2 skrll struct ieee80211_frame *wh;
3870 1.29.2.2 skrll struct ieee80211_key *k = NULL;
3871 1.29.2.2 skrll struct mbuf *m1;
3872 1.29.2.2 skrll const struct iwm_rate *rinfo;
3873 1.29.2.2 skrll uint32_t flags;
3874 1.29.2.2 skrll u_int hdrlen;
3875 1.29.2.2 skrll bus_dma_segment_t *seg;
3876 1.29.2.2 skrll uint8_t tid, type;
3877 1.29.2.2 skrll int i, totlen, error, pad;
3878 1.29.2.2 skrll int hdrlen2;
3879 1.29.2.2 skrll
3880 1.29.2.2 skrll wh = mtod(m, struct ieee80211_frame *);
3881 1.29.2.2 skrll hdrlen = ieee80211_anyhdrsize(wh);
3882 1.29.2.2 skrll type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
3883 1.29.2.2 skrll
3884 1.29.2.2 skrll hdrlen2 = (ieee80211_has_qos(wh)) ?
3885 1.29.2.2 skrll sizeof (struct ieee80211_qosframe) :
3886 1.29.2.2 skrll sizeof (struct ieee80211_frame);
3887 1.29.2.2 skrll
3888 1.29.2.2 skrll if (hdrlen != hdrlen2)
3889 1.29.2.2 skrll DPRINTF(("%s: hdrlen error (%d != %d)\n",
3890 1.29.2.2 skrll DEVNAME(sc), hdrlen, hdrlen2));
3891 1.29.2.2 skrll
3892 1.29.2.2 skrll tid = 0;
3893 1.29.2.2 skrll
3894 1.29.2.2 skrll ring = &sc->txq[ac];
3895 1.29.2.2 skrll desc = &ring->desc[ring->cur];
3896 1.29.2.2 skrll memset(desc, 0, sizeof(*desc));
3897 1.29.2.2 skrll data = &ring->data[ring->cur];
3898 1.29.2.2 skrll
3899 1.29.2.2 skrll /* Fill out iwm_tx_cmd to send to the firmware */
3900 1.29.2.2 skrll cmd = &ring->cmd[ring->cur];
3901 1.29.2.2 skrll cmd->hdr.code = IWM_TX_CMD;
3902 1.29.2.2 skrll cmd->hdr.flags = 0;
3903 1.29.2.2 skrll cmd->hdr.qid = ring->qid;
3904 1.29.2.2 skrll cmd->hdr.idx = ring->cur;
3905 1.29.2.2 skrll
3906 1.29.2.2 skrll tx = (void *)cmd->data;
3907 1.29.2.2 skrll memset(tx, 0, sizeof(*tx));
3908 1.29.2.2 skrll
3909 1.29.2.2 skrll rinfo = iwm_tx_fill_cmd(sc, in, wh, tx);
3910 1.29.2.2 skrll
3911 1.29.2.2 skrll if (sc->sc_drvbpf != NULL) {
3912 1.29.2.2 skrll struct iwm_tx_radiotap_header *tap = &sc->sc_txtap;
3913 1.29.2.2 skrll
3914 1.29.2.2 skrll tap->wt_flags = 0;
3915 1.29.2.2 skrll tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
3916 1.29.2.2 skrll tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags);
3917 1.29.2.2 skrll tap->wt_rate = rinfo->rate;
3918 1.29.2.2 skrll tap->wt_hwqueue = ac;
3919 1.29.2.2 skrll if (wh->i_fc[1] & IEEE80211_FC1_WEP)
3920 1.29.2.2 skrll tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
3921 1.29.2.2 skrll
3922 1.29.2.2 skrll bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m);
3923 1.29.2.2 skrll }
3924 1.29.2.2 skrll
3925 1.29.2.2 skrll /* Encrypt the frame if need be. */
3926 1.29.2.2 skrll if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3927 1.29.2.2 skrll k = ieee80211_crypto_encap(ic, ni, m);
3928 1.29.2.2 skrll if (k == NULL) {
3929 1.29.2.2 skrll m_freem(m);
3930 1.29.2.2 skrll return ENOBUFS;
3931 1.29.2.2 skrll }
3932 1.29.2.2 skrll /* Packet header may have moved, reset our local pointer. */
3933 1.29.2.2 skrll wh = mtod(m, struct ieee80211_frame *);
3934 1.29.2.2 skrll }
3935 1.29.2.2 skrll totlen = m->m_pkthdr.len;
3936 1.29.2.2 skrll
3937 1.29.2.2 skrll flags = 0;
3938 1.29.2.2 skrll if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3939 1.29.2.2 skrll flags |= IWM_TX_CMD_FLG_ACK;
3940 1.29.2.2 skrll }
3941 1.29.2.2 skrll
3942 1.29.2.2 skrll if (type != IEEE80211_FC0_TYPE_DATA
3943 1.29.2.2 skrll && (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold)
3944 1.29.2.2 skrll && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
3945 1.29.2.2 skrll flags |= IWM_TX_CMD_FLG_PROT_REQUIRE;
3946 1.29.2.2 skrll }
3947 1.29.2.2 skrll
3948 1.29.2.2 skrll if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
3949 1.29.2.2 skrll type != IEEE80211_FC0_TYPE_DATA)
3950 1.29.2.2 skrll tx->sta_id = sc->sc_aux_sta.sta_id;
3951 1.29.2.2 skrll else
3952 1.29.2.2 skrll tx->sta_id = IWM_STATION_ID;
3953 1.29.2.2 skrll
3954 1.29.2.2 skrll if (type == IEEE80211_FC0_TYPE_MGT) {
3955 1.29.2.2 skrll uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
3956 1.29.2.2 skrll
3957 1.29.2.2 skrll if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
3958 1.29.2.2 skrll subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
3959 1.29.2.2 skrll tx->pm_frame_timeout = htole16(3);
3960 1.29.2.2 skrll else
3961 1.29.2.2 skrll tx->pm_frame_timeout = htole16(2);
3962 1.29.2.2 skrll } else {
3963 1.29.2.2 skrll tx->pm_frame_timeout = htole16(0);
3964 1.29.2.2 skrll }
3965 1.29.2.2 skrll
3966 1.29.2.2 skrll if (hdrlen & 3) {
3967 1.29.2.2 skrll /* First segment length must be a multiple of 4. */
3968 1.29.2.2 skrll flags |= IWM_TX_CMD_FLG_MH_PAD;
3969 1.29.2.2 skrll pad = 4 - (hdrlen & 3);
3970 1.29.2.2 skrll } else
3971 1.29.2.2 skrll pad = 0;
3972 1.29.2.2 skrll
3973 1.29.2.2 skrll tx->driver_txop = 0;
3974 1.29.2.2 skrll tx->next_frame_len = 0;
3975 1.29.2.2 skrll
3976 1.29.2.2 skrll tx->len = htole16(totlen);
3977 1.29.2.2 skrll tx->tid_tspec = tid;
3978 1.29.2.2 skrll tx->life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
3979 1.29.2.2 skrll
3980 1.29.2.2 skrll /* Set physical address of "scratch area". */
3981 1.29.2.2 skrll tx->dram_lsb_ptr = htole32(data->scratch_paddr);
3982 1.29.2.2 skrll tx->dram_msb_ptr = iwm_get_dma_hi_addr(data->scratch_paddr);
3983 1.29.2.2 skrll
3984 1.29.2.2 skrll /* Copy 802.11 header in TX command. */
3985 1.29.2.2 skrll memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen);
3986 1.29.2.2 skrll
3987 1.29.2.2 skrll flags |= IWM_TX_CMD_FLG_BT_DIS | IWM_TX_CMD_FLG_SEQ_CTL;
3988 1.29.2.2 skrll
3989 1.29.2.2 skrll tx->sec_ctl = 0;
3990 1.29.2.2 skrll tx->tx_flags |= htole32(flags);
3991 1.29.2.2 skrll
3992 1.29.2.2 skrll /* Trim 802.11 header. */
3993 1.29.2.2 skrll m_adj(m, hdrlen);
3994 1.29.2.2 skrll
3995 1.29.2.2 skrll error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
3996 1.29.2.2 skrll BUS_DMA_NOWAIT | BUS_DMA_WRITE);
3997 1.29.2.2 skrll if (error != 0) {
3998 1.29.2.2 skrll if (error != EFBIG) {
3999 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
4000 1.29.2.2 skrll "can't map mbuf (error %d)\n", error);
4001 1.29.2.2 skrll m_freem(m);
4002 1.29.2.2 skrll return error;
4003 1.29.2.2 skrll }
4004 1.29.2.2 skrll /* Too many DMA segments, linearize mbuf. */
4005 1.29.2.2 skrll MGETHDR(m1, M_DONTWAIT, MT_DATA);
4006 1.29.2.2 skrll if (m1 == NULL) {
4007 1.29.2.2 skrll m_freem(m);
4008 1.29.2.2 skrll return ENOBUFS;
4009 1.29.2.2 skrll }
4010 1.29.2.2 skrll if (m->m_pkthdr.len > MHLEN) {
4011 1.29.2.2 skrll MCLGET(m1, M_DONTWAIT);
4012 1.29.2.2 skrll if (!(m1->m_flags & M_EXT)) {
4013 1.29.2.2 skrll m_freem(m);
4014 1.29.2.2 skrll m_freem(m1);
4015 1.29.2.2 skrll return ENOBUFS;
4016 1.29.2.2 skrll }
4017 1.29.2.2 skrll }
4018 1.29.2.2 skrll m_copydata(m, 0, m->m_pkthdr.len, mtod(m1, void *));
4019 1.29.2.2 skrll m1->m_pkthdr.len = m1->m_len = m->m_pkthdr.len;
4020 1.29.2.2 skrll m_freem(m);
4021 1.29.2.2 skrll m = m1;
4022 1.29.2.2 skrll
4023 1.29.2.2 skrll error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
4024 1.29.2.2 skrll BUS_DMA_NOWAIT | BUS_DMA_WRITE);
4025 1.29.2.2 skrll if (error != 0) {
4026 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
4027 1.29.2.2 skrll "can't map mbuf (error %d)\n", error);
4028 1.29.2.2 skrll m_freem(m);
4029 1.29.2.2 skrll return error;
4030 1.29.2.2 skrll }
4031 1.29.2.2 skrll }
4032 1.29.2.2 skrll data->m = m;
4033 1.29.2.2 skrll data->in = in;
4034 1.29.2.2 skrll data->done = 0;
4035 1.29.2.2 skrll
4036 1.29.2.2 skrll DPRINTFN(8, ("sending txd %p, in %p\n", data, data->in));
4037 1.29.2.2 skrll KASSERT(data->in != NULL);
4038 1.29.2.2 skrll
4039 1.29.2.2 skrll DPRINTFN(8, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n",
4040 1.29.2.2 skrll ring->qid, ring->cur, totlen, data->map->dm_nsegs));
4041 1.29.2.2 skrll
4042 1.29.2.2 skrll /* Fill TX descriptor. */
4043 1.29.2.2 skrll desc->num_tbs = 2 + data->map->dm_nsegs;
4044 1.29.2.2 skrll
4045 1.29.2.2 skrll desc->tbs[0].lo = htole32(data->cmd_paddr);
4046 1.29.2.2 skrll desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) |
4047 1.29.2.2 skrll (TB0_SIZE << 4);
4048 1.29.2.2 skrll desc->tbs[1].lo = htole32(data->cmd_paddr + TB0_SIZE);
4049 1.29.2.2 skrll desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) |
4050 1.29.2.2 skrll ((sizeof(struct iwm_cmd_header) + sizeof(*tx)
4051 1.29.2.2 skrll + hdrlen + pad - TB0_SIZE) << 4);
4052 1.29.2.2 skrll
4053 1.29.2.2 skrll /* Other DMA segments are for data payload. */
4054 1.29.2.2 skrll seg = data->map->dm_segs;
4055 1.29.2.2 skrll for (i = 0; i < data->map->dm_nsegs; i++, seg++) {
4056 1.29.2.2 skrll desc->tbs[i+2].lo = htole32(seg->ds_addr);
4057 1.29.2.2 skrll desc->tbs[i+2].hi_n_len = \
4058 1.29.2.2 skrll htole16(iwm_get_dma_hi_addr(seg->ds_addr))
4059 1.29.2.2 skrll | ((seg->ds_len) << 4);
4060 1.29.2.2 skrll }
4061 1.29.2.2 skrll
4062 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
4063 1.29.2.2 skrll BUS_DMASYNC_PREWRITE);
4064 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
4065 1.29.2.2 skrll (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr,
4066 1.29.2.2 skrll sizeof (*cmd), BUS_DMASYNC_PREWRITE);
4067 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
4068 1.29.2.2 skrll (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
4069 1.29.2.2 skrll sizeof (*desc), BUS_DMASYNC_PREWRITE);
4070 1.29.2.2 skrll
4071 1.29.2.2 skrll #if 0
4072 1.29.2.2 skrll iwm_update_sched(sc, ring->qid, ring->cur, tx->sta_id, le16toh(tx->len));
4073 1.29.2.2 skrll #endif
4074 1.29.2.2 skrll
4075 1.29.2.2 skrll /* Kick TX ring. */
4076 1.29.2.2 skrll ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT;
4077 1.29.2.2 skrll IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
4078 1.29.2.2 skrll
4079 1.29.2.2 skrll /* Mark TX ring as full if we reach a certain threshold. */
4080 1.29.2.2 skrll if (++ring->queued > IWM_TX_RING_HIMARK) {
4081 1.29.2.2 skrll sc->qfullmsk |= 1 << ring->qid;
4082 1.29.2.2 skrll }
4083 1.29.2.2 skrll
4084 1.29.2.2 skrll return 0;
4085 1.29.2.2 skrll }
4086 1.29.2.2 skrll
4087 1.29.2.2 skrll #if 0
4088 1.29.2.2 skrll /* not necessary? */
4089 1.29.2.2 skrll static int
4090 1.29.2.2 skrll iwm_mvm_flush_tx_path(struct iwm_softc *sc, int tfd_msk, int sync)
4091 1.29.2.2 skrll {
4092 1.29.2.2 skrll struct iwm_tx_path_flush_cmd flush_cmd = {
4093 1.29.2.2 skrll .queues_ctl = htole32(tfd_msk),
4094 1.29.2.2 skrll .flush_ctl = htole16(IWM_DUMP_TX_FIFO_FLUSH),
4095 1.29.2.2 skrll };
4096 1.29.2.2 skrll int ret;
4097 1.29.2.2 skrll
4098 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu(sc, IWM_TXPATH_FLUSH,
4099 1.29.2.2 skrll sync ? IWM_CMD_SYNC : IWM_CMD_ASYNC,
4100 1.29.2.2 skrll sizeof(flush_cmd), &flush_cmd);
4101 1.29.2.2 skrll if (ret)
4102 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "Flushing tx queue failed: %d\n",
4103 1.29.2.2 skrll ret);
4104 1.29.2.2 skrll return ret;
4105 1.29.2.2 skrll }
4106 1.29.2.2 skrll #endif
4107 1.29.2.2 skrll
4108 1.29.2.2 skrll
4109 1.29.2.2 skrll /*
4110 1.29.2.2 skrll * BEGIN mvm/power.c
4111 1.29.2.2 skrll */
4112 1.29.2.2 skrll
4113 1.29.2.2 skrll #define IWM_POWER_KEEP_ALIVE_PERIOD_SEC 25
4114 1.29.2.2 skrll
4115 1.29.2.2 skrll static int
4116 1.29.2.2 skrll iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *sc,
4117 1.29.2.2 skrll struct iwm_beacon_filter_cmd *cmd)
4118 1.29.2.2 skrll {
4119 1.29.2.2 skrll int ret;
4120 1.29.2.2 skrll
4121 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD,
4122 1.29.2.2 skrll IWM_CMD_SYNC, sizeof(struct iwm_beacon_filter_cmd), cmd);
4123 1.29.2.2 skrll
4124 1.29.2.2 skrll if (!ret) {
4125 1.29.2.2 skrll DPRINTF(("ba_enable_beacon_abort is: %d\n",
4126 1.29.2.2 skrll le32toh(cmd->ba_enable_beacon_abort)));
4127 1.29.2.2 skrll DPRINTF(("ba_escape_timer is: %d\n",
4128 1.29.2.2 skrll le32toh(cmd->ba_escape_timer)));
4129 1.29.2.2 skrll DPRINTF(("bf_debug_flag is: %d\n",
4130 1.29.2.2 skrll le32toh(cmd->bf_debug_flag)));
4131 1.29.2.2 skrll DPRINTF(("bf_enable_beacon_filter is: %d\n",
4132 1.29.2.2 skrll le32toh(cmd->bf_enable_beacon_filter)));
4133 1.29.2.2 skrll DPRINTF(("bf_energy_delta is: %d\n",
4134 1.29.2.2 skrll le32toh(cmd->bf_energy_delta)));
4135 1.29.2.2 skrll DPRINTF(("bf_escape_timer is: %d\n",
4136 1.29.2.2 skrll le32toh(cmd->bf_escape_timer)));
4137 1.29.2.2 skrll DPRINTF(("bf_roaming_energy_delta is: %d\n",
4138 1.29.2.2 skrll le32toh(cmd->bf_roaming_energy_delta)));
4139 1.29.2.2 skrll DPRINTF(("bf_roaming_state is: %d\n",
4140 1.29.2.2 skrll le32toh(cmd->bf_roaming_state)));
4141 1.29.2.2 skrll DPRINTF(("bf_temp_threshold is: %d\n",
4142 1.29.2.2 skrll le32toh(cmd->bf_temp_threshold)));
4143 1.29.2.2 skrll DPRINTF(("bf_temp_fast_filter is: %d\n",
4144 1.29.2.2 skrll le32toh(cmd->bf_temp_fast_filter)));
4145 1.29.2.2 skrll DPRINTF(("bf_temp_slow_filter is: %d\n",
4146 1.29.2.2 skrll le32toh(cmd->bf_temp_slow_filter)));
4147 1.29.2.2 skrll }
4148 1.29.2.2 skrll return ret;
4149 1.29.2.2 skrll }
4150 1.29.2.2 skrll
4151 1.29.2.2 skrll static void
4152 1.29.2.2 skrll iwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *sc,
4153 1.29.2.2 skrll struct iwm_node *in, struct iwm_beacon_filter_cmd *cmd)
4154 1.29.2.2 skrll {
4155 1.29.2.2 skrll cmd->ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled);
4156 1.29.2.2 skrll }
4157 1.29.2.2 skrll
4158 1.29.2.2 skrll static int
4159 1.29.2.2 skrll iwm_mvm_update_beacon_abort(struct iwm_softc *sc, struct iwm_node *in,
4160 1.29.2.2 skrll int enable)
4161 1.29.2.2 skrll {
4162 1.29.2.2 skrll struct iwm_beacon_filter_cmd cmd = {
4163 1.29.2.2 skrll IWM_BF_CMD_CONFIG_DEFAULTS,
4164 1.29.2.2 skrll .bf_enable_beacon_filter = htole32(1),
4165 1.29.2.2 skrll .ba_enable_beacon_abort = htole32(enable),
4166 1.29.2.2 skrll };
4167 1.29.2.2 skrll
4168 1.29.2.2 skrll if (!sc->sc_bf.bf_enabled)
4169 1.29.2.2 skrll return 0;
4170 1.29.2.2 skrll
4171 1.29.2.2 skrll sc->sc_bf.ba_enabled = enable;
4172 1.29.2.2 skrll iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd);
4173 1.29.2.2 skrll return iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
4174 1.29.2.2 skrll }
4175 1.29.2.2 skrll
4176 1.29.2.2 skrll static void
4177 1.29.2.2 skrll iwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd)
4178 1.29.2.2 skrll {
4179 1.29.2.2 skrll DPRINTF(("Sending power table command on mac id 0x%X for "
4180 1.29.2.2 skrll "power level %d, flags = 0x%X\n",
4181 1.29.2.2 skrll cmd->id_and_color, IWM_POWER_SCHEME_CAM, le16toh(cmd->flags)));
4182 1.29.2.2 skrll DPRINTF(("Keep alive = %u sec\n", le16toh(cmd->keep_alive_seconds)));
4183 1.29.2.2 skrll
4184 1.29.2.2 skrll if (!(cmd->flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) {
4185 1.29.2.2 skrll DPRINTF(("Disable power management\n"));
4186 1.29.2.2 skrll return;
4187 1.29.2.2 skrll }
4188 1.29.2.2 skrll KASSERT(0);
4189 1.29.2.2 skrll
4190 1.29.2.2 skrll #if 0
4191 1.29.2.2 skrll DPRINTF(mvm, "Rx timeout = %u usec\n",
4192 1.29.2.2 skrll le32_to_cpu(cmd->rx_data_timeout));
4193 1.29.2.2 skrll DPRINTF(mvm, "Tx timeout = %u usec\n",
4194 1.29.2.2 skrll le32_to_cpu(cmd->tx_data_timeout));
4195 1.29.2.2 skrll if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK))
4196 1.29.2.2 skrll DPRINTF(mvm, "DTIM periods to skip = %u\n",
4197 1.29.2.2 skrll cmd->skip_dtim_periods);
4198 1.29.2.2 skrll if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_LPRX_ENA_MSK))
4199 1.29.2.2 skrll DPRINTF(mvm, "LP RX RSSI threshold = %u\n",
4200 1.29.2.2 skrll cmd->lprx_rssi_threshold);
4201 1.29.2.2 skrll if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
4202 1.29.2.2 skrll DPRINTF(mvm, "uAPSD enabled\n");
4203 1.29.2.2 skrll DPRINTF(mvm, "Rx timeout (uAPSD) = %u usec\n",
4204 1.29.2.2 skrll le32_to_cpu(cmd->rx_data_timeout_uapsd));
4205 1.29.2.2 skrll DPRINTF(mvm, "Tx timeout (uAPSD) = %u usec\n",
4206 1.29.2.2 skrll le32_to_cpu(cmd->tx_data_timeout_uapsd));
4207 1.29.2.2 skrll DPRINTF(mvm, "QNDP TID = %d\n", cmd->qndp_tid);
4208 1.29.2.2 skrll DPRINTF(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags);
4209 1.29.2.2 skrll DPRINTF(mvm, "Max SP = %d\n", cmd->uapsd_max_sp);
4210 1.29.2.2 skrll }
4211 1.29.2.2 skrll #endif
4212 1.29.2.2 skrll }
4213 1.29.2.2 skrll
4214 1.29.2.2 skrll static void
4215 1.29.2.2 skrll iwm_mvm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in,
4216 1.29.2.2 skrll struct iwm_mac_power_cmd *cmd)
4217 1.29.2.2 skrll {
4218 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
4219 1.29.2.2 skrll struct ieee80211_node *ni = &in->in_ni;
4220 1.29.2.2 skrll int dtimper, dtimper_msec;
4221 1.29.2.2 skrll int keep_alive;
4222 1.29.2.2 skrll
4223 1.29.2.2 skrll cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
4224 1.29.2.2 skrll in->in_color));
4225 1.29.2.2 skrll dtimper = ic->ic_dtim_period ?: 1;
4226 1.29.2.2 skrll
4227 1.29.2.2 skrll /*
4228 1.29.2.2 skrll * Regardless of power management state the driver must set
4229 1.29.2.2 skrll * keep alive period. FW will use it for sending keep alive NDPs
4230 1.29.2.2 skrll * immediately after association. Check that keep alive period
4231 1.29.2.2 skrll * is at least 3 * DTIM
4232 1.29.2.2 skrll */
4233 1.29.2.2 skrll dtimper_msec = dtimper * ni->ni_intval;
4234 1.29.2.2 skrll keep_alive
4235 1.29.2.2 skrll = MAX(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC);
4236 1.29.2.2 skrll keep_alive = roundup(keep_alive, 1000) / 1000;
4237 1.29.2.2 skrll cmd->keep_alive_seconds = htole16(keep_alive);
4238 1.29.2.2 skrll }
4239 1.29.2.2 skrll
4240 1.29.2.2 skrll static int
4241 1.29.2.2 skrll iwm_mvm_power_mac_update_mode(struct iwm_softc *sc, struct iwm_node *in)
4242 1.29.2.2 skrll {
4243 1.29.2.2 skrll int ret;
4244 1.29.2.2 skrll int ba_enable;
4245 1.29.2.2 skrll struct iwm_mac_power_cmd cmd;
4246 1.29.2.2 skrll
4247 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
4248 1.29.2.2 skrll
4249 1.29.2.2 skrll iwm_mvm_power_build_cmd(sc, in, &cmd);
4250 1.29.2.2 skrll iwm_mvm_power_log(sc, &cmd);
4251 1.29.2.2 skrll
4252 1.29.2.2 skrll if ((ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE,
4253 1.29.2.2 skrll IWM_CMD_SYNC, sizeof(cmd), &cmd)) != 0)
4254 1.29.2.2 skrll return ret;
4255 1.29.2.2 skrll
4256 1.29.2.2 skrll ba_enable = !!(cmd.flags &
4257 1.29.2.2 skrll htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
4258 1.29.2.2 skrll return iwm_mvm_update_beacon_abort(sc, in, ba_enable);
4259 1.29.2.2 skrll }
4260 1.29.2.2 skrll
4261 1.29.2.2 skrll static int
4262 1.29.2.2 skrll iwm_mvm_power_update_device(struct iwm_softc *sc)
4263 1.29.2.2 skrll {
4264 1.29.2.2 skrll struct iwm_device_power_cmd cmd = {
4265 1.29.2.2 skrll .flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
4266 1.29.2.2 skrll };
4267 1.29.2.2 skrll
4268 1.29.2.2 skrll if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
4269 1.29.2.2 skrll return 0;
4270 1.29.2.2 skrll
4271 1.29.2.2 skrll cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK);
4272 1.29.2.2 skrll DPRINTF(("Sending device power command with flags = 0x%X\n", cmd.flags));
4273 1.29.2.2 skrll
4274 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu(sc,
4275 1.29.2.2 skrll IWM_POWER_TABLE_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd);
4276 1.29.2.2 skrll }
4277 1.29.2.2 skrll
4278 1.29.2.2 skrll static int
4279 1.29.2.2 skrll iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
4280 1.29.2.2 skrll {
4281 1.29.2.2 skrll struct iwm_beacon_filter_cmd cmd = {
4282 1.29.2.2 skrll IWM_BF_CMD_CONFIG_DEFAULTS,
4283 1.29.2.2 skrll .bf_enable_beacon_filter = htole32(1),
4284 1.29.2.2 skrll };
4285 1.29.2.2 skrll int ret;
4286 1.29.2.2 skrll
4287 1.29.2.2 skrll iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd);
4288 1.29.2.2 skrll ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
4289 1.29.2.2 skrll
4290 1.29.2.2 skrll if (ret == 0)
4291 1.29.2.2 skrll sc->sc_bf.bf_enabled = 1;
4292 1.29.2.2 skrll
4293 1.29.2.2 skrll return ret;
4294 1.29.2.2 skrll }
4295 1.29.2.2 skrll
4296 1.29.2.2 skrll static int
4297 1.29.2.2 skrll iwm_mvm_disable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
4298 1.29.2.2 skrll {
4299 1.29.2.2 skrll struct iwm_beacon_filter_cmd cmd;
4300 1.29.2.2 skrll int ret;
4301 1.29.2.2 skrll
4302 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
4303 1.29.2.2 skrll if ((sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_BF_UPDATED) == 0)
4304 1.29.2.2 skrll return 0;
4305 1.29.2.2 skrll
4306 1.29.2.2 skrll ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
4307 1.29.2.2 skrll if (ret == 0)
4308 1.29.2.2 skrll sc->sc_bf.bf_enabled = 0;
4309 1.29.2.2 skrll
4310 1.29.2.2 skrll return ret;
4311 1.29.2.2 skrll }
4312 1.29.2.2 skrll
4313 1.29.2.2 skrll #if 0
4314 1.29.2.2 skrll static int
4315 1.29.2.2 skrll iwm_mvm_update_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
4316 1.29.2.2 skrll {
4317 1.29.2.2 skrll if (!sc->sc_bf.bf_enabled)
4318 1.29.2.2 skrll return 0;
4319 1.29.2.2 skrll
4320 1.29.2.2 skrll return iwm_mvm_enable_beacon_filter(sc, in);
4321 1.29.2.2 skrll }
4322 1.29.2.2 skrll #endif
4323 1.29.2.2 skrll
4324 1.29.2.2 skrll /*
4325 1.29.2.2 skrll * END mvm/power.c
4326 1.29.2.2 skrll */
4327 1.29.2.2 skrll
4328 1.29.2.2 skrll /*
4329 1.29.2.2 skrll * BEGIN mvm/sta.c
4330 1.29.2.2 skrll */
4331 1.29.2.2 skrll
4332 1.29.2.2 skrll static void
4333 1.29.2.2 skrll iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *cmd_v6,
4334 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v5 *cmd_v5)
4335 1.29.2.2 skrll {
4336 1.29.2.2 skrll memset(cmd_v5, 0, sizeof(*cmd_v5));
4337 1.29.2.2 skrll
4338 1.29.2.2 skrll cmd_v5->add_modify = cmd_v6->add_modify;
4339 1.29.2.2 skrll cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx;
4340 1.29.2.2 skrll cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color;
4341 1.29.2.2 skrll memcpy(cmd_v5->addr, cmd_v6->addr, ETHER_ADDR_LEN);
4342 1.29.2.2 skrll cmd_v5->sta_id = cmd_v6->sta_id;
4343 1.29.2.2 skrll cmd_v5->modify_mask = cmd_v6->modify_mask;
4344 1.29.2.2 skrll cmd_v5->station_flags = cmd_v6->station_flags;
4345 1.29.2.2 skrll cmd_v5->station_flags_msk = cmd_v6->station_flags_msk;
4346 1.29.2.2 skrll cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid;
4347 1.29.2.2 skrll cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid;
4348 1.29.2.2 skrll cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn;
4349 1.29.2.2 skrll cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count;
4350 1.29.2.2 skrll cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags;
4351 1.29.2.2 skrll cmd_v5->assoc_id = cmd_v6->assoc_id;
4352 1.29.2.2 skrll cmd_v5->beamform_flags = cmd_v6->beamform_flags;
4353 1.29.2.2 skrll cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk;
4354 1.29.2.2 skrll }
4355 1.29.2.2 skrll
4356 1.29.2.2 skrll static int
4357 1.29.2.2 skrll iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *sc,
4358 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v6 *cmd, int *status)
4359 1.29.2.2 skrll {
4360 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v5 cmd_v5;
4361 1.29.2.2 skrll
4362 1.29.2.2 skrll if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_STA_KEY_CMD) {
4363 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA,
4364 1.29.2.2 skrll sizeof(*cmd), cmd, status);
4365 1.29.2.2 skrll }
4366 1.29.2.2 skrll
4367 1.29.2.2 skrll iwm_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
4368 1.29.2.2 skrll
4369 1.29.2.2 skrll return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(cmd_v5),
4370 1.29.2.2 skrll &cmd_v5, status);
4371 1.29.2.2 skrll }
4372 1.29.2.2 skrll
4373 1.29.2.2 skrll /* send station add/update command to firmware */
4374 1.29.2.2 skrll static int
4375 1.29.2.2 skrll iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, int update)
4376 1.29.2.2 skrll {
4377 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v6 add_sta_cmd;
4378 1.29.2.2 skrll int ret;
4379 1.29.2.2 skrll uint32_t status;
4380 1.29.2.2 skrll
4381 1.29.2.2 skrll memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
4382 1.29.2.2 skrll
4383 1.29.2.2 skrll add_sta_cmd.sta_id = IWM_STATION_ID;
4384 1.29.2.2 skrll add_sta_cmd.mac_id_n_color
4385 1.29.2.2 skrll = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
4386 1.29.2.2 skrll if (!update) {
4387 1.29.2.2 skrll add_sta_cmd.tfd_queue_msk = htole32(0xf);
4388 1.29.2.2 skrll IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
4389 1.29.2.2 skrll }
4390 1.29.2.2 skrll add_sta_cmd.add_modify = update ? 1 : 0;
4391 1.29.2.2 skrll add_sta_cmd.station_flags_msk
4392 1.29.2.2 skrll |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK);
4393 1.29.2.2 skrll
4394 1.29.2.2 skrll status = IWM_ADD_STA_SUCCESS;
4395 1.29.2.2 skrll ret = iwm_mvm_send_add_sta_cmd_status(sc, &add_sta_cmd, &status);
4396 1.29.2.2 skrll if (ret)
4397 1.29.2.2 skrll return ret;
4398 1.29.2.2 skrll
4399 1.29.2.2 skrll switch (status) {
4400 1.29.2.2 skrll case IWM_ADD_STA_SUCCESS:
4401 1.29.2.2 skrll break;
4402 1.29.2.2 skrll default:
4403 1.29.2.2 skrll ret = EIO;
4404 1.29.2.2 skrll DPRINTF(("IWM_ADD_STA failed\n"));
4405 1.29.2.2 skrll break;
4406 1.29.2.2 skrll }
4407 1.29.2.2 skrll
4408 1.29.2.2 skrll return ret;
4409 1.29.2.2 skrll }
4410 1.29.2.2 skrll
4411 1.29.2.2 skrll static int
4412 1.29.2.2 skrll iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in)
4413 1.29.2.2 skrll {
4414 1.29.2.2 skrll int ret;
4415 1.29.2.2 skrll
4416 1.29.2.2 skrll ret = iwm_mvm_sta_send_to_fw(sc, in, 0);
4417 1.29.2.2 skrll if (ret)
4418 1.29.2.2 skrll return ret;
4419 1.29.2.2 skrll
4420 1.29.2.2 skrll return 0;
4421 1.29.2.2 skrll }
4422 1.29.2.2 skrll
4423 1.29.2.2 skrll static int
4424 1.29.2.2 skrll iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in)
4425 1.29.2.2 skrll {
4426 1.29.2.2 skrll return iwm_mvm_sta_send_to_fw(sc, in, 1);
4427 1.29.2.2 skrll }
4428 1.29.2.2 skrll
4429 1.29.2.2 skrll static int
4430 1.29.2.2 skrll iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta,
4431 1.29.2.2 skrll const uint8_t *addr, uint16_t mac_id, uint16_t color)
4432 1.29.2.2 skrll {
4433 1.29.2.2 skrll struct iwm_mvm_add_sta_cmd_v6 cmd;
4434 1.29.2.2 skrll int ret;
4435 1.29.2.2 skrll uint32_t status;
4436 1.29.2.2 skrll
4437 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
4438 1.29.2.2 skrll cmd.sta_id = sta->sta_id;
4439 1.29.2.2 skrll cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color));
4440 1.29.2.2 skrll
4441 1.29.2.2 skrll cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk);
4442 1.29.2.2 skrll
4443 1.29.2.2 skrll if (addr)
4444 1.29.2.2 skrll memcpy(cmd.addr, addr, ETHER_ADDR_LEN);
4445 1.29.2.2 skrll
4446 1.29.2.2 skrll ret = iwm_mvm_send_add_sta_cmd_status(sc, &cmd, &status);
4447 1.29.2.2 skrll if (ret)
4448 1.29.2.2 skrll return ret;
4449 1.29.2.2 skrll
4450 1.29.2.2 skrll switch (status) {
4451 1.29.2.2 skrll case IWM_ADD_STA_SUCCESS:
4452 1.29.2.2 skrll DPRINTF(("Internal station added.\n"));
4453 1.29.2.2 skrll return 0;
4454 1.29.2.2 skrll default:
4455 1.29.2.2 skrll DPRINTF(("%s: Add internal station failed, status=0x%x\n",
4456 1.29.2.2 skrll DEVNAME(sc), status));
4457 1.29.2.2 skrll ret = EIO;
4458 1.29.2.2 skrll break;
4459 1.29.2.2 skrll }
4460 1.29.2.2 skrll return ret;
4461 1.29.2.2 skrll }
4462 1.29.2.2 skrll
4463 1.29.2.2 skrll static int
4464 1.29.2.2 skrll iwm_mvm_add_aux_sta(struct iwm_softc *sc)
4465 1.29.2.2 skrll {
4466 1.29.2.2 skrll int ret;
4467 1.29.2.2 skrll
4468 1.29.2.2 skrll sc->sc_aux_sta.sta_id = 3;
4469 1.29.2.2 skrll sc->sc_aux_sta.tfd_queue_msk = 0;
4470 1.29.2.2 skrll
4471 1.29.2.2 skrll ret = iwm_mvm_add_int_sta_common(sc,
4472 1.29.2.2 skrll &sc->sc_aux_sta, NULL, IWM_MAC_INDEX_AUX, 0);
4473 1.29.2.2 skrll
4474 1.29.2.2 skrll if (ret)
4475 1.29.2.2 skrll memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta));
4476 1.29.2.2 skrll return ret;
4477 1.29.2.2 skrll }
4478 1.29.2.2 skrll
4479 1.29.2.2 skrll /*
4480 1.29.2.2 skrll * END mvm/sta.c
4481 1.29.2.2 skrll */
4482 1.29.2.2 skrll
4483 1.29.2.2 skrll /*
4484 1.29.2.2 skrll * BEGIN mvm/scan.c
4485 1.29.2.2 skrll */
4486 1.29.2.2 skrll
4487 1.29.2.2 skrll #define IWM_PLCP_QUIET_THRESH 1
4488 1.29.2.2 skrll #define IWM_ACTIVE_QUIET_TIME 10
4489 1.29.2.2 skrll #define LONG_OUT_TIME_PERIOD 600
4490 1.29.2.2 skrll #define SHORT_OUT_TIME_PERIOD 200
4491 1.29.2.2 skrll #define SUSPEND_TIME_PERIOD 100
4492 1.29.2.2 skrll
4493 1.29.2.2 skrll static uint16_t
4494 1.29.2.2 skrll iwm_mvm_scan_rx_chain(struct iwm_softc *sc)
4495 1.29.2.2 skrll {
4496 1.29.2.2 skrll uint16_t rx_chain;
4497 1.29.2.2 skrll uint8_t rx_ant;
4498 1.29.2.2 skrll
4499 1.29.2.2 skrll rx_ant = IWM_FW_VALID_RX_ANT(sc);
4500 1.29.2.2 skrll rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS;
4501 1.29.2.2 skrll rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
4502 1.29.2.2 skrll rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS;
4503 1.29.2.2 skrll rx_chain |= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS;
4504 1.29.2.2 skrll return htole16(rx_chain);
4505 1.29.2.2 skrll }
4506 1.29.2.2 skrll
4507 1.29.2.2 skrll #define ieee80211_tu_to_usec(a) (1024*(a))
4508 1.29.2.2 skrll
4509 1.29.2.2 skrll static uint32_t
4510 1.29.2.2 skrll iwm_mvm_scan_max_out_time(struct iwm_softc *sc, uint32_t flags, int is_assoc)
4511 1.29.2.2 skrll {
4512 1.29.2.2 skrll if (!is_assoc)
4513 1.29.2.2 skrll return 0;
4514 1.29.2.2 skrll if (flags & 0x1)
4515 1.29.2.2 skrll return htole32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD));
4516 1.29.2.2 skrll return htole32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD));
4517 1.29.2.2 skrll }
4518 1.29.2.2 skrll
4519 1.29.2.2 skrll static uint32_t
4520 1.29.2.2 skrll iwm_mvm_scan_suspend_time(struct iwm_softc *sc, int is_assoc)
4521 1.29.2.2 skrll {
4522 1.29.2.2 skrll if (!is_assoc)
4523 1.29.2.2 skrll return 0;
4524 1.29.2.2 skrll return htole32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD));
4525 1.29.2.2 skrll }
4526 1.29.2.2 skrll
4527 1.29.2.2 skrll static uint32_t
4528 1.29.2.2 skrll iwm_mvm_scan_rxon_flags(struct iwm_softc *sc, int flags)
4529 1.29.2.2 skrll {
4530 1.29.2.2 skrll if (flags & IEEE80211_CHAN_2GHZ)
4531 1.29.2.2 skrll return htole32(IWM_PHY_BAND_24);
4532 1.29.2.2 skrll else
4533 1.29.2.2 skrll return htole32(IWM_PHY_BAND_5);
4534 1.29.2.2 skrll }
4535 1.29.2.2 skrll
4536 1.29.2.2 skrll static uint32_t
4537 1.29.2.2 skrll iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
4538 1.29.2.2 skrll {
4539 1.29.2.2 skrll uint32_t tx_ant;
4540 1.29.2.2 skrll int i, ind;
4541 1.29.2.2 skrll
4542 1.29.2.2 skrll for (i = 0, ind = sc->sc_scan_last_antenna;
4543 1.29.2.2 skrll i < IWM_RATE_MCS_ANT_NUM; i++) {
4544 1.29.2.2 skrll ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM;
4545 1.29.2.2 skrll if (IWM_FW_VALID_TX_ANT(sc) & (1 << ind)) {
4546 1.29.2.2 skrll sc->sc_scan_last_antenna = ind;
4547 1.29.2.2 skrll break;
4548 1.29.2.2 skrll }
4549 1.29.2.2 skrll }
4550 1.29.2.2 skrll tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS;
4551 1.29.2.2 skrll
4552 1.29.2.2 skrll if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck)
4553 1.29.2.2 skrll return htole32(IWM_RATE_1M_PLCP | IWM_RATE_MCS_CCK_MSK |
4554 1.29.2.2 skrll tx_ant);
4555 1.29.2.2 skrll else
4556 1.29.2.2 skrll return htole32(IWM_RATE_6M_PLCP | tx_ant);
4557 1.29.2.2 skrll }
4558 1.29.2.2 skrll
4559 1.29.2.2 skrll /*
4560 1.29.2.2 skrll * If req->n_ssids > 0, it means we should do an active scan.
4561 1.29.2.2 skrll * In case of active scan w/o directed scan, we receive a zero-length SSID
4562 1.29.2.2 skrll * just to notify that this scan is active and not passive.
4563 1.29.2.2 skrll * In order to notify the FW of the number of SSIDs we wish to scan (including
4564 1.29.2.2 skrll * the zero-length one), we need to set the corresponding bits in chan->type,
4565 1.29.2.2 skrll * one for each SSID, and set the active bit (first). If the first SSID is
4566 1.29.2.2 skrll * already included in the probe template, so we need to set only
4567 1.29.2.2 skrll * req->n_ssids - 1 bits in addition to the first bit.
4568 1.29.2.2 skrll */
4569 1.29.2.2 skrll static uint16_t
4570 1.29.2.2 skrll iwm_mvm_get_active_dwell(struct iwm_softc *sc, int flags, int n_ssids)
4571 1.29.2.2 skrll {
4572 1.29.2.2 skrll if (flags & IEEE80211_CHAN_2GHZ)
4573 1.29.2.2 skrll return 30 + 3 * (n_ssids + 1);
4574 1.29.2.2 skrll return 20 + 2 * (n_ssids + 1);
4575 1.29.2.2 skrll }
4576 1.29.2.2 skrll
4577 1.29.2.2 skrll static uint16_t
4578 1.29.2.2 skrll iwm_mvm_get_passive_dwell(struct iwm_softc *sc, int flags)
4579 1.29.2.2 skrll {
4580 1.29.2.2 skrll return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10;
4581 1.29.2.2 skrll }
4582 1.29.2.2 skrll
4583 1.29.2.2 skrll static int
4584 1.29.2.2 skrll iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
4585 1.29.2.2 skrll int flags, int n_ssids, int basic_ssid)
4586 1.29.2.2 skrll {
4587 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
4588 1.29.2.2 skrll uint16_t passive_dwell = iwm_mvm_get_passive_dwell(sc, flags);
4589 1.29.2.2 skrll uint16_t active_dwell = iwm_mvm_get_active_dwell(sc, flags, n_ssids);
4590 1.29.2.2 skrll struct iwm_scan_channel *chan = (struct iwm_scan_channel *)
4591 1.29.2.2 skrll (cmd->data + le16toh(cmd->tx_cmd.len));
4592 1.29.2.2 skrll int type = (1 << n_ssids) - 1;
4593 1.29.2.2 skrll struct ieee80211_channel *c;
4594 1.29.2.2 skrll int nchan;
4595 1.29.2.2 skrll
4596 1.29.2.2 skrll if (!basic_ssid)
4597 1.29.2.2 skrll type |= (1 << n_ssids);
4598 1.29.2.2 skrll
4599 1.29.2.2 skrll for (nchan = 0, c = &ic->ic_channels[1];
4600 1.29.2.2 skrll c <= &ic->ic_channels[IEEE80211_CHAN_MAX];
4601 1.29.2.2 skrll c++) {
4602 1.29.2.2 skrll if ((c->ic_flags & flags) != flags)
4603 1.29.2.2 skrll continue;
4604 1.29.2.2 skrll
4605 1.29.2.2 skrll chan->channel = htole16(ieee80211_mhz2ieee(c->ic_freq, flags));
4606 1.29.2.2 skrll chan->type = htole32(type);
4607 1.29.2.2 skrll if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
4608 1.29.2.2 skrll chan->type &= htole32(~IWM_SCAN_CHANNEL_TYPE_ACTIVE);
4609 1.29.2.2 skrll chan->active_dwell = htole16(active_dwell);
4610 1.29.2.2 skrll chan->passive_dwell = htole16(passive_dwell);
4611 1.29.2.2 skrll chan->iteration_count = htole16(1);
4612 1.29.2.2 skrll chan++;
4613 1.29.2.2 skrll nchan++;
4614 1.29.2.2 skrll }
4615 1.29.2.2 skrll if (nchan == 0)
4616 1.29.2.2 skrll DPRINTF(("%s: NO CHANNEL!\n", DEVNAME(sc)));
4617 1.29.2.2 skrll return nchan;
4618 1.29.2.2 skrll }
4619 1.29.2.2 skrll
4620 1.29.2.2 skrll /*
4621 1.29.2.2 skrll * Fill in probe request with the following parameters:
4622 1.29.2.2 skrll * TA is our vif HW address, which mac80211 ensures we have.
4623 1.29.2.2 skrll * Packet is broadcasted, so this is both SA and DA.
4624 1.29.2.2 skrll * The probe request IE is made out of two: first comes the most prioritized
4625 1.29.2.2 skrll * SSID if a directed scan is requested. Second comes whatever extra
4626 1.29.2.2 skrll * information was given to us as the scan request IE.
4627 1.29.2.2 skrll */
4628 1.29.2.2 skrll static uint16_t
4629 1.29.2.2 skrll iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct ieee80211_frame *frame,
4630 1.29.2.2 skrll const uint8_t *ta, int n_ssids, const uint8_t *ssid, int ssid_len,
4631 1.29.2.2 skrll const uint8_t *ie, int ie_len, int left)
4632 1.29.2.2 skrll {
4633 1.29.2.2 skrll int len = 0;
4634 1.29.2.2 skrll uint8_t *pos = NULL;
4635 1.29.2.2 skrll
4636 1.29.2.2 skrll /* Make sure there is enough space for the probe request,
4637 1.29.2.2 skrll * two mandatory IEs and the data */
4638 1.29.2.2 skrll left -= sizeof(*frame);
4639 1.29.2.2 skrll if (left < 0)
4640 1.29.2.2 skrll return 0;
4641 1.29.2.2 skrll
4642 1.29.2.2 skrll frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
4643 1.29.2.2 skrll IEEE80211_FC0_SUBTYPE_PROBE_REQ;
4644 1.29.2.2 skrll frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
4645 1.29.2.2 skrll IEEE80211_ADDR_COPY(frame->i_addr1, etherbroadcastaddr);
4646 1.29.2.2 skrll memcpy(frame->i_addr2, ta, ETHER_ADDR_LEN);
4647 1.29.2.2 skrll IEEE80211_ADDR_COPY(frame->i_addr3, etherbroadcastaddr);
4648 1.29.2.2 skrll
4649 1.29.2.2 skrll len += sizeof(*frame);
4650 1.29.2.2 skrll CTASSERT(sizeof(*frame) == 24);
4651 1.29.2.2 skrll
4652 1.29.2.2 skrll /* for passive scans, no need to fill anything */
4653 1.29.2.2 skrll if (n_ssids == 0)
4654 1.29.2.2 skrll return (uint16_t)len;
4655 1.29.2.2 skrll
4656 1.29.2.2 skrll /* points to the payload of the request */
4657 1.29.2.2 skrll pos = (uint8_t *)frame + sizeof(*frame);
4658 1.29.2.2 skrll
4659 1.29.2.2 skrll /* fill in our SSID IE */
4660 1.29.2.2 skrll left -= ssid_len + 2;
4661 1.29.2.2 skrll if (left < 0)
4662 1.29.2.2 skrll return 0;
4663 1.29.2.2 skrll *pos++ = IEEE80211_ELEMID_SSID;
4664 1.29.2.2 skrll *pos++ = ssid_len;
4665 1.29.2.2 skrll if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
4666 1.29.2.2 skrll memcpy(pos, ssid, ssid_len);
4667 1.29.2.2 skrll pos += ssid_len;
4668 1.29.2.2 skrll }
4669 1.29.2.2 skrll
4670 1.29.2.2 skrll len += ssid_len + 2;
4671 1.29.2.2 skrll
4672 1.29.2.2 skrll if (left < ie_len)
4673 1.29.2.2 skrll return len;
4674 1.29.2.2 skrll
4675 1.29.2.2 skrll if (ie && ie_len) {
4676 1.29.2.2 skrll memcpy(pos, ie, ie_len);
4677 1.29.2.2 skrll len += ie_len;
4678 1.29.2.2 skrll }
4679 1.29.2.2 skrll
4680 1.29.2.2 skrll return (uint16_t)len;
4681 1.29.2.2 skrll }
4682 1.29.2.2 skrll
4683 1.29.2.2 skrll static int
4684 1.29.2.2 skrll iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
4685 1.29.2.2 skrll int n_ssids, uint8_t *ssid, int ssid_len)
4686 1.29.2.2 skrll {
4687 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
4688 1.29.2.2 skrll struct iwm_host_cmd hcmd = {
4689 1.29.2.2 skrll .id = IWM_SCAN_REQUEST_CMD,
4690 1.29.2.2 skrll .len = { 0, },
4691 1.29.2.2 skrll .data = { sc->sc_scan_cmd, },
4692 1.29.2.2 skrll .flags = IWM_CMD_SYNC,
4693 1.29.2.2 skrll .dataflags = { IWM_HCMD_DFL_NOCOPY, },
4694 1.29.2.2 skrll };
4695 1.29.2.2 skrll struct iwm_scan_cmd *cmd = sc->sc_scan_cmd;
4696 1.29.2.2 skrll int is_assoc = 0;
4697 1.29.2.2 skrll int ret;
4698 1.29.2.2 skrll uint32_t status;
4699 1.29.2.2 skrll int basic_ssid = !(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID);
4700 1.29.2.2 skrll
4701 1.29.2.2 skrll //lockdep_assert_held(&mvm->mutex);
4702 1.29.2.2 skrll
4703 1.29.2.2 skrll sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
4704 1.29.2.2 skrll
4705 1.29.2.2 skrll DPRINTF(("Handling ieee80211 scan request\n"));
4706 1.29.2.2 skrll memset(cmd, 0, sc->sc_scan_cmd_len);
4707 1.29.2.2 skrll
4708 1.29.2.2 skrll cmd->quiet_time = htole16(IWM_ACTIVE_QUIET_TIME);
4709 1.29.2.2 skrll cmd->quiet_plcp_th = htole16(IWM_PLCP_QUIET_THRESH);
4710 1.29.2.2 skrll cmd->rxchain_sel_flags = iwm_mvm_scan_rx_chain(sc);
4711 1.29.2.2 skrll cmd->max_out_time = iwm_mvm_scan_max_out_time(sc, 0, is_assoc);
4712 1.29.2.2 skrll cmd->suspend_time = iwm_mvm_scan_suspend_time(sc, is_assoc);
4713 1.29.2.2 skrll cmd->rxon_flags = iwm_mvm_scan_rxon_flags(sc, flags);
4714 1.29.2.2 skrll cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP |
4715 1.29.2.2 skrll IWM_MAC_FILTER_IN_BEACON);
4716 1.29.2.2 skrll
4717 1.29.2.2 skrll cmd->type = htole32(IWM_SCAN_TYPE_FORCED);
4718 1.29.2.2 skrll cmd->repeats = htole32(1);
4719 1.29.2.2 skrll
4720 1.29.2.2 skrll /*
4721 1.29.2.2 skrll * If the user asked for passive scan, don't change to active scan if
4722 1.29.2.2 skrll * you see any activity on the channel - remain passive.
4723 1.29.2.2 skrll */
4724 1.29.2.2 skrll if (n_ssids > 0) {
4725 1.29.2.2 skrll cmd->passive2active = htole16(1);
4726 1.29.2.2 skrll cmd->scan_flags |= IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
4727 1.29.2.2 skrll #if 0
4728 1.29.2.2 skrll if (basic_ssid) {
4729 1.29.2.2 skrll ssid = req->ssids[0].ssid;
4730 1.29.2.2 skrll ssid_len = req->ssids[0].ssid_len;
4731 1.29.2.2 skrll }
4732 1.29.2.2 skrll #endif
4733 1.29.2.2 skrll } else {
4734 1.29.2.2 skrll cmd->passive2active = 0;
4735 1.29.2.2 skrll cmd->scan_flags &= ~IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
4736 1.29.2.2 skrll }
4737 1.29.2.2 skrll
4738 1.29.2.2 skrll cmd->tx_cmd.tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
4739 1.29.2.2 skrll IWM_TX_CMD_FLG_BT_DIS);
4740 1.29.2.2 skrll cmd->tx_cmd.sta_id = sc->sc_aux_sta.sta_id;
4741 1.29.2.2 skrll cmd->tx_cmd.life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
4742 1.29.2.2 skrll cmd->tx_cmd.rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, flags, 1/*XXX*/);
4743 1.29.2.2 skrll
4744 1.29.2.2 skrll cmd->tx_cmd.len = htole16(iwm_mvm_fill_probe_req(sc,
4745 1.29.2.2 skrll (struct ieee80211_frame *)cmd->data,
4746 1.29.2.2 skrll ic->ic_myaddr, n_ssids, ssid, ssid_len,
4747 1.29.2.2 skrll NULL, 0, sc->sc_capa_max_probe_len));
4748 1.29.2.2 skrll
4749 1.29.2.2 skrll cmd->channel_count
4750 1.29.2.2 skrll = iwm_mvm_scan_fill_channels(sc, cmd, flags, n_ssids, basic_ssid);
4751 1.29.2.2 skrll
4752 1.29.2.2 skrll cmd->len = htole16(sizeof(struct iwm_scan_cmd) +
4753 1.29.2.2 skrll le16toh(cmd->tx_cmd.len) +
4754 1.29.2.2 skrll (cmd->channel_count * sizeof(struct iwm_scan_channel)));
4755 1.29.2.2 skrll hcmd.len[0] = le16toh(cmd->len);
4756 1.29.2.2 skrll
4757 1.29.2.2 skrll status = IWM_SCAN_RESPONSE_OK;
4758 1.29.2.2 skrll ret = iwm_mvm_send_cmd_status(sc, &hcmd, &status);
4759 1.29.2.2 skrll if (!ret && status == IWM_SCAN_RESPONSE_OK) {
4760 1.29.2.2 skrll DPRINTF(("Scan request was sent successfully\n"));
4761 1.29.2.2 skrll } else {
4762 1.29.2.2 skrll /*
4763 1.29.2.2 skrll * If the scan failed, it usually means that the FW was unable
4764 1.29.2.2 skrll * to allocate the time events. Warn on it, but maybe we
4765 1.29.2.2 skrll * should try to send the command again with different params.
4766 1.29.2.2 skrll */
4767 1.29.2.2 skrll sc->sc_scanband = 0;
4768 1.29.2.2 skrll ret = EIO;
4769 1.29.2.2 skrll }
4770 1.29.2.2 skrll return ret;
4771 1.29.2.2 skrll }
4772 1.29.2.2 skrll
4773 1.29.2.2 skrll /*
4774 1.29.2.2 skrll * END mvm/scan.c
4775 1.29.2.2 skrll */
4776 1.29.2.2 skrll
4777 1.29.2.2 skrll /*
4778 1.29.2.2 skrll * BEGIN mvm/mac-ctxt.c
4779 1.29.2.2 skrll */
4780 1.29.2.2 skrll
4781 1.29.2.2 skrll static void
4782 1.29.2.2 skrll iwm_mvm_ack_rates(struct iwm_softc *sc, struct iwm_node *in,
4783 1.29.2.2 skrll int *cck_rates, int *ofdm_rates)
4784 1.29.2.2 skrll {
4785 1.29.2.2 skrll struct ieee80211_node *ni = &in->in_ni;
4786 1.29.2.2 skrll int lowest_present_ofdm = 100;
4787 1.29.2.2 skrll int lowest_present_cck = 100;
4788 1.29.2.2 skrll uint8_t cck = 0;
4789 1.29.2.2 skrll uint8_t ofdm = 0;
4790 1.29.2.2 skrll int i;
4791 1.29.2.2 skrll
4792 1.29.2.2 skrll if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
4793 1.29.2.2 skrll for (i = 0; i <= IWM_LAST_CCK_RATE; i++) {
4794 1.29.2.2 skrll cck |= (1 << i);
4795 1.29.2.2 skrll if (lowest_present_cck > i)
4796 1.29.2.2 skrll lowest_present_cck = i;
4797 1.29.2.2 skrll }
4798 1.29.2.2 skrll }
4799 1.29.2.2 skrll for (i = IWM_FIRST_OFDM_RATE; i <= IWM_LAST_NON_HT_RATE; i++) {
4800 1.29.2.2 skrll int adj = i - IWM_FIRST_OFDM_RATE;
4801 1.29.2.2 skrll ofdm |= (1 << adj);
4802 1.29.2.2 skrll if (lowest_present_ofdm > i)
4803 1.29.2.2 skrll lowest_present_ofdm = i;
4804 1.29.2.2 skrll }
4805 1.29.2.2 skrll
4806 1.29.2.2 skrll /*
4807 1.29.2.2 skrll * Now we've got the basic rates as bitmaps in the ofdm and cck
4808 1.29.2.2 skrll * variables. This isn't sufficient though, as there might not
4809 1.29.2.2 skrll * be all the right rates in the bitmap. E.g. if the only basic
4810 1.29.2.2 skrll * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
4811 1.29.2.2 skrll * and 6 Mbps because the 802.11-2007 standard says in 9.6:
4812 1.29.2.2 skrll *
4813 1.29.2.2 skrll * [...] a STA responding to a received frame shall transmit
4814 1.29.2.2 skrll * its Control Response frame [...] at the highest rate in the
4815 1.29.2.2 skrll * BSSBasicRateSet parameter that is less than or equal to the
4816 1.29.2.2 skrll * rate of the immediately previous frame in the frame exchange
4817 1.29.2.2 skrll * sequence ([...]) and that is of the same modulation class
4818 1.29.2.2 skrll * ([...]) as the received frame. If no rate contained in the
4819 1.29.2.2 skrll * BSSBasicRateSet parameter meets these conditions, then the
4820 1.29.2.2 skrll * control frame sent in response to a received frame shall be
4821 1.29.2.2 skrll * transmitted at the highest mandatory rate of the PHY that is
4822 1.29.2.2 skrll * less than or equal to the rate of the received frame, and
4823 1.29.2.2 skrll * that is of the same modulation class as the received frame.
4824 1.29.2.2 skrll *
4825 1.29.2.2 skrll * As a consequence, we need to add all mandatory rates that are
4826 1.29.2.2 skrll * lower than all of the basic rates to these bitmaps.
4827 1.29.2.2 skrll */
4828 1.29.2.2 skrll
4829 1.29.2.2 skrll if (IWM_RATE_24M_INDEX < lowest_present_ofdm)
4830 1.29.2.2 skrll ofdm |= IWM_RATE_BIT_MSK(24) >> IWM_FIRST_OFDM_RATE;
4831 1.29.2.2 skrll if (IWM_RATE_12M_INDEX < lowest_present_ofdm)
4832 1.29.2.2 skrll ofdm |= IWM_RATE_BIT_MSK(12) >> IWM_FIRST_OFDM_RATE;
4833 1.29.2.2 skrll /* 6M already there or needed so always add */
4834 1.29.2.2 skrll ofdm |= IWM_RATE_BIT_MSK(6) >> IWM_FIRST_OFDM_RATE;
4835 1.29.2.2 skrll
4836 1.29.2.2 skrll /*
4837 1.29.2.2 skrll * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
4838 1.29.2.2 skrll * Note, however:
4839 1.29.2.2 skrll * - if no CCK rates are basic, it must be ERP since there must
4840 1.29.2.2 skrll * be some basic rates at all, so they're OFDM => ERP PHY
4841 1.29.2.2 skrll * (or we're in 5 GHz, and the cck bitmap will never be used)
4842 1.29.2.2 skrll * - if 11M is a basic rate, it must be ERP as well, so add 5.5M
4843 1.29.2.2 skrll * - if 5.5M is basic, 1M and 2M are mandatory
4844 1.29.2.2 skrll * - if 2M is basic, 1M is mandatory
4845 1.29.2.2 skrll * - if 1M is basic, that's the only valid ACK rate.
4846 1.29.2.2 skrll * As a consequence, it's not as complicated as it sounds, just add
4847 1.29.2.2 skrll * any lower rates to the ACK rate bitmap.
4848 1.29.2.2 skrll */
4849 1.29.2.2 skrll if (IWM_RATE_11M_INDEX < lowest_present_cck)
4850 1.29.2.2 skrll cck |= IWM_RATE_BIT_MSK(11) >> IWM_FIRST_CCK_RATE;
4851 1.29.2.2 skrll if (IWM_RATE_5M_INDEX < lowest_present_cck)
4852 1.29.2.2 skrll cck |= IWM_RATE_BIT_MSK(5) >> IWM_FIRST_CCK_RATE;
4853 1.29.2.2 skrll if (IWM_RATE_2M_INDEX < lowest_present_cck)
4854 1.29.2.2 skrll cck |= IWM_RATE_BIT_MSK(2) >> IWM_FIRST_CCK_RATE;
4855 1.29.2.2 skrll /* 1M already there or needed so always add */
4856 1.29.2.2 skrll cck |= IWM_RATE_BIT_MSK(1) >> IWM_FIRST_CCK_RATE;
4857 1.29.2.2 skrll
4858 1.29.2.2 skrll *cck_rates = cck;
4859 1.29.2.2 skrll *ofdm_rates = ofdm;
4860 1.29.2.2 skrll }
4861 1.29.2.2 skrll
4862 1.29.2.2 skrll static void
4863 1.29.2.2 skrll iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
4864 1.29.2.2 skrll struct iwm_mac_ctx_cmd *cmd, uint32_t action)
4865 1.29.2.2 skrll {
4866 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
4867 1.29.2.2 skrll struct ieee80211_node *ni = ic->ic_bss;
4868 1.29.2.2 skrll int cck_ack_rates, ofdm_ack_rates;
4869 1.29.2.2 skrll int i;
4870 1.29.2.2 skrll
4871 1.29.2.2 skrll cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
4872 1.29.2.2 skrll in->in_color));
4873 1.29.2.2 skrll cmd->action = htole32(action);
4874 1.29.2.2 skrll
4875 1.29.2.2 skrll cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
4876 1.29.2.2 skrll cmd->tsf_id = htole32(in->in_tsfid);
4877 1.29.2.2 skrll
4878 1.29.2.2 skrll IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr);
4879 1.29.2.2 skrll if (in->in_assoc) {
4880 1.29.2.2 skrll IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
4881 1.29.2.2 skrll } else {
4882 1.29.2.2 skrll memset(cmd->bssid_addr, 0, sizeof(cmd->bssid_addr));
4883 1.29.2.2 skrll }
4884 1.29.2.2 skrll iwm_mvm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates);
4885 1.29.2.2 skrll cmd->cck_rates = htole32(cck_ack_rates);
4886 1.29.2.2 skrll cmd->ofdm_rates = htole32(ofdm_ack_rates);
4887 1.29.2.2 skrll
4888 1.29.2.2 skrll cmd->cck_short_preamble
4889 1.29.2.2 skrll = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE)
4890 1.29.2.2 skrll ? IWM_MAC_FLG_SHORT_PREAMBLE : 0);
4891 1.29.2.2 skrll cmd->short_slot
4892 1.29.2.2 skrll = htole32((ic->ic_flags & IEEE80211_F_SHSLOT)
4893 1.29.2.2 skrll ? IWM_MAC_FLG_SHORT_SLOT : 0);
4894 1.29.2.2 skrll
4895 1.29.2.2 skrll for (i = 0; i < IWM_AC_NUM+1; i++) {
4896 1.29.2.2 skrll int txf = i;
4897 1.29.2.2 skrll
4898 1.29.2.2 skrll cmd->ac[txf].cw_min = htole16(0x0f);
4899 1.29.2.2 skrll cmd->ac[txf].cw_max = htole16(0x3f);
4900 1.29.2.2 skrll cmd->ac[txf].aifsn = 1;
4901 1.29.2.2 skrll cmd->ac[txf].fifos_mask = (1 << txf);
4902 1.29.2.2 skrll cmd->ac[txf].edca_txop = 0;
4903 1.29.2.2 skrll }
4904 1.29.2.2 skrll
4905 1.29.2.2 skrll if (ic->ic_flags & IEEE80211_F_USEPROT)
4906 1.29.2.2 skrll cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT);
4907 1.29.2.2 skrll
4908 1.29.2.2 skrll cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP);
4909 1.29.2.2 skrll }
4910 1.29.2.2 skrll
4911 1.29.2.2 skrll static int
4912 1.29.2.2 skrll iwm_mvm_mac_ctxt_send_cmd(struct iwm_softc *sc, struct iwm_mac_ctx_cmd *cmd)
4913 1.29.2.2 skrll {
4914 1.29.2.2 skrll int ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC,
4915 1.29.2.2 skrll sizeof(*cmd), cmd);
4916 1.29.2.2 skrll if (ret)
4917 1.29.2.2 skrll DPRINTF(("%s: Failed to send MAC context (action:%d): %d\n",
4918 1.29.2.2 skrll DEVNAME(sc), le32toh(cmd->action), ret));
4919 1.29.2.2 skrll return ret;
4920 1.29.2.2 skrll }
4921 1.29.2.2 skrll
4922 1.29.2.2 skrll /*
4923 1.29.2.2 skrll * Fill the specific data for mac context of type station or p2p client
4924 1.29.2.2 skrll */
4925 1.29.2.2 skrll static void
4926 1.29.2.2 skrll iwm_mvm_mac_ctxt_cmd_fill_sta(struct iwm_softc *sc, struct iwm_node *in,
4927 1.29.2.2 skrll struct iwm_mac_data_sta *ctxt_sta, int force_assoc_off)
4928 1.29.2.2 skrll {
4929 1.29.2.2 skrll struct ieee80211_node *ni = &in->in_ni;
4930 1.29.2.2 skrll unsigned dtim_period, dtim_count;
4931 1.29.2.2 skrll
4932 1.29.2.2 skrll dtim_period = ni->ni_dtim_period;
4933 1.29.2.2 skrll dtim_count = ni->ni_dtim_count;
4934 1.29.2.2 skrll
4935 1.29.2.2 skrll /* We need the dtim_period to set the MAC as associated */
4936 1.29.2.2 skrll if (in->in_assoc && dtim_period && !force_assoc_off) {
4937 1.29.2.2 skrll uint64_t tsf;
4938 1.29.2.2 skrll uint32_t dtim_offs;
4939 1.29.2.2 skrll
4940 1.29.2.2 skrll /*
4941 1.29.2.2 skrll * The DTIM count counts down, so when it is N that means N
4942 1.29.2.2 skrll * more beacon intervals happen until the DTIM TBTT. Therefore
4943 1.29.2.2 skrll * add this to the current time. If that ends up being in the
4944 1.29.2.2 skrll * future, the firmware will handle it.
4945 1.29.2.2 skrll *
4946 1.29.2.2 skrll * Also note that the system_timestamp (which we get here as
4947 1.29.2.2 skrll * "sync_device_ts") and TSF timestamp aren't at exactly the
4948 1.29.2.2 skrll * same offset in the frame -- the TSF is at the first symbol
4949 1.29.2.2 skrll * of the TSF, the system timestamp is at signal acquisition
4950 1.29.2.2 skrll * time. This means there's an offset between them of at most
4951 1.29.2.2 skrll * a few hundred microseconds (24 * 8 bits + PLCP time gives
4952 1.29.2.2 skrll * 384us in the longest case), this is currently not relevant
4953 1.29.2.2 skrll * as the firmware wakes up around 2ms before the TBTT.
4954 1.29.2.2 skrll */
4955 1.29.2.2 skrll dtim_offs = dtim_count * ni->ni_intval;
4956 1.29.2.2 skrll /* convert TU to usecs */
4957 1.29.2.2 skrll dtim_offs *= 1024;
4958 1.29.2.2 skrll
4959 1.29.2.2 skrll tsf = ni->ni_tstamp.tsf;
4960 1.29.2.2 skrll
4961 1.29.2.2 skrll ctxt_sta->dtim_tsf = htole64(tsf + dtim_offs);
4962 1.29.2.2 skrll ctxt_sta->dtim_time = htole64(ni->ni_rstamp + dtim_offs);
4963 1.29.2.2 skrll
4964 1.29.2.2 skrll DPRINTF(("DTIM TBTT is 0x%llx/0x%x, offset %d\n",
4965 1.29.2.2 skrll (long long)le64toh(ctxt_sta->dtim_tsf),
4966 1.29.2.2 skrll le32toh(ctxt_sta->dtim_time), dtim_offs));
4967 1.29.2.2 skrll
4968 1.29.2.2 skrll ctxt_sta->is_assoc = htole32(1);
4969 1.29.2.2 skrll } else {
4970 1.29.2.2 skrll ctxt_sta->is_assoc = htole32(0);
4971 1.29.2.2 skrll }
4972 1.29.2.2 skrll
4973 1.29.2.2 skrll ctxt_sta->bi = htole32(ni->ni_intval);
4974 1.29.2.2 skrll ctxt_sta->bi_reciprocal = htole32(iwm_mvm_reciprocal(ni->ni_intval));
4975 1.29.2.2 skrll ctxt_sta->dtim_interval = htole32(ni->ni_intval * dtim_period);
4976 1.29.2.2 skrll ctxt_sta->dtim_reciprocal =
4977 1.29.2.2 skrll htole32(iwm_mvm_reciprocal(ni->ni_intval * dtim_period));
4978 1.29.2.2 skrll
4979 1.29.2.2 skrll /* 10 = CONN_MAX_LISTEN_INTERVAL */
4980 1.29.2.2 skrll ctxt_sta->listen_interval = htole32(10);
4981 1.29.2.2 skrll ctxt_sta->assoc_id = htole32(ni->ni_associd);
4982 1.29.2.2 skrll }
4983 1.29.2.2 skrll
4984 1.29.2.2 skrll static int
4985 1.29.2.2 skrll iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *sc, struct iwm_node *in,
4986 1.29.2.2 skrll uint32_t action)
4987 1.29.2.2 skrll {
4988 1.29.2.2 skrll struct iwm_mac_ctx_cmd cmd;
4989 1.29.2.2 skrll
4990 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
4991 1.29.2.2 skrll
4992 1.29.2.2 skrll /* Fill the common data for all mac context types */
4993 1.29.2.2 skrll iwm_mvm_mac_ctxt_cmd_common(sc, in, &cmd, action);
4994 1.29.2.2 skrll
4995 1.29.2.2 skrll /* Allow beacons to pass through as long as we are not associated,or we
4996 1.29.2.2 skrll * do not have dtim period information */
4997 1.29.2.2 skrll if (!in->in_assoc || !sc->sc_ic.ic_dtim_period)
4998 1.29.2.2 skrll cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON);
4999 1.29.2.2 skrll else
5000 1.29.2.2 skrll cmd.filter_flags &= ~htole32(IWM_MAC_FILTER_IN_BEACON);
5001 1.29.2.2 skrll
5002 1.29.2.2 skrll /* Fill the data specific for station mode */
5003 1.29.2.2 skrll iwm_mvm_mac_ctxt_cmd_fill_sta(sc, in,
5004 1.29.2.2 skrll &cmd.sta, action == IWM_FW_CTXT_ACTION_ADD);
5005 1.29.2.2 skrll
5006 1.29.2.2 skrll return iwm_mvm_mac_ctxt_send_cmd(sc, &cmd);
5007 1.29.2.2 skrll }
5008 1.29.2.2 skrll
5009 1.29.2.2 skrll static int
5010 1.29.2.2 skrll iwm_mvm_mac_ctx_send(struct iwm_softc *sc, struct iwm_node *in, uint32_t action)
5011 1.29.2.2 skrll {
5012 1.29.2.2 skrll return iwm_mvm_mac_ctxt_cmd_station(sc, in, action);
5013 1.29.2.2 skrll }
5014 1.29.2.2 skrll
5015 1.29.2.2 skrll static int
5016 1.29.2.2 skrll iwm_mvm_mac_ctxt_add(struct iwm_softc *sc, struct iwm_node *in)
5017 1.29.2.2 skrll {
5018 1.29.2.2 skrll int ret;
5019 1.29.2.2 skrll
5020 1.29.2.2 skrll ret = iwm_mvm_mac_ctx_send(sc, in, IWM_FW_CTXT_ACTION_ADD);
5021 1.29.2.2 skrll if (ret)
5022 1.29.2.2 skrll return ret;
5023 1.29.2.2 skrll
5024 1.29.2.2 skrll return 0;
5025 1.29.2.2 skrll }
5026 1.29.2.2 skrll
5027 1.29.2.2 skrll static int
5028 1.29.2.2 skrll iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct iwm_node *in)
5029 1.29.2.2 skrll {
5030 1.29.2.2 skrll return iwm_mvm_mac_ctx_send(sc, in, IWM_FW_CTXT_ACTION_MODIFY);
5031 1.29.2.2 skrll }
5032 1.29.2.2 skrll
5033 1.29.2.2 skrll #if 0
5034 1.29.2.2 skrll static int
5035 1.29.2.2 skrll iwm_mvm_mac_ctxt_remove(struct iwm_softc *sc, struct iwm_node *in)
5036 1.29.2.2 skrll {
5037 1.29.2.2 skrll struct iwm_mac_ctx_cmd cmd;
5038 1.29.2.2 skrll int ret;
5039 1.29.2.2 skrll
5040 1.29.2.2 skrll if (!in->in_uploaded) {
5041 1.29.2.2 skrll print("%s: attempt to remove !uploaded node %p", DEVNAME(sc), in);
5042 1.29.2.2 skrll return EIO;
5043 1.29.2.2 skrll }
5044 1.29.2.2 skrll
5045 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
5046 1.29.2.2 skrll
5047 1.29.2.2 skrll cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
5048 1.29.2.2 skrll in->in_color));
5049 1.29.2.2 skrll cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE);
5050 1.29.2.2 skrll
5051 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu(sc,
5052 1.29.2.2 skrll IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd);
5053 1.29.2.2 skrll if (ret) {
5054 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
5055 1.29.2.2 skrll "Failed to remove MAC context: %d\n", ret);
5056 1.29.2.2 skrll return ret;
5057 1.29.2.2 skrll }
5058 1.29.2.2 skrll in->in_uploaded = 0;
5059 1.29.2.2 skrll
5060 1.29.2.2 skrll return 0;
5061 1.29.2.2 skrll }
5062 1.29.2.2 skrll #endif
5063 1.29.2.2 skrll
5064 1.29.2.2 skrll #define IWM_MVM_MISSED_BEACONS_THRESHOLD 8
5065 1.29.2.2 skrll
5066 1.29.2.2 skrll static void
5067 1.29.2.2 skrll iwm_mvm_rx_missed_beacons_notif(struct iwm_softc *sc,
5068 1.29.2.2 skrll struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
5069 1.29.2.2 skrll {
5070 1.29.2.2 skrll struct iwm_missed_beacons_notif *mb = (void *)pkt->data;
5071 1.29.2.2 skrll
5072 1.29.2.2 skrll DPRINTF(("missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
5073 1.29.2.2 skrll le32toh(mb->mac_id),
5074 1.29.2.2 skrll le32toh(mb->consec_missed_beacons),
5075 1.29.2.2 skrll le32toh(mb->consec_missed_beacons_since_last_rx),
5076 1.29.2.2 skrll le32toh(mb->num_recvd_beacons),
5077 1.29.2.2 skrll le32toh(mb->num_expected_beacons)));
5078 1.29.2.2 skrll
5079 1.29.2.2 skrll /*
5080 1.29.2.2 skrll * TODO: the threshold should be adjusted based on latency conditions,
5081 1.29.2.2 skrll * and/or in case of a CS flow on one of the other AP vifs.
5082 1.29.2.2 skrll */
5083 1.29.2.2 skrll if (le32toh(mb->consec_missed_beacons_since_last_rx) >
5084 1.29.2.2 skrll IWM_MVM_MISSED_BEACONS_THRESHOLD)
5085 1.29.2.2 skrll ieee80211_beacon_miss(&sc->sc_ic);
5086 1.29.2.2 skrll }
5087 1.29.2.2 skrll
5088 1.29.2.2 skrll /*
5089 1.29.2.2 skrll * END mvm/mac-ctxt.c
5090 1.29.2.2 skrll */
5091 1.29.2.2 skrll
5092 1.29.2.2 skrll /*
5093 1.29.2.2 skrll * BEGIN mvm/quota.c
5094 1.29.2.2 skrll */
5095 1.29.2.2 skrll
5096 1.29.2.2 skrll static int
5097 1.29.2.2 skrll iwm_mvm_update_quotas(struct iwm_softc *sc, struct iwm_node *in)
5098 1.29.2.2 skrll {
5099 1.29.2.2 skrll struct iwm_time_quota_cmd cmd;
5100 1.29.2.2 skrll int i, idx, ret, num_active_macs, quota, quota_rem;
5101 1.29.2.2 skrll int colors[IWM_MAX_BINDINGS] = { -1, -1, -1, -1, };
5102 1.29.2.2 skrll int n_ifs[IWM_MAX_BINDINGS] = {0, };
5103 1.29.2.2 skrll uint16_t id;
5104 1.29.2.2 skrll
5105 1.29.2.2 skrll memset(&cmd, 0, sizeof(cmd));
5106 1.29.2.2 skrll
5107 1.29.2.2 skrll /* currently, PHY ID == binding ID */
5108 1.29.2.2 skrll if (in) {
5109 1.29.2.2 skrll id = in->in_phyctxt->id;
5110 1.29.2.2 skrll KASSERT(id < IWM_MAX_BINDINGS);
5111 1.29.2.2 skrll colors[id] = in->in_phyctxt->color;
5112 1.29.2.2 skrll
5113 1.29.2.2 skrll if (1)
5114 1.29.2.2 skrll n_ifs[id] = 1;
5115 1.29.2.2 skrll }
5116 1.29.2.2 skrll
5117 1.29.2.2 skrll /*
5118 1.29.2.2 skrll * The FW's scheduling session consists of
5119 1.29.2.2 skrll * IWM_MVM_MAX_QUOTA fragments. Divide these fragments
5120 1.29.2.2 skrll * equally between all the bindings that require quota
5121 1.29.2.2 skrll */
5122 1.29.2.2 skrll num_active_macs = 0;
5123 1.29.2.2 skrll for (i = 0; i < IWM_MAX_BINDINGS; i++) {
5124 1.29.2.2 skrll cmd.quotas[i].id_and_color = htole32(IWM_FW_CTXT_INVALID);
5125 1.29.2.2 skrll num_active_macs += n_ifs[i];
5126 1.29.2.2 skrll }
5127 1.29.2.2 skrll
5128 1.29.2.2 skrll quota = 0;
5129 1.29.2.2 skrll quota_rem = 0;
5130 1.29.2.2 skrll if (num_active_macs) {
5131 1.29.2.2 skrll quota = IWM_MVM_MAX_QUOTA / num_active_macs;
5132 1.29.2.2 skrll quota_rem = IWM_MVM_MAX_QUOTA % num_active_macs;
5133 1.29.2.2 skrll }
5134 1.29.2.2 skrll
5135 1.29.2.2 skrll for (idx = 0, i = 0; i < IWM_MAX_BINDINGS; i++) {
5136 1.29.2.2 skrll if (colors[i] < 0)
5137 1.29.2.2 skrll continue;
5138 1.29.2.2 skrll
5139 1.29.2.2 skrll cmd.quotas[idx].id_and_color =
5140 1.29.2.2 skrll htole32(IWM_FW_CMD_ID_AND_COLOR(i, colors[i]));
5141 1.29.2.2 skrll
5142 1.29.2.2 skrll if (n_ifs[i] <= 0) {
5143 1.29.2.2 skrll cmd.quotas[idx].quota = htole32(0);
5144 1.29.2.2 skrll cmd.quotas[idx].max_duration = htole32(0);
5145 1.29.2.2 skrll } else {
5146 1.29.2.2 skrll cmd.quotas[idx].quota = htole32(quota * n_ifs[i]);
5147 1.29.2.2 skrll cmd.quotas[idx].max_duration = htole32(0);
5148 1.29.2.2 skrll }
5149 1.29.2.2 skrll idx++;
5150 1.29.2.2 skrll }
5151 1.29.2.2 skrll
5152 1.29.2.2 skrll /* Give the remainder of the session to the first binding */
5153 1.29.2.2 skrll cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem);
5154 1.29.2.2 skrll
5155 1.29.2.2 skrll ret = iwm_mvm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, IWM_CMD_SYNC,
5156 1.29.2.2 skrll sizeof(cmd), &cmd);
5157 1.29.2.2 skrll if (ret)
5158 1.29.2.2 skrll DPRINTF(("%s: Failed to send quota: %d\n", DEVNAME(sc), ret));
5159 1.29.2.2 skrll return ret;
5160 1.29.2.2 skrll }
5161 1.29.2.2 skrll
5162 1.29.2.2 skrll /*
5163 1.29.2.2 skrll * END mvm/quota.c
5164 1.29.2.2 skrll */
5165 1.29.2.2 skrll
5166 1.29.2.2 skrll /*
5167 1.29.2.2 skrll * aieee80211 routines
5168 1.29.2.2 skrll */
5169 1.29.2.2 skrll
5170 1.29.2.2 skrll /*
5171 1.29.2.2 skrll * Change to AUTH state in 80211 state machine. Roughly matches what
5172 1.29.2.2 skrll * Linux does in bss_info_changed().
5173 1.29.2.2 skrll */
5174 1.29.2.2 skrll static int
5175 1.29.2.2 skrll iwm_auth(struct iwm_softc *sc)
5176 1.29.2.2 skrll {
5177 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5178 1.29.2.2 skrll struct iwm_node *in = (void *)ic->ic_bss;
5179 1.29.2.2 skrll uint32_t duration;
5180 1.29.2.2 skrll uint32_t min_duration;
5181 1.29.2.2 skrll int error;
5182 1.29.2.2 skrll
5183 1.29.2.2 skrll in->in_assoc = 0;
5184 1.29.2.2 skrll
5185 1.29.2.2 skrll if ((error = iwm_allow_mcast(sc)) != 0)
5186 1.29.2.2 skrll return error;
5187 1.29.2.2 skrll
5188 1.29.2.2 skrll if ((error = iwm_mvm_mac_ctxt_add(sc, in)) != 0) {
5189 1.29.2.2 skrll DPRINTF(("%s: failed to add MAC\n", DEVNAME(sc)));
5190 1.29.2.2 skrll return error;
5191 1.29.2.2 skrll }
5192 1.29.2.2 skrll
5193 1.29.2.2 skrll if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0],
5194 1.29.2.2 skrll in->in_ni.ni_chan, 1, 1)) != 0) {
5195 1.29.2.2 skrll DPRINTF(("%s: failed add phy ctxt\n", DEVNAME(sc)));
5196 1.29.2.2 skrll return error;
5197 1.29.2.2 skrll }
5198 1.29.2.2 skrll in->in_phyctxt = &sc->sc_phyctxt[0];
5199 1.29.2.2 skrll
5200 1.29.2.2 skrll if ((error = iwm_mvm_binding_add_vif(sc, in)) != 0) {
5201 1.29.2.2 skrll DPRINTF(("%s: binding cmd\n", DEVNAME(sc)));
5202 1.29.2.2 skrll return error;
5203 1.29.2.2 skrll }
5204 1.29.2.2 skrll
5205 1.29.2.2 skrll if ((error = iwm_mvm_add_sta(sc, in)) != 0) {
5206 1.29.2.2 skrll DPRINTF(("%s: failed to add MAC\n", DEVNAME(sc)));
5207 1.29.2.2 skrll return error;
5208 1.29.2.2 skrll }
5209 1.29.2.2 skrll
5210 1.29.2.2 skrll /* a bit superfluous? */
5211 1.29.2.2 skrll while (sc->sc_auth_prot)
5212 1.29.2.2 skrll tsleep(&sc->sc_auth_prot, 0, "iwmauth", 0);
5213 1.29.2.2 skrll sc->sc_auth_prot = 1;
5214 1.29.2.2 skrll
5215 1.29.2.2 skrll duration = min(IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
5216 1.29.2.2 skrll 200 + in->in_ni.ni_intval);
5217 1.29.2.2 skrll min_duration = min(IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
5218 1.29.2.2 skrll 100 + in->in_ni.ni_intval);
5219 1.29.2.2 skrll iwm_mvm_protect_session(sc, in, duration, min_duration, 500);
5220 1.29.2.2 skrll
5221 1.29.2.2 skrll while (sc->sc_auth_prot != 2) {
5222 1.29.2.2 skrll /*
5223 1.29.2.2 skrll * well, meh, but if the kernel is sleeping for half a
5224 1.29.2.2 skrll * second, we have bigger problems
5225 1.29.2.2 skrll */
5226 1.29.2.2 skrll if (sc->sc_auth_prot == 0) {
5227 1.29.2.2 skrll DPRINTF(("%s: missed auth window!\n", DEVNAME(sc)));
5228 1.29.2.2 skrll return ETIMEDOUT;
5229 1.29.2.2 skrll } else if (sc->sc_auth_prot == -1) {
5230 1.29.2.2 skrll DPRINTF(("%s: no time event, denied!\n", DEVNAME(sc)));
5231 1.29.2.2 skrll sc->sc_auth_prot = 0;
5232 1.29.2.2 skrll return EAUTH;
5233 1.29.2.2 skrll }
5234 1.29.2.2 skrll tsleep(&sc->sc_auth_prot, 0, "iwmau2", 0);
5235 1.29.2.2 skrll }
5236 1.29.2.2 skrll
5237 1.29.2.2 skrll return 0;
5238 1.29.2.2 skrll }
5239 1.29.2.2 skrll
5240 1.29.2.2 skrll static int
5241 1.29.2.2 skrll iwm_assoc(struct iwm_softc *sc)
5242 1.29.2.2 skrll {
5243 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5244 1.29.2.2 skrll struct iwm_node *in = (void *)ic->ic_bss;
5245 1.29.2.2 skrll int error;
5246 1.29.2.2 skrll
5247 1.29.2.2 skrll if ((error = iwm_mvm_update_sta(sc, in)) != 0) {
5248 1.29.2.2 skrll DPRINTF(("%s: failed to update STA\n", DEVNAME(sc)));
5249 1.29.2.2 skrll return error;
5250 1.29.2.2 skrll }
5251 1.29.2.2 skrll
5252 1.29.2.2 skrll in->in_assoc = 1;
5253 1.29.2.2 skrll if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
5254 1.29.2.2 skrll DPRINTF(("%s: failed to update MAC\n", DEVNAME(sc)));
5255 1.29.2.2 skrll return error;
5256 1.29.2.2 skrll }
5257 1.29.2.2 skrll
5258 1.29.2.2 skrll return 0;
5259 1.29.2.2 skrll }
5260 1.29.2.2 skrll
5261 1.29.2.2 skrll static int
5262 1.29.2.2 skrll iwm_release(struct iwm_softc *sc, struct iwm_node *in)
5263 1.29.2.2 skrll {
5264 1.29.2.2 skrll /*
5265 1.29.2.2 skrll * Ok, so *technically* the proper set of calls for going
5266 1.29.2.2 skrll * from RUN back to SCAN is:
5267 1.29.2.2 skrll *
5268 1.29.2.2 skrll * iwm_mvm_power_mac_disable(sc, in);
5269 1.29.2.2 skrll * iwm_mvm_mac_ctxt_changed(sc, in);
5270 1.29.2.2 skrll * iwm_mvm_rm_sta(sc, in);
5271 1.29.2.2 skrll * iwm_mvm_update_quotas(sc, NULL);
5272 1.29.2.2 skrll * iwm_mvm_mac_ctxt_changed(sc, in);
5273 1.29.2.2 skrll * iwm_mvm_binding_remove_vif(sc, in);
5274 1.29.2.2 skrll * iwm_mvm_mac_ctxt_remove(sc, in);
5275 1.29.2.2 skrll *
5276 1.29.2.2 skrll * However, that freezes the device not matter which permutations
5277 1.29.2.2 skrll * and modifications are attempted. Obviously, this driver is missing
5278 1.29.2.2 skrll * something since it works in the Linux driver, but figuring out what
5279 1.29.2.2 skrll * is missing is a little more complicated. Now, since we're going
5280 1.29.2.2 skrll * back to nothing anyway, we'll just do a complete device reset.
5281 1.29.2.2 skrll * Up your's, device!
5282 1.29.2.2 skrll */
5283 1.29.2.2 skrll //iwm_mvm_flush_tx_path(sc, 0xf, 1);
5284 1.29.2.2 skrll iwm_stop_device(sc);
5285 1.29.2.2 skrll iwm_init_hw(sc);
5286 1.29.2.2 skrll if (in)
5287 1.29.2.2 skrll in->in_assoc = 0;
5288 1.29.2.2 skrll return 0;
5289 1.29.2.2 skrll
5290 1.29.2.2 skrll #if 0
5291 1.29.2.2 skrll int error;
5292 1.29.2.2 skrll
5293 1.29.2.2 skrll iwm_mvm_power_mac_disable(sc, in);
5294 1.29.2.2 skrll
5295 1.29.2.2 skrll if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
5296 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "mac ctxt change fail 1 %d\n",
5297 1.29.2.2 skrll error);
5298 1.29.2.2 skrll return error;
5299 1.29.2.2 skrll }
5300 1.29.2.2 skrll
5301 1.29.2.2 skrll if ((error = iwm_mvm_rm_sta(sc, in)) != 0) {
5302 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "sta remove fail %d\n", error);
5303 1.29.2.2 skrll return error;
5304 1.29.2.2 skrll }
5305 1.29.2.2 skrll error = iwm_mvm_rm_sta(sc, in);
5306 1.29.2.2 skrll in->in_assoc = 0;
5307 1.29.2.2 skrll iwm_mvm_update_quotas(sc, NULL);
5308 1.29.2.2 skrll if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
5309 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "mac ctxt change fail 2 %d\n",
5310 1.29.2.2 skrll error);
5311 1.29.2.2 skrll return error;
5312 1.29.2.2 skrll }
5313 1.29.2.2 skrll iwm_mvm_binding_remove_vif(sc, in);
5314 1.29.2.2 skrll
5315 1.29.2.2 skrll iwm_mvm_mac_ctxt_remove(sc, in);
5316 1.29.2.2 skrll
5317 1.29.2.2 skrll return error;
5318 1.29.2.2 skrll #endif
5319 1.29.2.2 skrll }
5320 1.29.2.2 skrll
5321 1.29.2.2 skrll
5322 1.29.2.2 skrll static struct ieee80211_node *
5323 1.29.2.2 skrll iwm_node_alloc(struct ieee80211_node_table *nt)
5324 1.29.2.2 skrll {
5325 1.29.2.2 skrll return malloc(sizeof(struct iwm_node), M_80211_NODE, M_NOWAIT | M_ZERO);
5326 1.29.2.2 skrll }
5327 1.29.2.2 skrll
5328 1.29.2.2 skrll static void
5329 1.29.2.2 skrll iwm_calib_timeout(void *arg)
5330 1.29.2.2 skrll {
5331 1.29.2.2 skrll struct iwm_softc *sc = arg;
5332 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5333 1.29.2.2 skrll int s;
5334 1.29.2.2 skrll
5335 1.29.2.2 skrll s = splnet();
5336 1.29.2.2 skrll if (ic->ic_fixed_rate == -1
5337 1.29.2.2 skrll && ic->ic_opmode == IEEE80211_M_STA
5338 1.29.2.2 skrll && ic->ic_bss) {
5339 1.29.2.2 skrll struct iwm_node *in = (void *)ic->ic_bss;
5340 1.29.2.2 skrll ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn);
5341 1.29.2.2 skrll }
5342 1.29.2.2 skrll splx(s);
5343 1.29.2.2 skrll
5344 1.29.2.2 skrll callout_schedule(&sc->sc_calib_to, hz/2);
5345 1.29.2.2 skrll }
5346 1.29.2.2 skrll
5347 1.29.2.2 skrll static void
5348 1.29.2.2 skrll iwm_setrates(struct iwm_node *in)
5349 1.29.2.2 skrll {
5350 1.29.2.2 skrll struct ieee80211_node *ni = &in->in_ni;
5351 1.29.2.2 skrll struct ieee80211com *ic = ni->ni_ic;
5352 1.29.2.2 skrll struct iwm_softc *sc = IC2IFP(ic)->if_softc;
5353 1.29.2.2 skrll struct iwm_lq_cmd *lq = &in->in_lq;
5354 1.29.2.2 skrll int nrates = ni->ni_rates.rs_nrates;
5355 1.29.2.2 skrll int i, ridx, tab = 0;
5356 1.29.2.2 skrll int txant = 0;
5357 1.29.2.2 skrll
5358 1.29.2.2 skrll if (nrates > __arraycount(lq->rs_table) ||
5359 1.29.2.2 skrll nrates > IEEE80211_RATE_MAXSIZE) {
5360 1.29.2.2 skrll DPRINTF(("%s: node supports %d rates, driver handles only "
5361 1.29.2.2 skrll "%zu\n", DEVNAME(sc), nrates, __arraycount(lq->rs_table)));
5362 1.29.2.2 skrll return;
5363 1.29.2.2 skrll }
5364 1.29.2.2 skrll
5365 1.29.2.2 skrll /* first figure out which rates we should support */
5366 1.29.2.2 skrll memset(&in->in_ridx, -1, sizeof(in->in_ridx));
5367 1.29.2.2 skrll for (i = 0; i < nrates; i++) {
5368 1.29.2.2 skrll int rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
5369 1.29.2.2 skrll
5370 1.29.2.2 skrll /* Map 802.11 rate to HW rate index. */
5371 1.29.2.2 skrll for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
5372 1.29.2.2 skrll if (iwm_rates[ridx].rate == rate)
5373 1.29.2.2 skrll break;
5374 1.29.2.2 skrll if (ridx > IWM_RIDX_MAX)
5375 1.29.2.2 skrll DPRINTF(("%s: WARNING: device rate for %d not found!\n",
5376 1.29.2.2 skrll DEVNAME(sc), rate));
5377 1.29.2.2 skrll else
5378 1.29.2.2 skrll in->in_ridx[i] = ridx;
5379 1.29.2.2 skrll }
5380 1.29.2.2 skrll
5381 1.29.2.2 skrll /* then construct a lq_cmd based on those */
5382 1.29.2.2 skrll memset(lq, 0, sizeof(*lq));
5383 1.29.2.2 skrll lq->sta_id = IWM_STATION_ID;
5384 1.29.2.2 skrll
5385 1.29.2.2 skrll /*
5386 1.29.2.2 skrll * are these used? (we don't do SISO or MIMO)
5387 1.29.2.2 skrll * need to set them to non-zero, though, or we get an error.
5388 1.29.2.2 skrll */
5389 1.29.2.2 skrll lq->single_stream_ant_msk = 1;
5390 1.29.2.2 skrll lq->dual_stream_ant_msk = 1;
5391 1.29.2.2 skrll
5392 1.29.2.2 skrll /*
5393 1.29.2.2 skrll * Build the actual rate selection table.
5394 1.29.2.2 skrll * The lowest bits are the rates. Additionally,
5395 1.29.2.2 skrll * CCK needs bit 9 to be set. The rest of the bits
5396 1.29.2.2 skrll * we add to the table select the tx antenna
5397 1.29.2.2 skrll * Note that we add the rates in the highest rate first
5398 1.29.2.2 skrll * (opposite of ni_rates).
5399 1.29.2.2 skrll */
5400 1.29.2.2 skrll for (i = 0; i < nrates; i++) {
5401 1.29.2.2 skrll int nextant;
5402 1.29.2.2 skrll
5403 1.29.2.2 skrll if (txant == 0)
5404 1.29.2.2 skrll txant = IWM_FW_VALID_TX_ANT(sc);
5405 1.29.2.2 skrll nextant = 1<<(ffs(txant)-1);
5406 1.29.2.2 skrll txant &= ~nextant;
5407 1.29.2.2 skrll
5408 1.29.2.2 skrll ridx = in->in_ridx[(nrates-1)-i];
5409 1.29.2.2 skrll tab = iwm_rates[ridx].plcp;
5410 1.29.2.2 skrll tab |= nextant << IWM_RATE_MCS_ANT_POS;
5411 1.29.2.2 skrll if (IWM_RIDX_IS_CCK(ridx))
5412 1.29.2.2 skrll tab |= IWM_RATE_MCS_CCK_MSK;
5413 1.29.2.2 skrll DPRINTFN(2, ("station rate %d %x\n", i, tab));
5414 1.29.2.2 skrll lq->rs_table[i] = htole32(tab);
5415 1.29.2.2 skrll }
5416 1.29.2.2 skrll /* then fill the rest with the lowest possible rate */
5417 1.29.2.2 skrll for (i = nrates; i < __arraycount(lq->rs_table); i++) {
5418 1.29.2.2 skrll KASSERT(tab != 0);
5419 1.29.2.2 skrll lq->rs_table[i] = htole32(tab);
5420 1.29.2.2 skrll }
5421 1.29.2.2 skrll
5422 1.29.2.2 skrll /* init amrr */
5423 1.29.2.2 skrll ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
5424 1.29.2.2 skrll /* Start at lowest available bit-rate, AMRR will raise. */
5425 1.29.2.2 skrll ni->ni_txrate = 0;
5426 1.29.2.2 skrll }
5427 1.29.2.2 skrll
5428 1.29.2.2 skrll static int
5429 1.29.2.2 skrll iwm_media_change(struct ifnet *ifp)
5430 1.29.2.2 skrll {
5431 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5432 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5433 1.29.2.2 skrll uint8_t rate, ridx;
5434 1.29.2.2 skrll int error;
5435 1.29.2.2 skrll
5436 1.29.2.2 skrll error = ieee80211_media_change(ifp);
5437 1.29.2.2 skrll if (error != ENETRESET)
5438 1.29.2.2 skrll return error;
5439 1.29.2.2 skrll
5440 1.29.2.2 skrll if (ic->ic_fixed_rate != -1) {
5441 1.29.2.2 skrll rate = ic->ic_sup_rates[ic->ic_curmode].
5442 1.29.2.2 skrll rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
5443 1.29.2.2 skrll /* Map 802.11 rate to HW rate index. */
5444 1.29.2.2 skrll for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
5445 1.29.2.2 skrll if (iwm_rates[ridx].rate == rate)
5446 1.29.2.2 skrll break;
5447 1.29.2.2 skrll sc->sc_fixed_ridx = ridx;
5448 1.29.2.2 skrll }
5449 1.29.2.2 skrll
5450 1.29.2.2 skrll if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
5451 1.29.2.2 skrll (IFF_UP | IFF_RUNNING)) {
5452 1.29.2.2 skrll iwm_stop(ifp, 0);
5453 1.29.2.2 skrll error = iwm_init(ifp);
5454 1.29.2.2 skrll }
5455 1.29.2.2 skrll return error;
5456 1.29.2.2 skrll }
5457 1.29.2.2 skrll
5458 1.29.2.2 skrll static void
5459 1.29.2.2 skrll iwm_newstate_cb(struct work *wk, void *v)
5460 1.29.2.2 skrll {
5461 1.29.2.2 skrll struct iwm_softc *sc = v;
5462 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5463 1.29.2.2 skrll struct iwm_newstate_state *iwmns = (void *)wk;
5464 1.29.2.2 skrll enum ieee80211_state nstate = iwmns->ns_nstate;
5465 1.29.2.2 skrll int generation = iwmns->ns_generation;
5466 1.29.2.2 skrll struct iwm_node *in;
5467 1.29.2.2 skrll int arg = iwmns->ns_arg;
5468 1.29.2.2 skrll int error;
5469 1.29.2.2 skrll
5470 1.29.2.2 skrll kmem_free(iwmns, sizeof(*iwmns));
5471 1.29.2.2 skrll
5472 1.29.2.2 skrll DPRINTF(("Prepare to switch state %d->%d\n", ic->ic_state, nstate));
5473 1.29.2.2 skrll if (sc->sc_generation != generation) {
5474 1.29.2.2 skrll DPRINTF(("newstate_cb: someone pulled the plug meanwhile\n"));
5475 1.29.2.2 skrll if (nstate == IEEE80211_S_INIT) {
5476 1.29.2.2 skrll DPRINTF(("newstate_cb: nstate == IEEE80211_S_INIT: calling sc_newstate()\n"));
5477 1.29.2.2 skrll sc->sc_newstate(ic, nstate, arg);
5478 1.29.2.2 skrll }
5479 1.29.2.2 skrll return;
5480 1.29.2.2 skrll }
5481 1.29.2.2 skrll
5482 1.29.2.2 skrll DPRINTF(("switching state %d->%d\n", ic->ic_state, nstate));
5483 1.29.2.2 skrll
5484 1.29.2.2 skrll /* disable beacon filtering if we're hopping out of RUN */
5485 1.29.2.2 skrll if (ic->ic_state == IEEE80211_S_RUN && nstate != ic->ic_state) {
5486 1.29.2.2 skrll iwm_mvm_disable_beacon_filter(sc, (void *)ic->ic_bss);
5487 1.29.2.2 skrll
5488 1.29.2.2 skrll if (((in = (void *)ic->ic_bss) != NULL))
5489 1.29.2.2 skrll in->in_assoc = 0;
5490 1.29.2.2 skrll iwm_release(sc, NULL);
5491 1.29.2.2 skrll
5492 1.29.2.2 skrll /*
5493 1.29.2.2 skrll * It's impossible to directly go RUN->SCAN. If we iwm_release()
5494 1.29.2.2 skrll * above then the card will be completely reinitialized,
5495 1.29.2.2 skrll * so the driver must do everything necessary to bring the card
5496 1.29.2.2 skrll * from INIT to SCAN.
5497 1.29.2.2 skrll *
5498 1.29.2.2 skrll * Additionally, upon receiving deauth frame from AP,
5499 1.29.2.2 skrll * OpenBSD 802.11 stack puts the driver in IEEE80211_S_AUTH
5500 1.29.2.2 skrll * state. This will also fail with this driver, so bring the FSM
5501 1.29.2.2 skrll * from IEEE80211_S_RUN to IEEE80211_S_SCAN in this case as well.
5502 1.29.2.2 skrll */
5503 1.29.2.2 skrll if (nstate == IEEE80211_S_SCAN ||
5504 1.29.2.2 skrll nstate == IEEE80211_S_AUTH ||
5505 1.29.2.2 skrll nstate == IEEE80211_S_ASSOC) {
5506 1.29.2.2 skrll DPRINTF(("Force transition to INIT; MGT=%d\n", arg));
5507 1.29.2.2 skrll sc->sc_newstate(ic, IEEE80211_S_INIT, arg);
5508 1.29.2.2 skrll DPRINTF(("Going INIT->SCAN\n"));
5509 1.29.2.2 skrll nstate = IEEE80211_S_SCAN;
5510 1.29.2.2 skrll }
5511 1.29.2.2 skrll }
5512 1.29.2.2 skrll
5513 1.29.2.2 skrll switch (nstate) {
5514 1.29.2.2 skrll case IEEE80211_S_INIT:
5515 1.29.2.2 skrll sc->sc_scanband = 0;
5516 1.29.2.2 skrll break;
5517 1.29.2.2 skrll
5518 1.29.2.2 skrll case IEEE80211_S_SCAN:
5519 1.29.2.2 skrll if (sc->sc_scanband)
5520 1.29.2.2 skrll break;
5521 1.29.2.2 skrll
5522 1.29.2.2 skrll if ((error = iwm_mvm_scan_request(sc, IEEE80211_CHAN_2GHZ,
5523 1.29.2.2 skrll ic->ic_des_esslen != 0,
5524 1.29.2.2 skrll ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
5525 1.29.2.2 skrll DPRINTF(("%s: could not initiate scan\n", DEVNAME(sc)));
5526 1.29.2.2 skrll return;
5527 1.29.2.2 skrll }
5528 1.29.2.2 skrll ic->ic_state = nstate;
5529 1.29.2.2 skrll return;
5530 1.29.2.2 skrll
5531 1.29.2.2 skrll case IEEE80211_S_AUTH:
5532 1.29.2.2 skrll if ((error = iwm_auth(sc)) != 0) {
5533 1.29.2.2 skrll DPRINTF(("%s: could not move to auth state: %d\n",
5534 1.29.2.2 skrll DEVNAME(sc), error));
5535 1.29.2.2 skrll return;
5536 1.29.2.2 skrll }
5537 1.29.2.2 skrll
5538 1.29.2.2 skrll break;
5539 1.29.2.2 skrll
5540 1.29.2.2 skrll case IEEE80211_S_ASSOC:
5541 1.29.2.2 skrll if ((error = iwm_assoc(sc)) != 0) {
5542 1.29.2.2 skrll DPRINTF(("%s: failed to associate: %d\n", DEVNAME(sc),
5543 1.29.2.2 skrll error));
5544 1.29.2.2 skrll return;
5545 1.29.2.2 skrll }
5546 1.29.2.2 skrll break;
5547 1.29.2.2 skrll
5548 1.29.2.2 skrll case IEEE80211_S_RUN: {
5549 1.29.2.2 skrll struct iwm_host_cmd cmd = {
5550 1.29.2.2 skrll .id = IWM_LQ_CMD,
5551 1.29.2.2 skrll .len = { sizeof(in->in_lq), },
5552 1.29.2.2 skrll .flags = IWM_CMD_SYNC,
5553 1.29.2.2 skrll };
5554 1.29.2.2 skrll
5555 1.29.2.2 skrll in = (struct iwm_node *)ic->ic_bss;
5556 1.29.2.2 skrll iwm_mvm_power_mac_update_mode(sc, in);
5557 1.29.2.2 skrll iwm_mvm_enable_beacon_filter(sc, in);
5558 1.29.2.2 skrll iwm_mvm_update_quotas(sc, in);
5559 1.29.2.2 skrll iwm_setrates(in);
5560 1.29.2.2 skrll
5561 1.29.2.2 skrll cmd.data[0] = &in->in_lq;
5562 1.29.2.2 skrll if ((error = iwm_send_cmd(sc, &cmd)) != 0) {
5563 1.29.2.2 skrll DPRINTF(("%s: IWM_LQ_CMD failed\n", DEVNAME(sc)));
5564 1.29.2.2 skrll }
5565 1.29.2.2 skrll
5566 1.29.2.2 skrll callout_schedule(&sc->sc_calib_to, hz/2);
5567 1.29.2.2 skrll
5568 1.29.2.2 skrll break; }
5569 1.29.2.2 skrll
5570 1.29.2.2 skrll default:
5571 1.29.2.2 skrll DPRINTF(("%s: unsupported state %d\n", DEVNAME(sc), nstate));
5572 1.29.2.2 skrll break;
5573 1.29.2.2 skrll }
5574 1.29.2.2 skrll
5575 1.29.2.2 skrll sc->sc_newstate(ic, nstate, arg);
5576 1.29.2.2 skrll }
5577 1.29.2.2 skrll
5578 1.29.2.2 skrll static int
5579 1.29.2.2 skrll iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
5580 1.29.2.2 skrll {
5581 1.29.2.2 skrll struct iwm_newstate_state *iwmns;
5582 1.29.2.2 skrll struct ifnet *ifp = IC2IFP(ic);
5583 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5584 1.29.2.2 skrll
5585 1.29.2.2 skrll callout_stop(&sc->sc_calib_to);
5586 1.29.2.2 skrll
5587 1.29.2.2 skrll iwmns = kmem_intr_alloc(sizeof(*iwmns), KM_NOSLEEP);
5588 1.29.2.2 skrll if (!iwmns) {
5589 1.29.2.2 skrll DPRINTF(("%s: allocating state cb mem failed\n", DEVNAME(sc)));
5590 1.29.2.2 skrll return ENOMEM;
5591 1.29.2.2 skrll }
5592 1.29.2.2 skrll
5593 1.29.2.2 skrll iwmns->ns_nstate = nstate;
5594 1.29.2.2 skrll iwmns->ns_arg = arg;
5595 1.29.2.2 skrll iwmns->ns_generation = sc->sc_generation;
5596 1.29.2.2 skrll
5597 1.29.2.2 skrll workqueue_enqueue(sc->sc_nswq, &iwmns->ns_wk, NULL);
5598 1.29.2.2 skrll
5599 1.29.2.2 skrll return 0;
5600 1.29.2.2 skrll }
5601 1.29.2.2 skrll
5602 1.29.2.2 skrll static void
5603 1.29.2.2 skrll iwm_endscan_cb(struct work *work __unused, void *arg)
5604 1.29.2.2 skrll {
5605 1.29.2.2 skrll struct iwm_softc *sc = arg;
5606 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5607 1.29.2.2 skrll int done;
5608 1.29.2.2 skrll
5609 1.29.2.2 skrll DPRINTF(("scan ended\n"));
5610 1.29.2.2 skrll
5611 1.29.2.2 skrll if (sc->sc_scanband == IEEE80211_CHAN_2GHZ &&
5612 1.29.2.2 skrll sc->sc_nvm.sku_cap_band_52GHz_enable) {
5613 1.29.2.2 skrll int error;
5614 1.29.2.2 skrll done = 0;
5615 1.29.2.2 skrll if ((error = iwm_mvm_scan_request(sc,
5616 1.29.2.2 skrll IEEE80211_CHAN_5GHZ, ic->ic_des_esslen != 0,
5617 1.29.2.2 skrll ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
5618 1.29.2.2 skrll DPRINTF(("%s: could not initiate scan\n", DEVNAME(sc)));
5619 1.29.2.2 skrll done = 1;
5620 1.29.2.2 skrll }
5621 1.29.2.2 skrll } else {
5622 1.29.2.2 skrll done = 1;
5623 1.29.2.2 skrll }
5624 1.29.2.2 skrll
5625 1.29.2.2 skrll if (done) {
5626 1.29.2.2 skrll if (!sc->sc_scanband) {
5627 1.29.2.2 skrll ieee80211_cancel_scan(ic);
5628 1.29.2.2 skrll } else {
5629 1.29.2.2 skrll ieee80211_end_scan(ic);
5630 1.29.2.2 skrll }
5631 1.29.2.2 skrll sc->sc_scanband = 0;
5632 1.29.2.2 skrll }
5633 1.29.2.2 skrll }
5634 1.29.2.2 skrll
5635 1.29.2.2 skrll static int
5636 1.29.2.2 skrll iwm_init_hw(struct iwm_softc *sc)
5637 1.29.2.2 skrll {
5638 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5639 1.29.2.2 skrll int error, i, qid;
5640 1.29.2.2 skrll
5641 1.29.2.2 skrll if ((error = iwm_preinit(sc)) != 0)
5642 1.29.2.2 skrll return error;
5643 1.29.2.2 skrll
5644 1.29.2.2 skrll if ((error = iwm_start_hw(sc)) != 0)
5645 1.29.2.2 skrll return error;
5646 1.29.2.2 skrll
5647 1.29.2.2 skrll if ((error = iwm_run_init_mvm_ucode(sc, 0)) != 0) {
5648 1.29.2.2 skrll return error;
5649 1.29.2.2 skrll }
5650 1.29.2.2 skrll
5651 1.29.2.2 skrll /*
5652 1.29.2.2 skrll * should stop and start HW since that INIT
5653 1.29.2.2 skrll * image just loaded
5654 1.29.2.2 skrll */
5655 1.29.2.2 skrll iwm_stop_device(sc);
5656 1.29.2.2 skrll if ((error = iwm_start_hw(sc)) != 0) {
5657 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
5658 1.29.2.2 skrll return error;
5659 1.29.2.2 skrll }
5660 1.29.2.2 skrll
5661 1.29.2.2 skrll /* omstart, this time with the regular firmware */
5662 1.29.2.2 skrll error = iwm_mvm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR);
5663 1.29.2.2 skrll if (error) {
5664 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not load firmware\n");
5665 1.29.2.2 skrll goto error;
5666 1.29.2.2 skrll }
5667 1.29.2.2 skrll
5668 1.29.2.2 skrll if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
5669 1.29.2.2 skrll goto error;
5670 1.29.2.2 skrll
5671 1.29.2.2 skrll /* Send phy db control command and then phy db calibration*/
5672 1.29.2.2 skrll if ((error = iwm_send_phy_db_data(sc)) != 0)
5673 1.29.2.2 skrll goto error;
5674 1.29.2.2 skrll
5675 1.29.2.2 skrll if ((error = iwm_send_phy_cfg_cmd(sc)) != 0)
5676 1.29.2.2 skrll goto error;
5677 1.29.2.2 skrll
5678 1.29.2.2 skrll /* Add auxiliary station for scanning */
5679 1.29.2.2 skrll if ((error = iwm_mvm_add_aux_sta(sc)) != 0)
5680 1.29.2.2 skrll goto error;
5681 1.29.2.2 skrll
5682 1.29.2.2 skrll for (i = 0; i < IWM_NUM_PHY_CTX; i++) {
5683 1.29.2.2 skrll /*
5684 1.29.2.2 skrll * The channel used here isn't relevant as it's
5685 1.29.2.2 skrll * going to be overwritten in the other flows.
5686 1.29.2.2 skrll * For now use the first channel we have.
5687 1.29.2.2 skrll */
5688 1.29.2.2 skrll if ((error = iwm_mvm_phy_ctxt_add(sc,
5689 1.29.2.2 skrll &sc->sc_phyctxt[i], &ic->ic_channels[1], 1, 1)) != 0)
5690 1.29.2.2 skrll goto error;
5691 1.29.2.2 skrll }
5692 1.29.2.2 skrll
5693 1.29.2.2 skrll error = iwm_mvm_power_update_device(sc);
5694 1.29.2.2 skrll if (error)
5695 1.29.2.2 skrll goto error;
5696 1.29.2.2 skrll
5697 1.29.2.2 skrll /* Mark TX rings as active. */
5698 1.29.2.2 skrll for (qid = 0; qid < 4; qid++) {
5699 1.29.2.2 skrll iwm_enable_txq(sc, qid, qid);
5700 1.29.2.2 skrll }
5701 1.29.2.2 skrll
5702 1.29.2.2 skrll return 0;
5703 1.29.2.2 skrll
5704 1.29.2.2 skrll error:
5705 1.29.2.2 skrll iwm_stop_device(sc);
5706 1.29.2.2 skrll return error;
5707 1.29.2.2 skrll }
5708 1.29.2.2 skrll
5709 1.29.2.2 skrll /* Allow multicast from our BSSID. */
5710 1.29.2.2 skrll static int
5711 1.29.2.2 skrll iwm_allow_mcast(struct iwm_softc *sc)
5712 1.29.2.2 skrll {
5713 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5714 1.29.2.2 skrll struct ieee80211_node *ni = ic->ic_bss;
5715 1.29.2.2 skrll struct iwm_mcast_filter_cmd *cmd;
5716 1.29.2.2 skrll size_t size;
5717 1.29.2.2 skrll int error;
5718 1.29.2.2 skrll
5719 1.29.2.2 skrll size = roundup(sizeof(*cmd), 4);
5720 1.29.2.2 skrll cmd = kmem_intr_zalloc(size, KM_NOSLEEP);
5721 1.29.2.2 skrll if (cmd == NULL)
5722 1.29.2.2 skrll return ENOMEM;
5723 1.29.2.2 skrll cmd->filter_own = 1;
5724 1.29.2.2 skrll cmd->port_id = 0;
5725 1.29.2.2 skrll cmd->count = 0;
5726 1.29.2.2 skrll cmd->pass_all = 1;
5727 1.29.2.2 skrll IEEE80211_ADDR_COPY(cmd->bssid, ni->ni_bssid);
5728 1.29.2.2 skrll
5729 1.29.2.2 skrll error = iwm_mvm_send_cmd_pdu(sc, IWM_MCAST_FILTER_CMD,
5730 1.29.2.2 skrll IWM_CMD_SYNC, size, cmd);
5731 1.29.2.2 skrll kmem_intr_free(cmd, size);
5732 1.29.2.2 skrll return error;
5733 1.29.2.2 skrll }
5734 1.29.2.2 skrll
5735 1.29.2.2 skrll /*
5736 1.29.2.2 skrll * ifnet interfaces
5737 1.29.2.2 skrll */
5738 1.29.2.2 skrll
5739 1.29.2.2 skrll static int
5740 1.29.2.2 skrll iwm_init(struct ifnet *ifp)
5741 1.29.2.2 skrll {
5742 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5743 1.29.2.2 skrll int error;
5744 1.29.2.2 skrll
5745 1.29.2.2 skrll if (sc->sc_flags & IWM_FLAG_HW_INITED) {
5746 1.29.2.2 skrll return 0;
5747 1.29.2.2 skrll }
5748 1.29.2.2 skrll sc->sc_generation++;
5749 1.29.2.2 skrll sc->sc_flags &= ~IWM_FLAG_STOPPED;
5750 1.29.2.2 skrll
5751 1.29.2.2 skrll if ((error = iwm_init_hw(sc)) != 0) {
5752 1.29.2.2 skrll iwm_stop(ifp, 1);
5753 1.29.2.2 skrll return error;
5754 1.29.2.2 skrll }
5755 1.29.2.2 skrll
5756 1.29.2.2 skrll /*
5757 1.29.2.2 skrll * Ok, firmware loaded and we are jogging
5758 1.29.2.2 skrll */
5759 1.29.2.2 skrll
5760 1.29.2.2 skrll ifp->if_flags &= ~IFF_OACTIVE;
5761 1.29.2.2 skrll ifp->if_flags |= IFF_RUNNING;
5762 1.29.2.2 skrll
5763 1.29.2.2 skrll ieee80211_begin_scan(&sc->sc_ic, 0);
5764 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_HW_INITED;
5765 1.29.2.2 skrll
5766 1.29.2.2 skrll return 0;
5767 1.29.2.2 skrll }
5768 1.29.2.2 skrll
5769 1.29.2.2 skrll /*
5770 1.29.2.2 skrll * Dequeue packets from sendq and call send.
5771 1.29.2.2 skrll * mostly from iwn
5772 1.29.2.2 skrll */
5773 1.29.2.2 skrll static void
5774 1.29.2.2 skrll iwm_start(struct ifnet *ifp)
5775 1.29.2.2 skrll {
5776 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5777 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5778 1.29.2.2 skrll struct ieee80211_node *ni;
5779 1.29.2.2 skrll struct ether_header *eh;
5780 1.29.2.2 skrll struct mbuf *m;
5781 1.29.2.2 skrll int ac;
5782 1.29.2.2 skrll
5783 1.29.2.2 skrll if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
5784 1.29.2.2 skrll return;
5785 1.29.2.2 skrll
5786 1.29.2.2 skrll for (;;) {
5787 1.29.2.2 skrll /* why isn't this done per-queue? */
5788 1.29.2.2 skrll if (sc->qfullmsk != 0) {
5789 1.29.2.2 skrll ifp->if_flags |= IFF_OACTIVE;
5790 1.29.2.2 skrll break;
5791 1.29.2.2 skrll }
5792 1.29.2.2 skrll
5793 1.29.2.2 skrll /* need to send management frames even if we're not RUNning */
5794 1.29.2.2 skrll IF_DEQUEUE(&ic->ic_mgtq, m);
5795 1.29.2.2 skrll if (m) {
5796 1.29.2.2 skrll ni = (void *)m->m_pkthdr.rcvif;
5797 1.29.2.2 skrll ac = 0;
5798 1.29.2.2 skrll goto sendit;
5799 1.29.2.2 skrll }
5800 1.29.2.2 skrll if (ic->ic_state != IEEE80211_S_RUN) {
5801 1.29.2.2 skrll break;
5802 1.29.2.2 skrll }
5803 1.29.2.2 skrll
5804 1.29.2.2 skrll IFQ_DEQUEUE(&ifp->if_snd, m);
5805 1.29.2.2 skrll if (!m)
5806 1.29.2.2 skrll break;
5807 1.29.2.2 skrll if (m->m_len < sizeof (*eh) &&
5808 1.29.2.2 skrll (m = m_pullup(m, sizeof (*eh))) == NULL) {
5809 1.29.2.2 skrll ifp->if_oerrors++;
5810 1.29.2.2 skrll continue;
5811 1.29.2.2 skrll }
5812 1.29.2.2 skrll if (ifp->if_bpf != NULL)
5813 1.29.2.2 skrll bpf_mtap(ifp, m);
5814 1.29.2.2 skrll
5815 1.29.2.2 skrll eh = mtod(m, struct ether_header *);
5816 1.29.2.2 skrll ni = ieee80211_find_txnode(ic, eh->ether_dhost);
5817 1.29.2.2 skrll if (ni == NULL) {
5818 1.29.2.2 skrll m_freem(m);
5819 1.29.2.2 skrll ifp->if_oerrors++;
5820 1.29.2.2 skrll continue;
5821 1.29.2.2 skrll }
5822 1.29.2.2 skrll /* classify mbuf so we can find which tx ring to use */
5823 1.29.2.2 skrll if (ieee80211_classify(ic, m, ni) != 0) {
5824 1.29.2.2 skrll m_freem(m);
5825 1.29.2.2 skrll ieee80211_free_node(ni);
5826 1.29.2.2 skrll ifp->if_oerrors++;
5827 1.29.2.2 skrll continue;
5828 1.29.2.2 skrll }
5829 1.29.2.2 skrll
5830 1.29.2.2 skrll /* No QoS encapsulation for EAPOL frames. */
5831 1.29.2.2 skrll ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ?
5832 1.29.2.2 skrll M_WME_GETAC(m) : WME_AC_BE;
5833 1.29.2.2 skrll
5834 1.29.2.2 skrll if ((m = ieee80211_encap(ic, m, ni)) == NULL) {
5835 1.29.2.2 skrll ieee80211_free_node(ni);
5836 1.29.2.2 skrll ifp->if_oerrors++;
5837 1.29.2.2 skrll continue;
5838 1.29.2.2 skrll }
5839 1.29.2.2 skrll
5840 1.29.2.2 skrll sendit:
5841 1.29.2.2 skrll if (ic->ic_rawbpf != NULL)
5842 1.29.2.2 skrll bpf_mtap3(ic->ic_rawbpf, m);
5843 1.29.2.2 skrll if (iwm_tx(sc, m, ni, ac) != 0) {
5844 1.29.2.2 skrll ieee80211_free_node(ni);
5845 1.29.2.2 skrll ifp->if_oerrors++;
5846 1.29.2.2 skrll continue;
5847 1.29.2.2 skrll }
5848 1.29.2.2 skrll
5849 1.29.2.2 skrll if (ifp->if_flags & IFF_UP) {
5850 1.29.2.2 skrll sc->sc_tx_timer = 15;
5851 1.29.2.2 skrll ifp->if_timer = 1;
5852 1.29.2.2 skrll }
5853 1.29.2.2 skrll }
5854 1.29.2.2 skrll
5855 1.29.2.2 skrll return;
5856 1.29.2.2 skrll }
5857 1.29.2.2 skrll
5858 1.29.2.2 skrll static void
5859 1.29.2.2 skrll iwm_stop(struct ifnet *ifp, int disable)
5860 1.29.2.2 skrll {
5861 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5862 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5863 1.29.2.2 skrll
5864 1.29.2.2 skrll sc->sc_flags &= ~IWM_FLAG_HW_INITED;
5865 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_STOPPED;
5866 1.29.2.2 skrll sc->sc_generation++;
5867 1.29.2.2 skrll sc->sc_scanband = 0;
5868 1.29.2.2 skrll sc->sc_auth_prot = 0;
5869 1.29.2.2 skrll ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
5870 1.29.2.2 skrll
5871 1.29.2.2 skrll if (ic->ic_state != IEEE80211_S_INIT)
5872 1.29.2.2 skrll ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
5873 1.29.2.2 skrll
5874 1.29.2.2 skrll callout_stop(&sc->sc_calib_to);
5875 1.29.2.2 skrll ifp->if_timer = sc->sc_tx_timer = 0;
5876 1.29.2.2 skrll iwm_stop_device(sc);
5877 1.29.2.2 skrll }
5878 1.29.2.2 skrll
5879 1.29.2.2 skrll static void
5880 1.29.2.2 skrll iwm_watchdog(struct ifnet *ifp)
5881 1.29.2.2 skrll {
5882 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5883 1.29.2.2 skrll
5884 1.29.2.2 skrll ifp->if_timer = 0;
5885 1.29.2.2 skrll if (sc->sc_tx_timer > 0) {
5886 1.29.2.2 skrll if (--sc->sc_tx_timer == 0) {
5887 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "device timeout\n");
5888 1.29.2.2 skrll #ifdef IWM_DEBUG
5889 1.29.2.2 skrll iwm_nic_error(sc);
5890 1.29.2.2 skrll #endif
5891 1.29.2.2 skrll ifp->if_flags &= ~IFF_UP;
5892 1.29.2.2 skrll iwm_stop(ifp, 1);
5893 1.29.2.2 skrll ifp->if_oerrors++;
5894 1.29.2.2 skrll return;
5895 1.29.2.2 skrll }
5896 1.29.2.2 skrll ifp->if_timer = 1;
5897 1.29.2.2 skrll }
5898 1.29.2.2 skrll
5899 1.29.2.2 skrll ieee80211_watchdog(&sc->sc_ic);
5900 1.29.2.2 skrll }
5901 1.29.2.2 skrll
5902 1.29.2.2 skrll static int
5903 1.29.2.2 skrll iwm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
5904 1.29.2.2 skrll {
5905 1.29.2.2 skrll struct iwm_softc *sc = ifp->if_softc;
5906 1.29.2.2 skrll struct ieee80211com *ic = &sc->sc_ic;
5907 1.29.2.2 skrll const struct sockaddr *sa;
5908 1.29.2.2 skrll int s, error = 0;
5909 1.29.2.2 skrll
5910 1.29.2.2 skrll s = splnet();
5911 1.29.2.2 skrll
5912 1.29.2.2 skrll switch (cmd) {
5913 1.29.2.2 skrll case SIOCSIFADDR:
5914 1.29.2.2 skrll ifp->if_flags |= IFF_UP;
5915 1.29.2.2 skrll /* FALLTHROUGH */
5916 1.29.2.2 skrll case SIOCSIFFLAGS:
5917 1.29.2.2 skrll if ((error = ifioctl_common(ifp, cmd, data)) != 0)
5918 1.29.2.2 skrll break;
5919 1.29.2.2 skrll if (ifp->if_flags & IFF_UP) {
5920 1.29.2.2 skrll if (!(ifp->if_flags & IFF_RUNNING)) {
5921 1.29.2.2 skrll if ((error = iwm_init(ifp)) != 0)
5922 1.29.2.2 skrll ifp->if_flags &= ~IFF_UP;
5923 1.29.2.2 skrll }
5924 1.29.2.2 skrll } else {
5925 1.29.2.2 skrll if (ifp->if_flags & IFF_RUNNING)
5926 1.29.2.2 skrll iwm_stop(ifp, 1);
5927 1.29.2.2 skrll }
5928 1.29.2.2 skrll break;
5929 1.29.2.2 skrll
5930 1.29.2.2 skrll case SIOCADDMULTI:
5931 1.29.2.2 skrll case SIOCDELMULTI:
5932 1.29.2.4 skrll if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
5933 1.29.2.4 skrll error = ENXIO;
5934 1.29.2.4 skrll break;
5935 1.29.2.4 skrll }
5936 1.29.2.2 skrll sa = ifreq_getaddr(SIOCADDMULTI, (struct ifreq *)data);
5937 1.29.2.2 skrll error = (cmd == SIOCADDMULTI) ?
5938 1.29.2.2 skrll ether_addmulti(sa, &sc->sc_ec) :
5939 1.29.2.2 skrll ether_delmulti(sa, &sc->sc_ec);
5940 1.29.2.2 skrll if (error == ENETRESET)
5941 1.29.2.2 skrll error = 0;
5942 1.29.2.2 skrll break;
5943 1.29.2.2 skrll
5944 1.29.2.2 skrll default:
5945 1.29.2.4 skrll if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
5946 1.29.2.4 skrll error = ether_ioctl(ifp, cmd, data);
5947 1.29.2.4 skrll break;
5948 1.29.2.4 skrll }
5949 1.29.2.2 skrll error = ieee80211_ioctl(ic, cmd, data);
5950 1.29.2.4 skrll break;
5951 1.29.2.2 skrll }
5952 1.29.2.2 skrll
5953 1.29.2.2 skrll if (error == ENETRESET) {
5954 1.29.2.2 skrll error = 0;
5955 1.29.2.2 skrll if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
5956 1.29.2.2 skrll (IFF_UP | IFF_RUNNING)) {
5957 1.29.2.2 skrll iwm_stop(ifp, 0);
5958 1.29.2.2 skrll error = iwm_init(ifp);
5959 1.29.2.2 skrll }
5960 1.29.2.2 skrll }
5961 1.29.2.2 skrll
5962 1.29.2.2 skrll splx(s);
5963 1.29.2.2 skrll return error;
5964 1.29.2.2 skrll }
5965 1.29.2.2 skrll
5966 1.29.2.2 skrll /*
5967 1.29.2.2 skrll * The interrupt side of things
5968 1.29.2.2 skrll */
5969 1.29.2.2 skrll
5970 1.29.2.2 skrll /*
5971 1.29.2.2 skrll * error dumping routines are from iwlwifi/mvm/utils.c
5972 1.29.2.2 skrll */
5973 1.29.2.2 skrll
5974 1.29.2.2 skrll /*
5975 1.29.2.2 skrll * Note: This structure is read from the device with IO accesses,
5976 1.29.2.2 skrll * and the reading already does the endian conversion. As it is
5977 1.29.2.2 skrll * read with uint32_t-sized accesses, any members with a different size
5978 1.29.2.2 skrll * need to be ordered correctly though!
5979 1.29.2.2 skrll */
5980 1.29.2.2 skrll struct iwm_error_event_table {
5981 1.29.2.2 skrll uint32_t valid; /* (nonzero) valid, (0) log is empty */
5982 1.29.2.2 skrll uint32_t error_id; /* type of error */
5983 1.29.2.2 skrll uint32_t pc; /* program counter */
5984 1.29.2.2 skrll uint32_t blink1; /* branch link */
5985 1.29.2.2 skrll uint32_t blink2; /* branch link */
5986 1.29.2.2 skrll uint32_t ilink1; /* interrupt link */
5987 1.29.2.2 skrll uint32_t ilink2; /* interrupt link */
5988 1.29.2.2 skrll uint32_t data1; /* error-specific data */
5989 1.29.2.2 skrll uint32_t data2; /* error-specific data */
5990 1.29.2.2 skrll uint32_t data3; /* error-specific data */
5991 1.29.2.2 skrll uint32_t bcon_time; /* beacon timer */
5992 1.29.2.2 skrll uint32_t tsf_low; /* network timestamp function timer */
5993 1.29.2.2 skrll uint32_t tsf_hi; /* network timestamp function timer */
5994 1.29.2.2 skrll uint32_t gp1; /* GP1 timer register */
5995 1.29.2.2 skrll uint32_t gp2; /* GP2 timer register */
5996 1.29.2.2 skrll uint32_t gp3; /* GP3 timer register */
5997 1.29.2.2 skrll uint32_t ucode_ver; /* uCode version */
5998 1.29.2.2 skrll uint32_t hw_ver; /* HW Silicon version */
5999 1.29.2.2 skrll uint32_t brd_ver; /* HW board version */
6000 1.29.2.2 skrll uint32_t log_pc; /* log program counter */
6001 1.29.2.2 skrll uint32_t frame_ptr; /* frame pointer */
6002 1.29.2.2 skrll uint32_t stack_ptr; /* stack pointer */
6003 1.29.2.2 skrll uint32_t hcmd; /* last host command header */
6004 1.29.2.2 skrll uint32_t isr0; /* isr status register LMPM_NIC_ISR0:
6005 1.29.2.2 skrll * rxtx_flag */
6006 1.29.2.2 skrll uint32_t isr1; /* isr status register LMPM_NIC_ISR1:
6007 1.29.2.2 skrll * host_flag */
6008 1.29.2.2 skrll uint32_t isr2; /* isr status register LMPM_NIC_ISR2:
6009 1.29.2.2 skrll * enc_flag */
6010 1.29.2.2 skrll uint32_t isr3; /* isr status register LMPM_NIC_ISR3:
6011 1.29.2.2 skrll * time_flag */
6012 1.29.2.2 skrll uint32_t isr4; /* isr status register LMPM_NIC_ISR4:
6013 1.29.2.2 skrll * wico interrupt */
6014 1.29.2.2 skrll uint32_t isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
6015 1.29.2.2 skrll uint32_t wait_event; /* wait event() caller address */
6016 1.29.2.2 skrll uint32_t l2p_control; /* L2pControlField */
6017 1.29.2.2 skrll uint32_t l2p_duration; /* L2pDurationField */
6018 1.29.2.2 skrll uint32_t l2p_mhvalid; /* L2pMhValidBits */
6019 1.29.2.2 skrll uint32_t l2p_addr_match; /* L2pAddrMatchStat */
6020 1.29.2.2 skrll uint32_t lmpm_pmg_sel; /* indicate which clocks are turned on
6021 1.29.2.2 skrll * (LMPM_PMG_SEL) */
6022 1.29.2.2 skrll uint32_t u_timestamp; /* indicate when the date and time of the
6023 1.29.2.2 skrll * compilation */
6024 1.29.2.2 skrll uint32_t flow_handler; /* FH read/write pointers, RX credit */
6025 1.29.2.2 skrll } __packed;
6026 1.29.2.2 skrll
6027 1.29.2.2 skrll #define ERROR_START_OFFSET (1 * sizeof(uint32_t))
6028 1.29.2.2 skrll #define ERROR_ELEM_SIZE (7 * sizeof(uint32_t))
6029 1.29.2.2 skrll
6030 1.29.2.2 skrll #ifdef IWM_DEBUG
6031 1.29.2.2 skrll static const struct {
6032 1.29.2.2 skrll const char *name;
6033 1.29.2.2 skrll uint8_t num;
6034 1.29.2.2 skrll } advanced_lookup[] = {
6035 1.29.2.2 skrll { "NMI_INTERRUPT_WDG", 0x34 },
6036 1.29.2.2 skrll { "SYSASSERT", 0x35 },
6037 1.29.2.2 skrll { "UCODE_VERSION_MISMATCH", 0x37 },
6038 1.29.2.2 skrll { "BAD_COMMAND", 0x38 },
6039 1.29.2.2 skrll { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
6040 1.29.2.2 skrll { "FATAL_ERROR", 0x3D },
6041 1.29.2.2 skrll { "NMI_TRM_HW_ERR", 0x46 },
6042 1.29.2.2 skrll { "NMI_INTERRUPT_TRM", 0x4C },
6043 1.29.2.2 skrll { "NMI_INTERRUPT_BREAK_POINT", 0x54 },
6044 1.29.2.2 skrll { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
6045 1.29.2.2 skrll { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
6046 1.29.2.2 skrll { "NMI_INTERRUPT_HOST", 0x66 },
6047 1.29.2.2 skrll { "NMI_INTERRUPT_ACTION_PT", 0x7C },
6048 1.29.2.2 skrll { "NMI_INTERRUPT_UNKNOWN", 0x84 },
6049 1.29.2.2 skrll { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
6050 1.29.2.2 skrll { "ADVANCED_SYSASSERT", 0 },
6051 1.29.2.2 skrll };
6052 1.29.2.2 skrll
6053 1.29.2.2 skrll static const char *
6054 1.29.2.2 skrll iwm_desc_lookup(uint32_t num)
6055 1.29.2.2 skrll {
6056 1.29.2.2 skrll int i;
6057 1.29.2.2 skrll
6058 1.29.2.2 skrll for (i = 0; i < __arraycount(advanced_lookup) - 1; i++)
6059 1.29.2.2 skrll if (advanced_lookup[i].num == num)
6060 1.29.2.2 skrll return advanced_lookup[i].name;
6061 1.29.2.2 skrll
6062 1.29.2.2 skrll /* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */
6063 1.29.2.2 skrll return advanced_lookup[i].name;
6064 1.29.2.2 skrll }
6065 1.29.2.2 skrll
6066 1.29.2.2 skrll /*
6067 1.29.2.2 skrll * Support for dumping the error log seemed like a good idea ...
6068 1.29.2.2 skrll * but it's mostly hex junk and the only sensible thing is the
6069 1.29.2.2 skrll * hw/ucode revision (which we know anyway). Since it's here,
6070 1.29.2.2 skrll * I'll just leave it in, just in case e.g. the Intel guys want to
6071 1.29.2.2 skrll * help us decipher some "ADVANCED_SYSASSERT" later.
6072 1.29.2.2 skrll */
6073 1.29.2.2 skrll static void
6074 1.29.2.2 skrll iwm_nic_error(struct iwm_softc *sc)
6075 1.29.2.2 skrll {
6076 1.29.2.2 skrll struct iwm_error_event_table table;
6077 1.29.2.2 skrll uint32_t base;
6078 1.29.2.2 skrll
6079 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "dumping device error log\n");
6080 1.29.2.2 skrll base = sc->sc_uc.uc_error_event_table;
6081 1.29.2.2 skrll if (base < 0x800000 || base >= 0x80C000) {
6082 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6083 1.29.2.2 skrll "Not valid error log pointer 0x%08x\n", base);
6084 1.29.2.2 skrll return;
6085 1.29.2.2 skrll }
6086 1.29.2.2 skrll
6087 1.29.2.2 skrll if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t)) != 0) {
6088 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "reading errlog failed\n");
6089 1.29.2.2 skrll return;
6090 1.29.2.2 skrll }
6091 1.29.2.2 skrll
6092 1.29.2.2 skrll if (!table.valid) {
6093 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "errlog not found, skipping\n");
6094 1.29.2.2 skrll return;
6095 1.29.2.2 skrll }
6096 1.29.2.2 skrll
6097 1.29.2.2 skrll if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
6098 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "Start IWL Error Log Dump:\n");
6099 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "Status: 0x%x, count: %d\n",
6100 1.29.2.2 skrll sc->sc_flags, table.valid);
6101 1.29.2.2 skrll }
6102 1.29.2.2 skrll
6103 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | %-28s\n", table.error_id,
6104 1.29.2.2 skrll iwm_desc_lookup(table.error_id));
6105 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | uPc\n", table.pc);
6106 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | branchlink1\n", table.blink1);
6107 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | branchlink2\n", table.blink2);
6108 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | interruptlink1\n", table.ilink1);
6109 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | interruptlink2\n", table.ilink2);
6110 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | data1\n", table.data1);
6111 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | data2\n", table.data2);
6112 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | data3\n", table.data3);
6113 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | beacon time\n", table.bcon_time);
6114 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | tsf low\n", table.tsf_low);
6115 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | tsf hi\n", table.tsf_hi);
6116 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | time gp1\n", table.gp1);
6117 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | time gp2\n", table.gp2);
6118 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | time gp3\n", table.gp3);
6119 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | uCode version\n", table.ucode_ver);
6120 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | hw version\n", table.hw_ver);
6121 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | board version\n", table.brd_ver);
6122 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | hcmd\n", table.hcmd);
6123 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr0\n", table.isr0);
6124 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr1\n", table.isr1);
6125 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr2\n", table.isr2);
6126 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr3\n", table.isr3);
6127 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr4\n", table.isr4);
6128 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | isr_pref\n", table.isr_pref);
6129 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | wait_event\n", table.wait_event);
6130 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | l2p_control\n", table.l2p_control);
6131 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | l2p_duration\n",
6132 1.29.2.2 skrll table.l2p_duration);
6133 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | l2p_mhvalid\n", table.l2p_mhvalid);
6134 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | l2p_addr_match\n",
6135 1.29.2.2 skrll table.l2p_addr_match);
6136 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | lmpm_pmg_sel\n",
6137 1.29.2.2 skrll table.lmpm_pmg_sel);
6138 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | timestamp\n", table.u_timestamp);
6139 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "%08X | flow_handler\n",
6140 1.29.2.2 skrll table.flow_handler);
6141 1.29.2.2 skrll }
6142 1.29.2.2 skrll #endif
6143 1.29.2.2 skrll
6144 1.29.2.2 skrll #define SYNC_RESP_STRUCT(_var_, _pkt_) \
6145 1.29.2.2 skrll do { \
6146 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \
6147 1.29.2.2 skrll sizeof(*(_var_)), BUS_DMASYNC_POSTREAD); \
6148 1.29.2.2 skrll _var_ = (void *)((_pkt_)+1); \
6149 1.29.2.2 skrll } while (/*CONSTCOND*/0)
6150 1.29.2.2 skrll
6151 1.29.2.2 skrll #define SYNC_RESP_PTR(_ptr_, _len_, _pkt_) \
6152 1.29.2.2 skrll do { \
6153 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)), \
6154 1.29.2.2 skrll sizeof(len), BUS_DMASYNC_POSTREAD); \
6155 1.29.2.2 skrll _ptr_ = (void *)((_pkt_)+1); \
6156 1.29.2.2 skrll } while (/*CONSTCOND*/0)
6157 1.29.2.2 skrll
6158 1.29.2.2 skrll #define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % IWM_RX_RING_COUNT);
6159 1.29.2.2 skrll
6160 1.29.2.2 skrll /*
6161 1.29.2.2 skrll * Process an IWM_CSR_INT_BIT_FH_RX or IWM_CSR_INT_BIT_SW_RX interrupt.
6162 1.29.2.2 skrll * Basic structure from if_iwn
6163 1.29.2.2 skrll */
6164 1.29.2.2 skrll static void
6165 1.29.2.2 skrll iwm_notif_intr(struct iwm_softc *sc)
6166 1.29.2.2 skrll {
6167 1.29.2.2 skrll uint16_t hw;
6168 1.29.2.2 skrll
6169 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
6170 1.29.2.2 skrll 0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
6171 1.29.2.2 skrll
6172 1.29.2.2 skrll hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
6173 1.29.2.2 skrll while (sc->rxq.cur != hw) {
6174 1.29.2.2 skrll struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
6175 1.29.2.2 skrll struct iwm_rx_packet *pkt, tmppkt;
6176 1.29.2.2 skrll struct iwm_cmd_response *cresp;
6177 1.29.2.2 skrll int qid, idx;
6178 1.29.2.2 skrll
6179 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof(*pkt),
6180 1.29.2.2 skrll BUS_DMASYNC_POSTREAD);
6181 1.29.2.2 skrll pkt = mtod(data->m, struct iwm_rx_packet *);
6182 1.29.2.2 skrll
6183 1.29.2.2 skrll qid = pkt->hdr.qid & ~0x80;
6184 1.29.2.2 skrll idx = pkt->hdr.idx;
6185 1.29.2.2 skrll
6186 1.29.2.2 skrll DPRINTFN(12, ("rx packet qid=%d idx=%d flags=%x type=%x %d %d\n",
6187 1.29.2.2 skrll pkt->hdr.qid & ~0x80, pkt->hdr.idx, pkt->hdr.flags,
6188 1.29.2.2 skrll pkt->hdr.code, sc->rxq.cur, hw));
6189 1.29.2.2 skrll
6190 1.29.2.2 skrll /*
6191 1.29.2.2 skrll * randomly get these from the firmware, no idea why.
6192 1.29.2.2 skrll * they at least seem harmless, so just ignore them for now
6193 1.29.2.2 skrll */
6194 1.29.2.2 skrll if (__predict_false((pkt->hdr.code == 0 && qid == 0 && idx == 0)
6195 1.29.2.2 skrll || pkt->len_n_flags == htole32(0x55550000))) {
6196 1.29.2.2 skrll ADVANCE_RXQ(sc);
6197 1.29.2.2 skrll continue;
6198 1.29.2.2 skrll }
6199 1.29.2.2 skrll
6200 1.29.2.2 skrll switch (pkt->hdr.code) {
6201 1.29.2.2 skrll case IWM_REPLY_RX_PHY_CMD:
6202 1.29.2.2 skrll iwm_mvm_rx_rx_phy_cmd(sc, pkt, data);
6203 1.29.2.2 skrll break;
6204 1.29.2.2 skrll
6205 1.29.2.2 skrll case IWM_REPLY_RX_MPDU_CMD:
6206 1.29.2.2 skrll tmppkt = *pkt; // XXX m is freed by ieee80211_input()
6207 1.29.2.2 skrll iwm_mvm_rx_rx_mpdu(sc, pkt, data);
6208 1.29.2.2 skrll pkt = &tmppkt;
6209 1.29.2.2 skrll break;
6210 1.29.2.2 skrll
6211 1.29.2.2 skrll case IWM_TX_CMD:
6212 1.29.2.2 skrll iwm_mvm_rx_tx_cmd(sc, pkt, data);
6213 1.29.2.2 skrll break;
6214 1.29.2.2 skrll
6215 1.29.2.2 skrll case IWM_MISSED_BEACONS_NOTIFICATION:
6216 1.29.2.2 skrll iwm_mvm_rx_missed_beacons_notif(sc, pkt, data);
6217 1.29.2.2 skrll break;
6218 1.29.2.2 skrll
6219 1.29.2.2 skrll case IWM_MVM_ALIVE: {
6220 1.29.2.2 skrll struct iwm_mvm_alive_resp *resp;
6221 1.29.2.2 skrll SYNC_RESP_STRUCT(resp, pkt);
6222 1.29.2.2 skrll
6223 1.29.2.2 skrll sc->sc_uc.uc_error_event_table
6224 1.29.2.2 skrll = le32toh(resp->error_event_table_ptr);
6225 1.29.2.2 skrll sc->sc_uc.uc_log_event_table
6226 1.29.2.2 skrll = le32toh(resp->log_event_table_ptr);
6227 1.29.2.2 skrll sc->sched_base = le32toh(resp->scd_base_ptr);
6228 1.29.2.2 skrll sc->sc_uc.uc_ok = resp->status == IWM_ALIVE_STATUS_OK;
6229 1.29.2.2 skrll
6230 1.29.2.2 skrll sc->sc_uc.uc_intr = 1;
6231 1.29.2.2 skrll wakeup(&sc->sc_uc);
6232 1.29.2.2 skrll break; }
6233 1.29.2.2 skrll
6234 1.29.2.2 skrll case IWM_CALIB_RES_NOTIF_PHY_DB: {
6235 1.29.2.2 skrll struct iwm_calib_res_notif_phy_db *phy_db_notif;
6236 1.29.2.2 skrll SYNC_RESP_STRUCT(phy_db_notif, pkt);
6237 1.29.2.2 skrll
6238 1.29.2.2 skrll uint16_t size = le16toh(phy_db_notif->length);
6239 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map,
6240 1.29.2.2 skrll sizeof(*pkt) + sizeof(*phy_db_notif),
6241 1.29.2.2 skrll size, BUS_DMASYNC_POSTREAD);
6242 1.29.2.2 skrll iwm_phy_db_set_section(sc, phy_db_notif, size);
6243 1.29.2.2 skrll
6244 1.29.2.2 skrll break; }
6245 1.29.2.2 skrll
6246 1.29.2.2 skrll case IWM_STATISTICS_NOTIFICATION: {
6247 1.29.2.2 skrll struct iwm_notif_statistics *stats;
6248 1.29.2.2 skrll SYNC_RESP_STRUCT(stats, pkt);
6249 1.29.2.2 skrll memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats));
6250 1.29.2.2 skrll sc->sc_noise = iwm_get_noise(&stats->rx.general);
6251 1.29.2.2 skrll break; }
6252 1.29.2.2 skrll
6253 1.29.2.2 skrll case IWM_NVM_ACCESS_CMD:
6254 1.29.2.2 skrll if (sc->sc_wantresp == ((qid << 16) | idx)) {
6255 1.29.2.2 skrll bus_dmamap_sync(sc->sc_dmat, data->map, 0,
6256 1.29.2.2 skrll sizeof(sc->sc_cmd_resp),
6257 1.29.2.2 skrll BUS_DMASYNC_POSTREAD);
6258 1.29.2.2 skrll memcpy(sc->sc_cmd_resp,
6259 1.29.2.2 skrll pkt, sizeof(sc->sc_cmd_resp));
6260 1.29.2.2 skrll }
6261 1.29.2.2 skrll break;
6262 1.29.2.2 skrll
6263 1.29.2.2 skrll case IWM_PHY_CONFIGURATION_CMD:
6264 1.29.2.2 skrll case IWM_TX_ANT_CONFIGURATION_CMD:
6265 1.29.2.2 skrll case IWM_ADD_STA:
6266 1.29.2.2 skrll case IWM_MAC_CONTEXT_CMD:
6267 1.29.2.2 skrll case IWM_REPLY_SF_CFG_CMD:
6268 1.29.2.2 skrll case IWM_POWER_TABLE_CMD:
6269 1.29.2.2 skrll case IWM_PHY_CONTEXT_CMD:
6270 1.29.2.2 skrll case IWM_BINDING_CONTEXT_CMD:
6271 1.29.2.2 skrll case IWM_TIME_EVENT_CMD:
6272 1.29.2.2 skrll case IWM_SCAN_REQUEST_CMD:
6273 1.29.2.2 skrll case IWM_REPLY_BEACON_FILTERING_CMD:
6274 1.29.2.2 skrll case IWM_MAC_PM_POWER_TABLE:
6275 1.29.2.2 skrll case IWM_TIME_QUOTA_CMD:
6276 1.29.2.2 skrll case IWM_REMOVE_STA:
6277 1.29.2.2 skrll case IWM_TXPATH_FLUSH:
6278 1.29.2.2 skrll case IWM_LQ_CMD:
6279 1.29.2.2 skrll SYNC_RESP_STRUCT(cresp, pkt);
6280 1.29.2.2 skrll if (sc->sc_wantresp == ((qid << 16) | idx)) {
6281 1.29.2.2 skrll memcpy(sc->sc_cmd_resp,
6282 1.29.2.2 skrll pkt, sizeof(*pkt)+sizeof(*cresp));
6283 1.29.2.2 skrll }
6284 1.29.2.2 skrll break;
6285 1.29.2.2 skrll
6286 1.29.2.2 skrll /* ignore */
6287 1.29.2.2 skrll case 0x6c: /* IWM_PHY_DB_CMD, no idea why it's not in fw-api.h */
6288 1.29.2.2 skrll break;
6289 1.29.2.2 skrll
6290 1.29.2.2 skrll case IWM_INIT_COMPLETE_NOTIF:
6291 1.29.2.2 skrll sc->sc_init_complete = 1;
6292 1.29.2.2 skrll wakeup(&sc->sc_init_complete);
6293 1.29.2.2 skrll break;
6294 1.29.2.2 skrll
6295 1.29.2.2 skrll case IWM_SCAN_COMPLETE_NOTIFICATION: {
6296 1.29.2.2 skrll struct iwm_scan_complete_notif *notif;
6297 1.29.2.2 skrll SYNC_RESP_STRUCT(notif, pkt);
6298 1.29.2.2 skrll
6299 1.29.2.2 skrll workqueue_enqueue(sc->sc_eswq, &sc->sc_eswk, NULL);
6300 1.29.2.2 skrll break; }
6301 1.29.2.2 skrll
6302 1.29.2.2 skrll case IWM_REPLY_ERROR: {
6303 1.29.2.2 skrll struct iwm_error_resp *resp;
6304 1.29.2.2 skrll SYNC_RESP_STRUCT(resp, pkt);
6305 1.29.2.2 skrll
6306 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6307 1.29.2.2 skrll "firmware error 0x%x, cmd 0x%x\n",
6308 1.29.2.2 skrll le32toh(resp->error_type), resp->cmd_id);
6309 1.29.2.2 skrll break; }
6310 1.29.2.2 skrll
6311 1.29.2.2 skrll case IWM_TIME_EVENT_NOTIFICATION: {
6312 1.29.2.2 skrll struct iwm_time_event_notif *notif;
6313 1.29.2.2 skrll SYNC_RESP_STRUCT(notif, pkt);
6314 1.29.2.2 skrll
6315 1.29.2.2 skrll if (notif->status) {
6316 1.29.2.2 skrll if (le32toh(notif->action) &
6317 1.29.2.2 skrll IWM_TE_V2_NOTIF_HOST_EVENT_START)
6318 1.29.2.2 skrll sc->sc_auth_prot = 2;
6319 1.29.2.2 skrll else
6320 1.29.2.2 skrll sc->sc_auth_prot = 0;
6321 1.29.2.2 skrll } else {
6322 1.29.2.2 skrll sc->sc_auth_prot = -1;
6323 1.29.2.2 skrll }
6324 1.29.2.2 skrll wakeup(&sc->sc_auth_prot);
6325 1.29.2.2 skrll break; }
6326 1.29.2.2 skrll
6327 1.29.2.2 skrll case IWM_MCAST_FILTER_CMD:
6328 1.29.2.2 skrll break;
6329 1.29.2.2 skrll
6330 1.29.2.2 skrll default:
6331 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6332 1.29.2.2 skrll "code %02x frame %d/%d %x UNHANDLED "
6333 1.29.2.2 skrll "(this should not happen)\n",
6334 1.29.2.2 skrll pkt->hdr.code, qid, idx, pkt->len_n_flags);
6335 1.29.2.2 skrll break;
6336 1.29.2.2 skrll }
6337 1.29.2.2 skrll
6338 1.29.2.2 skrll /*
6339 1.29.2.2 skrll * Why test bit 0x80? The Linux driver:
6340 1.29.2.2 skrll *
6341 1.29.2.2 skrll * There is one exception: uCode sets bit 15 when it
6342 1.29.2.2 skrll * originates the response/notification, i.e. when the
6343 1.29.2.2 skrll * response/notification is not a direct response to a
6344 1.29.2.2 skrll * command sent by the driver. For example, uCode issues
6345 1.29.2.2 skrll * IWM_REPLY_RX when it sends a received frame to the driver;
6346 1.29.2.2 skrll * it is not a direct response to any driver command.
6347 1.29.2.2 skrll *
6348 1.29.2.2 skrll * Ok, so since when is 7 == 15? Well, the Linux driver
6349 1.29.2.2 skrll * uses a slightly different format for pkt->hdr, and "qid"
6350 1.29.2.2 skrll * is actually the upper byte of a two-byte field.
6351 1.29.2.2 skrll */
6352 1.29.2.2 skrll if (!(pkt->hdr.qid & (1 << 7))) {
6353 1.29.2.2 skrll iwm_cmd_done(sc, pkt);
6354 1.29.2.2 skrll }
6355 1.29.2.2 skrll
6356 1.29.2.2 skrll ADVANCE_RXQ(sc);
6357 1.29.2.2 skrll }
6358 1.29.2.2 skrll
6359 1.29.2.2 skrll IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
6360 1.29.2.2 skrll IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
6361 1.29.2.2 skrll
6362 1.29.2.2 skrll /*
6363 1.29.2.2 skrll * Tell the firmware what we have processed.
6364 1.29.2.2 skrll * Seems like the hardware gets upset unless we align
6365 1.29.2.2 skrll * the write by 8??
6366 1.29.2.2 skrll */
6367 1.29.2.2 skrll hw = (hw == 0) ? IWM_RX_RING_COUNT - 1 : hw - 1;
6368 1.29.2.2 skrll IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7);
6369 1.29.2.2 skrll }
6370 1.29.2.2 skrll
6371 1.29.2.2 skrll static int
6372 1.29.2.2 skrll iwm_intr(void *arg)
6373 1.29.2.2 skrll {
6374 1.29.2.2 skrll struct iwm_softc *sc = arg;
6375 1.29.2.2 skrll struct ifnet *ifp = IC2IFP(&sc->sc_ic);
6376 1.29.2.2 skrll int handled = 0;
6377 1.29.2.2 skrll int r1, r2, rv = 0;
6378 1.29.2.2 skrll int isperiodic = 0;
6379 1.29.2.2 skrll
6380 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
6381 1.29.2.2 skrll
6382 1.29.2.2 skrll if (sc->sc_flags & IWM_FLAG_USE_ICT) {
6383 1.29.2.2 skrll uint32_t *ict = sc->ict_dma.vaddr;
6384 1.29.2.2 skrll int tmp;
6385 1.29.2.2 skrll
6386 1.29.2.2 skrll tmp = htole32(ict[sc->ict_cur]);
6387 1.29.2.2 skrll if (!tmp)
6388 1.29.2.2 skrll goto out_ena;
6389 1.29.2.2 skrll
6390 1.29.2.2 skrll /*
6391 1.29.2.2 skrll * ok, there was something. keep plowing until we have all.
6392 1.29.2.2 skrll */
6393 1.29.2.2 skrll r1 = r2 = 0;
6394 1.29.2.2 skrll while (tmp) {
6395 1.29.2.2 skrll r1 |= tmp;
6396 1.29.2.2 skrll ict[sc->ict_cur] = 0;
6397 1.29.2.2 skrll sc->ict_cur = (sc->ict_cur+1) % IWM_ICT_COUNT;
6398 1.29.2.2 skrll tmp = htole32(ict[sc->ict_cur]);
6399 1.29.2.2 skrll }
6400 1.29.2.2 skrll
6401 1.29.2.2 skrll /* this is where the fun begins. don't ask */
6402 1.29.2.2 skrll if (r1 == 0xffffffff)
6403 1.29.2.2 skrll r1 = 0;
6404 1.29.2.2 skrll
6405 1.29.2.2 skrll /* i am not expected to understand this */
6406 1.29.2.2 skrll if (r1 & 0xc0000)
6407 1.29.2.2 skrll r1 |= 0x8000;
6408 1.29.2.2 skrll r1 = (0xff & r1) | ((0xff00 & r1) << 16);
6409 1.29.2.2 skrll } else {
6410 1.29.2.2 skrll r1 = IWM_READ(sc, IWM_CSR_INT);
6411 1.29.2.2 skrll /* "hardware gone" (where, fishing?) */
6412 1.29.2.2 skrll if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
6413 1.29.2.2 skrll goto out;
6414 1.29.2.2 skrll r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS);
6415 1.29.2.2 skrll }
6416 1.29.2.2 skrll if (r1 == 0 && r2 == 0) {
6417 1.29.2.2 skrll goto out_ena;
6418 1.29.2.2 skrll }
6419 1.29.2.2 skrll
6420 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask);
6421 1.29.2.2 skrll
6422 1.29.2.2 skrll /* ignored */
6423 1.29.2.2 skrll handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/));
6424 1.29.2.2 skrll
6425 1.29.2.2 skrll if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
6426 1.29.2.2 skrll #ifdef IWM_DEBUG
6427 1.29.2.2 skrll int i;
6428 1.29.2.2 skrll
6429 1.29.2.2 skrll iwm_nic_error(sc);
6430 1.29.2.2 skrll
6431 1.29.2.2 skrll /* Dump driver status (TX and RX rings) while we're here. */
6432 1.29.2.2 skrll DPRINTF(("driver status:\n"));
6433 1.29.2.2 skrll for (i = 0; i < IWM_MVM_MAX_QUEUES; i++) {
6434 1.29.2.2 skrll struct iwm_tx_ring *ring = &sc->txq[i];
6435 1.29.2.2 skrll DPRINTF((" tx ring %2d: qid=%-2d cur=%-3d "
6436 1.29.2.2 skrll "queued=%-3d\n",
6437 1.29.2.2 skrll i, ring->qid, ring->cur, ring->queued));
6438 1.29.2.2 skrll }
6439 1.29.2.2 skrll DPRINTF((" rx ring: cur=%d\n", sc->rxq.cur));
6440 1.29.2.2 skrll DPRINTF((" 802.11 state %d\n", sc->sc_ic.ic_state));
6441 1.29.2.2 skrll #endif
6442 1.29.2.2 skrll
6443 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
6444 1.29.2.2 skrll ifp->if_flags &= ~IFF_UP;
6445 1.29.2.2 skrll iwm_stop(ifp, 1);
6446 1.29.2.2 skrll rv = 1;
6447 1.29.2.2 skrll goto out;
6448 1.29.2.2 skrll
6449 1.29.2.2 skrll }
6450 1.29.2.2 skrll
6451 1.29.2.2 skrll if (r1 & IWM_CSR_INT_BIT_HW_ERR) {
6452 1.29.2.2 skrll handled |= IWM_CSR_INT_BIT_HW_ERR;
6453 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6454 1.29.2.2 skrll "hardware error, stopping device\n");
6455 1.29.2.2 skrll ifp->if_flags &= ~IFF_UP;
6456 1.29.2.2 skrll iwm_stop(ifp, 1);
6457 1.29.2.2 skrll rv = 1;
6458 1.29.2.2 skrll goto out;
6459 1.29.2.2 skrll }
6460 1.29.2.2 skrll
6461 1.29.2.2 skrll /* firmware chunk loaded */
6462 1.29.2.2 skrll if (r1 & IWM_CSR_INT_BIT_FH_TX) {
6463 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_TX_MASK);
6464 1.29.2.2 skrll handled |= IWM_CSR_INT_BIT_FH_TX;
6465 1.29.2.2 skrll
6466 1.29.2.2 skrll sc->sc_fw_chunk_done = 1;
6467 1.29.2.2 skrll wakeup(&sc->sc_fw);
6468 1.29.2.2 skrll }
6469 1.29.2.2 skrll
6470 1.29.2.2 skrll if (r1 & IWM_CSR_INT_BIT_RF_KILL) {
6471 1.29.2.2 skrll handled |= IWM_CSR_INT_BIT_RF_KILL;
6472 1.29.2.2 skrll if (iwm_check_rfkill(sc) && (ifp->if_flags & IFF_UP)) {
6473 1.29.2.2 skrll DPRINTF(("%s: rfkill switch, disabling interface\n",
6474 1.29.2.2 skrll DEVNAME(sc)));
6475 1.29.2.2 skrll ifp->if_flags &= ~IFF_UP;
6476 1.29.2.2 skrll iwm_stop(ifp, 1);
6477 1.29.2.2 skrll }
6478 1.29.2.2 skrll }
6479 1.29.2.2 skrll
6480 1.29.2.2 skrll /*
6481 1.29.2.2 skrll * The Linux driver uses periodic interrupts to avoid races.
6482 1.29.2.2 skrll * We cargo-cult like it's going out of fashion.
6483 1.29.2.2 skrll */
6484 1.29.2.2 skrll if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) {
6485 1.29.2.2 skrll handled |= IWM_CSR_INT_BIT_RX_PERIODIC;
6486 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC);
6487 1.29.2.2 skrll if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) == 0)
6488 1.29.2.2 skrll IWM_WRITE_1(sc,
6489 1.29.2.2 skrll IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_DIS);
6490 1.29.2.2 skrll isperiodic = 1;
6491 1.29.2.2 skrll }
6492 1.29.2.2 skrll
6493 1.29.2.2 skrll if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) || isperiodic) {
6494 1.29.2.2 skrll handled |= (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX);
6495 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK);
6496 1.29.2.2 skrll
6497 1.29.2.2 skrll iwm_notif_intr(sc);
6498 1.29.2.2 skrll
6499 1.29.2.2 skrll /* enable periodic interrupt, see above */
6500 1.29.2.2 skrll if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX) && !isperiodic)
6501 1.29.2.2 skrll IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG,
6502 1.29.2.2 skrll IWM_CSR_INT_PERIODIC_ENA);
6503 1.29.2.2 skrll }
6504 1.29.2.2 skrll
6505 1.29.2.2 skrll if (__predict_false(r1 & ~handled))
6506 1.29.2.2 skrll DPRINTF(("%s: unhandled interrupts: %x\n", DEVNAME(sc), r1));
6507 1.29.2.2 skrll rv = 1;
6508 1.29.2.2 skrll
6509 1.29.2.2 skrll out_ena:
6510 1.29.2.2 skrll iwm_restore_interrupts(sc);
6511 1.29.2.2 skrll out:
6512 1.29.2.2 skrll return rv;
6513 1.29.2.2 skrll }
6514 1.29.2.2 skrll
6515 1.29.2.2 skrll /*
6516 1.29.2.2 skrll * Autoconf glue-sniffing
6517 1.29.2.2 skrll */
6518 1.29.2.2 skrll
6519 1.29.2.2 skrll static const pci_product_id_t iwm_devices[] = {
6520 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_7260_1,
6521 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_7260_2,
6522 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_3160_1,
6523 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_3160_2,
6524 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_7265_1,
6525 1.29.2.2 skrll PCI_PRODUCT_INTEL_WIFI_LINK_7265_2,
6526 1.29.2.2 skrll };
6527 1.29.2.2 skrll
6528 1.29.2.2 skrll static int
6529 1.29.2.2 skrll iwm_match(device_t parent, cfdata_t match __unused, void *aux)
6530 1.29.2.2 skrll {
6531 1.29.2.2 skrll struct pci_attach_args *pa = aux;
6532 1.29.2.2 skrll
6533 1.29.2.2 skrll if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
6534 1.29.2.2 skrll return 0;
6535 1.29.2.2 skrll
6536 1.29.2.2 skrll for (size_t i = 0; i < __arraycount(iwm_devices); i++)
6537 1.29.2.2 skrll if (PCI_PRODUCT(pa->pa_id) == iwm_devices[i])
6538 1.29.2.2 skrll return 1;
6539 1.29.2.2 skrll
6540 1.29.2.2 skrll return 0;
6541 1.29.2.2 skrll }
6542 1.29.2.2 skrll
6543 1.29.2.2 skrll static int
6544 1.29.2.2 skrll iwm_preinit(struct iwm_softc *sc)
6545 1.29.2.2 skrll {
6546 1.29.2.4 skrll struct ieee80211com *ic = &sc->sc_ic;
6547 1.29.2.2 skrll int error;
6548 1.29.2.2 skrll
6549 1.29.2.2 skrll if (sc->sc_flags & IWM_FLAG_ATTACHED)
6550 1.29.2.2 skrll return 0;
6551 1.29.2.2 skrll
6552 1.29.2.2 skrll if ((error = iwm_start_hw(sc)) != 0) {
6553 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
6554 1.29.2.2 skrll return error;
6555 1.29.2.2 skrll }
6556 1.29.2.2 skrll
6557 1.29.2.2 skrll error = iwm_run_init_mvm_ucode(sc, 1);
6558 1.29.2.2 skrll iwm_stop_device(sc);
6559 1.29.2.4 skrll if (error)
6560 1.29.2.4 skrll return error;
6561 1.29.2.2 skrll
6562 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_ATTACHED;
6563 1.29.2.2 skrll
6564 1.29.2.2 skrll aprint_normal_dev(sc->sc_dev,
6565 1.29.2.2 skrll "hw rev: 0x%x, fw ver %d.%d (API ver %d), address %s\n",
6566 1.29.2.2 skrll sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK,
6567 1.29.2.2 skrll IWM_UCODE_MAJOR(sc->sc_fwver),
6568 1.29.2.2 skrll IWM_UCODE_MINOR(sc->sc_fwver),
6569 1.29.2.2 skrll IWM_UCODE_API(sc->sc_fwver),
6570 1.29.2.2 skrll ether_sprintf(sc->sc_nvm.hw_addr));
6571 1.29.2.2 skrll
6572 1.29.2.2 skrll /* not all hardware can do 5GHz band */
6573 1.29.2.2 skrll if (sc->sc_nvm.sku_cap_band_52GHz_enable)
6574 1.29.2.2 skrll ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
6575 1.29.2.2 skrll
6576 1.29.2.2 skrll ieee80211_ifattach(ic);
6577 1.29.2.2 skrll
6578 1.29.2.2 skrll ic->ic_node_alloc = iwm_node_alloc;
6579 1.29.2.2 skrll
6580 1.29.2.2 skrll /* Override 802.11 state transition machine. */
6581 1.29.2.2 skrll sc->sc_newstate = ic->ic_newstate;
6582 1.29.2.2 skrll ic->ic_newstate = iwm_newstate;
6583 1.29.2.2 skrll ieee80211_media_init(ic, iwm_media_change, ieee80211_media_status);
6584 1.29.2.2 skrll ieee80211_announce(ic);
6585 1.29.2.2 skrll
6586 1.29.2.2 skrll iwm_radiotap_attach(sc);
6587 1.29.2.2 skrll
6588 1.29.2.4 skrll return 0;
6589 1.29.2.4 skrll }
6590 1.29.2.3 skrll
6591 1.29.2.4 skrll static void
6592 1.29.2.4 skrll iwm_attach_hook(device_t dev)
6593 1.29.2.4 skrll {
6594 1.29.2.4 skrll struct iwm_softc *sc = device_private(dev);
6595 1.29.2.4 skrll
6596 1.29.2.4 skrll iwm_preinit(sc);
6597 1.29.2.2 skrll }
6598 1.29.2.2 skrll
6599 1.29.2.2 skrll static void
6600 1.29.2.2 skrll iwm_attach(device_t parent, device_t self, void *aux)
6601 1.29.2.2 skrll {
6602 1.29.2.2 skrll struct iwm_softc *sc = device_private(self);
6603 1.29.2.2 skrll struct pci_attach_args *pa = aux;
6604 1.29.2.4 skrll struct ieee80211com *ic = &sc->sc_ic;
6605 1.29.2.4 skrll struct ifnet *ifp = &sc->sc_ec.ec_if;
6606 1.29.2.3 skrll #ifndef __HAVE_PCI_MSI_MSIX
6607 1.29.2.2 skrll pci_intr_handle_t ih;
6608 1.29.2.3 skrll #endif
6609 1.29.2.2 skrll pcireg_t reg, memtype;
6610 1.29.2.4 skrll char intrbuf[PCI_INTRSTR_LEN];
6611 1.29.2.2 skrll const char *intrstr;
6612 1.29.2.2 skrll int error;
6613 1.29.2.2 skrll int txq_i;
6614 1.29.2.4 skrll const struct sysctlnode *node;
6615 1.29.2.2 skrll
6616 1.29.2.2 skrll sc->sc_dev = self;
6617 1.29.2.2 skrll sc->sc_pct = pa->pa_pc;
6618 1.29.2.2 skrll sc->sc_pcitag = pa->pa_tag;
6619 1.29.2.2 skrll sc->sc_dmat = pa->pa_dmat;
6620 1.29.2.2 skrll sc->sc_pciid = pa->pa_id;
6621 1.29.2.2 skrll
6622 1.29.2.2 skrll pci_aprint_devinfo(pa, NULL);
6623 1.29.2.2 skrll
6624 1.29.2.2 skrll /*
6625 1.29.2.2 skrll * Get the offset of the PCI Express Capability Structure in PCI
6626 1.29.2.2 skrll * Configuration Space.
6627 1.29.2.2 skrll */
6628 1.29.2.2 skrll error = pci_get_capability(sc->sc_pct, sc->sc_pcitag,
6629 1.29.2.2 skrll PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL);
6630 1.29.2.2 skrll if (error == 0) {
6631 1.29.2.2 skrll aprint_error_dev(self,
6632 1.29.2.2 skrll "PCIe capability structure not found!\n");
6633 1.29.2.2 skrll return;
6634 1.29.2.2 skrll }
6635 1.29.2.2 skrll
6636 1.29.2.2 skrll /* Clear device-specific "PCI retry timeout" register (41h). */
6637 1.29.2.2 skrll reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
6638 1.29.2.2 skrll pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
6639 1.29.2.2 skrll
6640 1.29.2.2 skrll /* Enable bus-mastering and hardware bug workaround. */
6641 1.29.2.2 skrll reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG);
6642 1.29.2.2 skrll reg |= PCI_COMMAND_MASTER_ENABLE;
6643 1.29.2.2 skrll /* if !MSI */
6644 1.29.2.2 skrll if (reg & PCI_COMMAND_INTERRUPT_DISABLE) {
6645 1.29.2.2 skrll reg &= ~PCI_COMMAND_INTERRUPT_DISABLE;
6646 1.29.2.2 skrll }
6647 1.29.2.2 skrll pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg);
6648 1.29.2.2 skrll
6649 1.29.2.2 skrll memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
6650 1.29.2.2 skrll error = pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0,
6651 1.29.2.2 skrll &sc->sc_st, &sc->sc_sh, NULL, &sc->sc_sz);
6652 1.29.2.2 skrll if (error != 0) {
6653 1.29.2.2 skrll aprint_error_dev(self, "can't map mem space\n");
6654 1.29.2.2 skrll return;
6655 1.29.2.2 skrll }
6656 1.29.2.2 skrll
6657 1.29.2.2 skrll /* Install interrupt handler. */
6658 1.29.2.3 skrll #ifdef __HAVE_PCI_MSI_MSIX
6659 1.29.2.4 skrll error = pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0);
6660 1.29.2.3 skrll if (error != 0) {
6661 1.29.2.4 skrll aprint_error_dev(self, "can't allocate interrupt\n");
6662 1.29.2.2 skrll return;
6663 1.29.2.2 skrll }
6664 1.29.2.3 skrll intrstr = pci_intr_string(sc->sc_pct, sc->sc_pihp[0], intrbuf,
6665 1.29.2.3 skrll sizeof(intrbuf));
6666 1.29.2.3 skrll sc->sc_ih = pci_intr_establish(sc->sc_pct, sc->sc_pihp[0], IPL_NET,
6667 1.29.2.3 skrll iwm_intr, sc);
6668 1.29.2.3 skrll #else /* !__HAVE_PCI_MSI_MSIX */
6669 1.29.2.4 skrll if (pci_intr_map(pa, &ih)) {
6670 1.29.2.4 skrll aprint_error_dev(self, "can't map interrupt\n");
6671 1.29.2.4 skrll return;
6672 1.29.2.4 skrll }
6673 1.29.2.2 skrll intrstr = pci_intr_string(sc->sc_pct, ih, intrbuf, sizeof(intrbuf));
6674 1.29.2.2 skrll sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, iwm_intr, sc);
6675 1.29.2.3 skrll #endif /* __HAVE_PCI_MSI_MSIX */
6676 1.29.2.2 skrll if (sc->sc_ih == NULL) {
6677 1.29.2.2 skrll aprint_error_dev(self, "can't establish interrupt");
6678 1.29.2.2 skrll if (intrstr != NULL)
6679 1.29.2.2 skrll aprint_error(" at %s", intrstr);
6680 1.29.2.2 skrll aprint_error("\n");
6681 1.29.2.2 skrll return;
6682 1.29.2.2 skrll }
6683 1.29.2.2 skrll aprint_normal_dev(self, "interrupting at %s\n", intrstr);
6684 1.29.2.2 skrll
6685 1.29.2.2 skrll sc->sc_wantresp = -1;
6686 1.29.2.2 skrll
6687 1.29.2.2 skrll switch (PCI_PRODUCT(sc->sc_pciid)) {
6688 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_7260_1:
6689 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_7260_2:
6690 1.29.2.2 skrll sc->sc_fwname = "iwlwifi-7260-9.ucode";
6691 1.29.2.2 skrll sc->host_interrupt_operation_mode = 1;
6692 1.29.2.2 skrll break;
6693 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_3160_1:
6694 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_3160_2:
6695 1.29.2.2 skrll sc->sc_fwname = "iwlwifi-3160-9.ucode";
6696 1.29.2.2 skrll sc->host_interrupt_operation_mode = 1;
6697 1.29.2.2 skrll break;
6698 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_7265_1:
6699 1.29.2.2 skrll case PCI_PRODUCT_INTEL_WIFI_LINK_7265_2:
6700 1.29.2.2 skrll sc->sc_fwname = "iwlwifi-7265-9.ucode";
6701 1.29.2.2 skrll sc->host_interrupt_operation_mode = 0;
6702 1.29.2.2 skrll break;
6703 1.29.2.2 skrll default:
6704 1.29.2.2 skrll aprint_error_dev(self, "unknown product %#x",
6705 1.29.2.2 skrll PCI_PRODUCT(sc->sc_pciid));
6706 1.29.2.2 skrll return;
6707 1.29.2.2 skrll }
6708 1.29.2.2 skrll DPRINTF(("%s: firmware=%s\n", DEVNAME(sc), sc->sc_fwname));
6709 1.29.2.2 skrll sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
6710 1.29.2.2 skrll
6711 1.29.2.2 skrll /*
6712 1.29.2.2 skrll * We now start fiddling with the hardware
6713 1.29.2.2 skrll */
6714 1.29.2.2 skrll
6715 1.29.2.2 skrll sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV);
6716 1.29.2.2 skrll if (iwm_prepare_card_hw(sc) != 0) {
6717 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
6718 1.29.2.2 skrll return;
6719 1.29.2.2 skrll }
6720 1.29.2.2 skrll
6721 1.29.2.2 skrll /* Allocate DMA memory for firmware transfers. */
6722 1.29.2.2 skrll if ((error = iwm_alloc_fwmem(sc)) != 0) {
6723 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6724 1.29.2.2 skrll "could not allocate memory for firmware\n");
6725 1.29.2.2 skrll return;
6726 1.29.2.2 skrll }
6727 1.29.2.2 skrll
6728 1.29.2.2 skrll /* Allocate "Keep Warm" page. */
6729 1.29.2.2 skrll if ((error = iwm_alloc_kw(sc)) != 0) {
6730 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6731 1.29.2.2 skrll "could not allocate keep warm page\n");
6732 1.29.2.2 skrll goto fail1;
6733 1.29.2.2 skrll }
6734 1.29.2.2 skrll
6735 1.29.2.2 skrll /* We use ICT interrupts */
6736 1.29.2.2 skrll if ((error = iwm_alloc_ict(sc)) != 0) {
6737 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not allocate ICT table\n");
6738 1.29.2.2 skrll goto fail2;
6739 1.29.2.2 skrll }
6740 1.29.2.2 skrll
6741 1.29.2.2 skrll /* Allocate TX scheduler "rings". */
6742 1.29.2.2 skrll if ((error = iwm_alloc_sched(sc)) != 0) {
6743 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6744 1.29.2.2 skrll "could not allocate TX scheduler rings\n");
6745 1.29.2.2 skrll goto fail3;
6746 1.29.2.2 skrll }
6747 1.29.2.2 skrll
6748 1.29.2.2 skrll /* Allocate TX rings */
6749 1.29.2.2 skrll for (txq_i = 0; txq_i < __arraycount(sc->txq); txq_i++) {
6750 1.29.2.2 skrll if ((error = iwm_alloc_tx_ring(sc,
6751 1.29.2.2 skrll &sc->txq[txq_i], txq_i)) != 0) {
6752 1.29.2.2 skrll aprint_error_dev(sc->sc_dev,
6753 1.29.2.2 skrll "could not allocate TX ring %d\n", txq_i);
6754 1.29.2.2 skrll goto fail4;
6755 1.29.2.2 skrll }
6756 1.29.2.2 skrll }
6757 1.29.2.2 skrll
6758 1.29.2.2 skrll /* Allocate RX ring. */
6759 1.29.2.2 skrll if ((error = iwm_alloc_rx_ring(sc, &sc->rxq)) != 0) {
6760 1.29.2.2 skrll aprint_error_dev(sc->sc_dev, "could not allocate RX ring\n");
6761 1.29.2.2 skrll goto fail4;
6762 1.29.2.2 skrll }
6763 1.29.2.2 skrll
6764 1.29.2.2 skrll workqueue_create(&sc->sc_eswq, "iwmes",
6765 1.29.2.2 skrll iwm_endscan_cb, sc, PRI_NONE, IPL_NET, 0);
6766 1.29.2.2 skrll workqueue_create(&sc->sc_nswq, "iwmns",
6767 1.29.2.2 skrll iwm_newstate_cb, sc, PRI_NONE, IPL_NET, 0);
6768 1.29.2.2 skrll
6769 1.29.2.2 skrll /* Clear pending interrupts. */
6770 1.29.2.2 skrll IWM_WRITE(sc, IWM_CSR_INT, 0xffffffff);
6771 1.29.2.2 skrll
6772 1.29.2.4 skrll if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
6773 1.29.2.4 skrll 0, CTLTYPE_NODE, device_xname(sc->sc_dev),
6774 1.29.2.4 skrll SYSCTL_DESCR("iwm per-controller controls"),
6775 1.29.2.4 skrll NULL, 0, NULL, 0,
6776 1.29.2.4 skrll CTL_HW, iwm_sysctl_root_num, CTL_CREATE,
6777 1.29.2.4 skrll CTL_EOL)) != 0) {
6778 1.29.2.4 skrll aprint_normal_dev(sc->sc_dev,
6779 1.29.2.4 skrll "couldn't create iwm per-controller sysctl node\n");
6780 1.29.2.4 skrll }
6781 1.29.2.4 skrll if (error == 0) {
6782 1.29.2.4 skrll int iwm_nodenum = node->sysctl_num;
6783 1.29.2.4 skrll
6784 1.29.2.4 skrll /* Reload firmware sysctl node */
6785 1.29.2.4 skrll if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
6786 1.29.2.4 skrll CTLFLAG_READWRITE, CTLTYPE_INT, "fw_loaded",
6787 1.29.2.4 skrll SYSCTL_DESCR("Reload firmware"),
6788 1.29.2.4 skrll iwm_sysctl_fw_loaded_handler, 0, (void *)sc, 0,
6789 1.29.2.4 skrll CTL_HW, iwm_sysctl_root_num, iwm_nodenum, CTL_CREATE,
6790 1.29.2.4 skrll CTL_EOL)) != 0) {
6791 1.29.2.4 skrll aprint_normal_dev(sc->sc_dev,
6792 1.29.2.4 skrll "couldn't create load_fw sysctl node\n");
6793 1.29.2.4 skrll }
6794 1.29.2.4 skrll }
6795 1.29.2.4 skrll
6796 1.29.2.4 skrll /*
6797 1.29.2.4 skrll * Attach interface
6798 1.29.2.4 skrll */
6799 1.29.2.4 skrll ic->ic_ifp = ifp;
6800 1.29.2.4 skrll ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
6801 1.29.2.4 skrll ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
6802 1.29.2.4 skrll ic->ic_state = IEEE80211_S_INIT;
6803 1.29.2.4 skrll
6804 1.29.2.4 skrll /* Set device capabilities. */
6805 1.29.2.4 skrll ic->ic_caps =
6806 1.29.2.4 skrll IEEE80211_C_WEP | /* WEP */
6807 1.29.2.4 skrll IEEE80211_C_WPA | /* 802.11i */
6808 1.29.2.4 skrll IEEE80211_C_SHSLOT | /* short slot time supported */
6809 1.29.2.4 skrll IEEE80211_C_SHPREAMBLE; /* short preamble supported */
6810 1.29.2.4 skrll
6811 1.29.2.4 skrll /* all hardware can do 2.4GHz band */
6812 1.29.2.4 skrll ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
6813 1.29.2.4 skrll ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
6814 1.29.2.4 skrll
6815 1.29.2.4 skrll for (int i = 0; i < __arraycount(sc->sc_phyctxt); i++) {
6816 1.29.2.4 skrll sc->sc_phyctxt[i].id = i;
6817 1.29.2.4 skrll }
6818 1.29.2.4 skrll
6819 1.29.2.4 skrll sc->sc_amrr.amrr_min_success_threshold = 1;
6820 1.29.2.4 skrll sc->sc_amrr.amrr_max_success_threshold = 15;
6821 1.29.2.4 skrll
6822 1.29.2.4 skrll /* IBSS channel undefined for now. */
6823 1.29.2.4 skrll ic->ic_ibss_chan = &ic->ic_channels[1];
6824 1.29.2.4 skrll
6825 1.29.2.4 skrll #if 0
6826 1.29.2.4 skrll /* Max RSSI */
6827 1.29.2.4 skrll ic->ic_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM;
6828 1.29.2.4 skrll #endif
6829 1.29.2.4 skrll
6830 1.29.2.4 skrll ifp->if_softc = sc;
6831 1.29.2.4 skrll ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
6832 1.29.2.4 skrll ifp->if_init = iwm_init;
6833 1.29.2.4 skrll ifp->if_stop = iwm_stop;
6834 1.29.2.4 skrll ifp->if_ioctl = iwm_ioctl;
6835 1.29.2.4 skrll ifp->if_start = iwm_start;
6836 1.29.2.4 skrll ifp->if_watchdog = iwm_watchdog;
6837 1.29.2.4 skrll IFQ_SET_READY(&ifp->if_snd);
6838 1.29.2.4 skrll memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
6839 1.29.2.4 skrll
6840 1.29.2.4 skrll if_initialize(ifp);
6841 1.29.2.4 skrll #if 0
6842 1.29.2.4 skrll ieee80211_ifattach(ic);
6843 1.29.2.4 skrll #else
6844 1.29.2.4 skrll ether_ifattach(ifp, ic->ic_myaddr); /* XXX */
6845 1.29.2.4 skrll #endif
6846 1.29.2.4 skrll if_register(ifp);
6847 1.29.2.4 skrll
6848 1.29.2.4 skrll callout_init(&sc->sc_calib_to, 0);
6849 1.29.2.4 skrll callout_setfunc(&sc->sc_calib_to, iwm_calib_timeout, sc);
6850 1.29.2.4 skrll
6851 1.29.2.4 skrll //task_set(&sc->init_task, iwm_init_task, sc);
6852 1.29.2.4 skrll
6853 1.29.2.4 skrll if (pmf_device_register(self, NULL, NULL))
6854 1.29.2.4 skrll pmf_class_network_register(self, ifp);
6855 1.29.2.4 skrll else
6856 1.29.2.4 skrll aprint_error_dev(self, "couldn't establish power handler\n");
6857 1.29.2.4 skrll
6858 1.29.2.2 skrll /*
6859 1.29.2.2 skrll * We can't do normal attach before the file system is mounted
6860 1.29.2.2 skrll * because we cannot read the MAC address without loading the
6861 1.29.2.2 skrll * firmware from disk. So we postpone until mountroot is done.
6862 1.29.2.2 skrll * Notably, this will require a full driver unload/load cycle
6863 1.29.2.2 skrll * (or reboot) in case the firmware is not present when the
6864 1.29.2.2 skrll * hook runs.
6865 1.29.2.2 skrll */
6866 1.29.2.2 skrll config_mountroot(self, iwm_attach_hook);
6867 1.29.2.2 skrll
6868 1.29.2.2 skrll return;
6869 1.29.2.2 skrll
6870 1.29.2.2 skrll /* Free allocated memory if something failed during attachment. */
6871 1.29.2.2 skrll fail4: while (--txq_i >= 0)
6872 1.29.2.2 skrll iwm_free_tx_ring(sc, &sc->txq[txq_i]);
6873 1.29.2.2 skrll iwm_free_sched(sc);
6874 1.29.2.2 skrll fail3: if (sc->ict_dma.vaddr != NULL)
6875 1.29.2.2 skrll iwm_free_ict(sc);
6876 1.29.2.2 skrll fail2: iwm_free_kw(sc);
6877 1.29.2.2 skrll fail1: iwm_free_fwmem(sc);
6878 1.29.2.2 skrll }
6879 1.29.2.2 skrll
6880 1.29.2.2 skrll /*
6881 1.29.2.2 skrll * Attach the interface to 802.11 radiotap.
6882 1.29.2.2 skrll */
6883 1.29.2.2 skrll void
6884 1.29.2.2 skrll iwm_radiotap_attach(struct iwm_softc *sc)
6885 1.29.2.2 skrll {
6886 1.29.2.2 skrll struct ifnet *ifp = sc->sc_ic.ic_ifp;
6887 1.29.2.2 skrll
6888 1.29.2.2 skrll bpf_attach2(ifp, DLT_IEEE802_11_RADIO,
6889 1.29.2.2 skrll sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
6890 1.29.2.2 skrll &sc->sc_drvbpf);
6891 1.29.2.2 skrll
6892 1.29.2.2 skrll sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
6893 1.29.2.2 skrll sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
6894 1.29.2.2 skrll sc->sc_rxtap.wr_ihdr.it_present = htole32(IWM_RX_RADIOTAP_PRESENT);
6895 1.29.2.2 skrll
6896 1.29.2.2 skrll sc->sc_txtap_len = sizeof sc->sc_txtapu;
6897 1.29.2.2 skrll sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
6898 1.29.2.2 skrll sc->sc_txtap.wt_ihdr.it_present = htole32(IWM_TX_RADIOTAP_PRESENT);
6899 1.29.2.2 skrll }
6900 1.29.2.2 skrll
6901 1.29.2.2 skrll #if 0
6902 1.29.2.2 skrll static void
6903 1.29.2.2 skrll iwm_init_task(void *arg1)
6904 1.29.2.2 skrll {
6905 1.29.2.2 skrll struct iwm_softc *sc = arg1;
6906 1.29.2.2 skrll struct ifnet *ifp = &sc->sc_ic.ic_if;
6907 1.29.2.2 skrll int s;
6908 1.29.2.2 skrll
6909 1.29.2.2 skrll s = splnet();
6910 1.29.2.2 skrll while (sc->sc_flags & IWM_FLAG_BUSY)
6911 1.29.2.2 skrll tsleep(&sc->sc_flags, 0, "iwmpwr", 0);
6912 1.29.2.2 skrll sc->sc_flags |= IWM_FLAG_BUSY;
6913 1.29.2.2 skrll
6914 1.29.2.2 skrll iwm_stop(ifp, 0);
6915 1.29.2.2 skrll if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
6916 1.29.2.2 skrll iwm_init(ifp);
6917 1.29.2.2 skrll
6918 1.29.2.2 skrll sc->sc_flags &= ~IWM_FLAG_BUSY;
6919 1.29.2.2 skrll wakeup(&sc->sc_flags);
6920 1.29.2.2 skrll splx(s);
6921 1.29.2.2 skrll }
6922 1.29.2.2 skrll
6923 1.29.2.2 skrll static void
6924 1.29.2.2 skrll iwm_wakeup(struct iwm_softc *sc)
6925 1.29.2.2 skrll {
6926 1.29.2.2 skrll pcireg_t reg;
6927 1.29.2.2 skrll
6928 1.29.2.2 skrll /* Clear device-specific "PCI retry timeout" register (41h). */
6929 1.29.2.2 skrll reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
6930 1.29.2.2 skrll pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
6931 1.29.2.2 skrll
6932 1.29.2.2 skrll iwm_init_task(sc);
6933 1.29.2.2 skrll }
6934 1.29.2.2 skrll
6935 1.29.2.2 skrll static int
6936 1.29.2.2 skrll iwm_activate(device_t self, enum devact act)
6937 1.29.2.2 skrll {
6938 1.29.2.2 skrll struct iwm_softc *sc = device_private(self);
6939 1.29.2.2 skrll struct ifnet *ifp = IC2IFP(&sc->sc_ic);
6940 1.29.2.2 skrll
6941 1.29.2.2 skrll switch (act) {
6942 1.29.2.2 skrll case DVACT_DEACTIVATE:
6943 1.29.2.2 skrll if (ifp->if_flags & IFF_RUNNING)
6944 1.29.2.2 skrll iwm_stop(ifp, 0);
6945 1.29.2.2 skrll return 0;
6946 1.29.2.2 skrll default:
6947 1.29.2.2 skrll return EOPNOTSUPP;
6948 1.29.2.2 skrll }
6949 1.29.2.2 skrll }
6950 1.29.2.2 skrll #endif
6951 1.29.2.2 skrll
6952 1.29.2.2 skrll CFATTACH_DECL_NEW(iwm, sizeof(struct iwm_softc), iwm_match, iwm_attach,
6953 1.29.2.2 skrll NULL, NULL);
6954 1.29.2.3 skrll
6955 1.29.2.4 skrll static int
6956 1.29.2.4 skrll iwm_sysctl_fw_loaded_handler(SYSCTLFN_ARGS)
6957 1.29.2.4 skrll {
6958 1.29.2.4 skrll struct sysctlnode node;
6959 1.29.2.4 skrll struct iwm_softc *sc;
6960 1.29.2.4 skrll int error, t;
6961 1.29.2.4 skrll
6962 1.29.2.4 skrll node = *rnode;
6963 1.29.2.4 skrll sc = node.sysctl_data;
6964 1.29.2.4 skrll t = ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED) ? 1 : 0;
6965 1.29.2.4 skrll node.sysctl_data = &t;
6966 1.29.2.4 skrll error = sysctl_lookup(SYSCTLFN_CALL(&node));
6967 1.29.2.4 skrll if (error || newp == NULL)
6968 1.29.2.4 skrll return error;
6969 1.29.2.4 skrll
6970 1.29.2.4 skrll if (t == 0)
6971 1.29.2.4 skrll CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
6972 1.29.2.4 skrll return 0;
6973 1.29.2.4 skrll }
6974 1.29.2.4 skrll
6975 1.29.2.3 skrll SYSCTL_SETUP(sysctl_iwm, "sysctl iwm(4) subtree setup")
6976 1.29.2.3 skrll {
6977 1.29.2.4 skrll const struct sysctlnode *rnode;
6978 1.29.2.4 skrll #ifdef IWM_DEBUG
6979 1.29.2.4 skrll const struct sysctlnode *cnode;
6980 1.29.2.4 skrll #endif /* IWM_DEBUG */
6981 1.29.2.3 skrll int rc;
6982 1.29.2.3 skrll
6983 1.29.2.3 skrll if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
6984 1.29.2.3 skrll CTLFLAG_PERMANENT, CTLTYPE_NODE, "iwm",
6985 1.29.2.3 skrll SYSCTL_DESCR("iwm global controls"),
6986 1.29.2.3 skrll NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
6987 1.29.2.3 skrll goto err;
6988 1.29.2.3 skrll
6989 1.29.2.4 skrll iwm_sysctl_root_num = rnode->sysctl_num;
6990 1.29.2.4 skrll
6991 1.29.2.4 skrll #ifdef IWM_DEBUG
6992 1.29.2.3 skrll /* control debugging printfs */
6993 1.29.2.3 skrll if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
6994 1.29.2.3 skrll CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
6995 1.29.2.3 skrll "debug", SYSCTL_DESCR("Enable debugging output"),
6996 1.29.2.3 skrll NULL, 0, &iwm_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
6997 1.29.2.3 skrll goto err;
6998 1.29.2.4 skrll #endif /* IWM_DEBUG */
6999 1.29.2.3 skrll
7000 1.29.2.3 skrll return;
7001 1.29.2.3 skrll
7002 1.29.2.3 skrll err:
7003 1.29.2.3 skrll aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
7004 1.29.2.3 skrll }
7005