1 /* $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */
4 * Copyright (c) 2014 genua mbh <info@genua.de>
5 * Copyright (c) 2014 Fixup Software Ltd.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Based on BSD-licensed source modules in the Linux iwlwifi driver,
22 * which were used as the reference documentation for this implementation.
24 * Driver version we are currently based off of is
25 * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
27 ***********************************************************************
29 * This file is provided under a dual BSD/GPLv2 license. When using or
30 * redistributing this file, you may do so under either license.
34 * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
36 * This program is free software; you can redistribute it and/or modify
37 * it under the terms of version 2 of the GNU General Public License as
38 * published by the Free Software Foundation.
40 * This program is distributed in the hope that it will be useful, but
41 * WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 * General Public License for more details.
45 * You should have received a copy of the GNU General Public License
46 * along with this program; if not, write to the Free Software
47 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
50 * The full GNU General Public License is included in this distribution
51 * in the file called COPYING.
53 * Contact Information:
54 * Intel Linux Wireless <ilw@linux.intel.com>
55 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
60 * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
61 * All rights reserved.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
67 * * Redistributions of source code must retain the above copyright
68 * notice, this list of conditions and the following disclaimer.
69 * * Redistributions in binary form must reproduce the above copyright
70 * notice, this list of conditions and the following disclaimer in
71 * the documentation and/or other materials provided with the
73 * * Neither the name Intel Corporation nor the names of its
74 * contributors may be used to endorse or promote products derived
75 * from this software without specific prior written permission.
77 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
78 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
79 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
80 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
81 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
82 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
83 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
84 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
85 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
86 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
87 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91 * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
93 * Permission to use, copy, modify, and distribute this software for any
94 * purpose with or without fee is hereby granted, provided that the above
95 * copyright notice and this permission notice appear in all copies.
97 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
99 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
100 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
101 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
102 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
103 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
105 #include <sys/cdefs.h>
106 __FBSDID("$FreeBSD$");
108 #include <sys/param.h>
110 #include <sys/endian.h>
111 #include <sys/firmware.h>
112 #include <sys/kernel.h>
113 #include <sys/malloc.h>
114 #include <sys/mbuf.h>
115 #include <sys/rman.h>
116 #include <sys/sysctl.h>
117 #include <sys/linker.h>
119 #include <machine/endian.h>
121 #include <bus/pci/pcivar.h>
122 #include <bus/pci/pcireg.h>
127 #include <net/if_var.h>
128 #include <net/if_arp.h>
129 #include <net/if_dl.h>
130 #include <net/if_media.h>
131 #include <net/if_types.h>
133 #include <netinet/in.h>
134 #include <netinet/in_systm.h>
135 #include <netinet/if_ether.h>
136 #include <netinet/ip.h>
138 #include <netproto/802_11/ieee80211_var.h>
139 #include <netproto/802_11/ieee80211_regdomain.h>
140 #include <netproto/802_11/ieee80211_ratectl.h>
141 #include <netproto/802_11/ieee80211_radiotap.h>
143 #include "if_iwmreg.h"
144 #include "if_iwmvar.h"
145 #include "if_iwm_config.h"
146 #include "if_iwm_debug.h"
147 #include "if_iwm_binding.h"
148 #include "if_iwm_util.h"
149 #include "if_iwm_pcie_trans.h"
152 * Send a command to the firmware. We try to implement the Linux
153 * driver interface for the routine.
154 * mostly from if_iwn (iwn_cmd()).
156 * For now, we always copy the first part and map the second one (if it exists).
159 iwm_send_cmd(struct iwm_softc
*sc
, struct iwm_host_cmd
*hcmd
)
161 struct iwm_tx_ring
*ring
= &sc
->txq
[IWM_MVM_CMD_QUEUE
];
162 struct iwm_tfd
*desc
;
163 struct iwm_tx_data
*txdata
= NULL
;
164 struct iwm_device_cmd
*cmd
;
166 bus_dma_segment_t seg
;
169 int error
= 0, i
, paylen
, off
;
174 size_t hdrlen
, datasz
;
178 async
= hcmd
->flags
& IWM_CMD_ASYNC
;
179 wantresp
= hcmd
->flags
& IWM_CMD_WANT_SKB
;
182 for (i
= 0, paylen
= 0; i
< nitems(hcmd
->len
); i
++) {
183 paylen
+= hcmd
->len
[i
];
186 /* if the command wants an answer, busy sc_cmd_resp */
188 KASSERT(!async
, ("invalid async parameter"));
189 while (sc
->sc_wantresp
!= -1) {
190 #if defined(__DragonFly__)
191 lksleep(&sc
->sc_wantresp
, &sc
->sc_lk
, 0, "iwmcmdsl", 0);
193 msleep(&sc
->sc_wantresp
, &sc
->sc_mtx
, 0, "iwmcmdsl", 0);
196 sc
->sc_wantresp
= ring
->qid
<< 16 | ring
->cur
;
197 IWM_DPRINTF(sc
, IWM_DEBUG_CMD
,
198 "wantresp is %x\n", sc
->sc_wantresp
);
202 * Is the hardware still available? (after e.g. above wait).
204 if (sc
->sc_flags
& IWM_FLAG_STOPPED
) {
209 desc
= &ring
->desc
[ring
->cur
];
210 txdata
= &ring
->data
[ring
->cur
];
212 group_id
= iwm_cmd_groupid(code
);
214 hdrlen
= sizeof(cmd
->hdr_wide
);
215 datasz
= sizeof(cmd
->data_wide
);
217 hdrlen
= sizeof(cmd
->hdr
);
218 datasz
= sizeof(cmd
->data
);
221 if (paylen
> datasz
) {
222 IWM_DPRINTF(sc
, IWM_DEBUG_CMD
,
223 "large command paylen=%u len0=%u\n",
224 paylen
, hcmd
->len
[0]);
225 /* Command is too large */
226 size_t totlen
= hdrlen
+ paylen
;
227 if (paylen
> IWM_MAX_CMD_PAYLOAD_SIZE
) {
228 device_printf(sc
->sc_dev
,
229 "firmware command too long (%zd bytes)\n",
234 m
= m_getjcl(M_NOWAIT
, MT_DATA
, M_PKTHDR
, IWM_RBUF_SIZE
);
240 m
->m_len
= m
->m_pkthdr
.len
= m
->m_ext
.ext_size
;
241 #if defined(__DragonFly__)
242 error
= bus_dmamap_load_mbuf_segment(ring
->data_dmat
,
243 txdata
->map
, m
, &seg
, 1, &nsegs
, BUS_DMA_NOWAIT
);
245 error
= bus_dmamap_load_mbuf_sg(ring
->data_dmat
,
246 txdata
->map
, m
, &seg
, &nsegs
, BUS_DMA_NOWAIT
);
249 device_printf(sc
->sc_dev
,
250 "%s: can't map mbuf, error %d\n", __func__
, error
);
254 txdata
->m
= m
; /* mbuf will be freed in iwm_cmd_done() */
255 cmd
= mtod(m
, struct iwm_device_cmd
*);
258 cmd
= &ring
->cmd
[ring
->cur
];
259 paddr
= txdata
->cmd_paddr
;
263 cmd
->hdr_wide
.opcode
= iwm_cmd_opcode(code
);
264 cmd
->hdr_wide
.group_id
= group_id
;
265 cmd
->hdr_wide
.qid
= ring
->qid
;
266 cmd
->hdr_wide
.idx
= ring
->cur
;
267 cmd
->hdr_wide
.length
= htole16(paylen
);
268 cmd
->hdr_wide
.version
= iwm_cmd_version(code
);
269 data
= cmd
->data_wide
;
271 cmd
->hdr
.code
= iwm_cmd_opcode(code
);
273 cmd
->hdr
.qid
= ring
->qid
;
274 cmd
->hdr
.idx
= ring
->cur
;
278 for (i
= 0, off
= 0; i
< nitems(hcmd
->data
); i
++) {
279 if (hcmd
->len
[i
] == 0)
281 memcpy(data
+ off
, hcmd
->data
[i
], hcmd
->len
[i
]);
284 KASSERT(off
== paylen
, ("off %d != paylen %d", off
, paylen
));
286 /* lo field is not aligned */
287 addr_lo
= htole32((uint32_t)paddr
);
288 memcpy(&desc
->tbs
[0].lo
, &addr_lo
, sizeof(uint32_t));
289 desc
->tbs
[0].hi_n_len
= htole16(iwm_get_dma_hi_addr(paddr
)
290 | ((hdrlen
+ paylen
) << 4));
293 IWM_DPRINTF(sc
, IWM_DEBUG_CMD
,
294 "iwm_send_cmd 0x%x size=%lu %s\n",
296 (unsigned long) (hcmd
->len
[0] + hcmd
->len
[1] + hdrlen
),
297 async
? " (async)" : "");
299 if (paylen
> datasz
) {
300 bus_dmamap_sync(ring
->data_dmat
, txdata
->map
,
301 BUS_DMASYNC_PREWRITE
);
303 bus_dmamap_sync(ring
->cmd_dma
.tag
, ring
->cmd_dma
.map
,
304 BUS_DMASYNC_PREWRITE
);
306 bus_dmamap_sync(ring
->desc_dma
.tag
, ring
->desc_dma
.map
,
307 BUS_DMASYNC_PREWRITE
);
309 error
= iwm_pcie_set_cmd_in_flight(sc
);
315 iwm_update_sched(sc
, ring
->qid
, ring
->cur
, 0, 0);
317 IWM_DPRINTF(sc
, IWM_DEBUG_CMD
,
318 "sending command 0x%x qid %d, idx %d\n",
319 code
, ring
->qid
, ring
->cur
);
321 /* Kick command ring. */
322 ring
->cur
= (ring
->cur
+ 1) % IWM_TX_RING_COUNT
;
323 IWM_WRITE(sc
, IWM_HBUS_TARG_WRPTR
, ring
->qid
<< 8 | ring
->cur
);
326 /* m..m-mmyy-mmyyyy-mym-ym m-my generation */
327 int generation
= sc
->sc_generation
;
328 #if defined(__DragonFly__)
329 error
= lksleep(desc
, &sc
->sc_lk
, PCATCH
, "iwmcmd", hz
);
331 error
= msleep(desc
, &sc
->sc_mtx
, PCATCH
, "iwmcmd", hz
);
334 /* if hardware is no longer up, return error */
335 if (generation
!= sc
->sc_generation
) {
338 hcmd
->resp_pkt
= (void *)sc
->sc_cmd_resp
;
343 if (wantresp
&& error
!= 0) {
344 iwm_free_resp(sc
, hcmd
);
351 iwm_mvm_send_cmd_pdu(struct iwm_softc
*sc
, uint32_t id
,
352 uint32_t flags
, uint16_t len
, const void *data
)
354 struct iwm_host_cmd cmd
= {
361 return iwm_send_cmd(sc
, &cmd
);
365 iwm_mvm_send_cmd_status(struct iwm_softc
*sc
,
366 struct iwm_host_cmd
*cmd
, uint32_t *status
)
368 struct iwm_rx_packet
*pkt
;
369 struct iwm_cmd_response
*resp
;
372 KASSERT((cmd
->flags
& IWM_CMD_WANT_SKB
) == 0,
373 ("invalid command"));
374 cmd
->flags
|= IWM_CMD_SYNC
| IWM_CMD_WANT_SKB
;
376 if ((error
= iwm_send_cmd(sc
, cmd
)) != 0)
380 /* Can happen if RFKILL is asserted */
386 if (pkt
->hdr
.flags
& IWM_CMD_FAILED_MSK
) {
391 resp_len
= iwm_rx_packet_payload_len(pkt
);
392 if (resp_len
!= sizeof(*resp
)) {
397 resp
= (void *)pkt
->data
;
398 *status
= le32toh(resp
->status
);
400 iwm_free_resp(sc
, cmd
);
405 iwm_mvm_send_cmd_pdu_status(struct iwm_softc
*sc
, uint32_t id
,
406 uint16_t len
, const void *data
, uint32_t *status
)
408 struct iwm_host_cmd cmd
= {
414 return iwm_mvm_send_cmd_status(sc
, &cmd
, status
);
418 iwm_free_resp(struct iwm_softc
*sc
, struct iwm_host_cmd
*hcmd
)
420 KASSERT(sc
->sc_wantresp
!= -1, ("already freed"));
421 KASSERT((hcmd
->flags
& (IWM_CMD_WANT_SKB
|IWM_CMD_SYNC
))
422 == (IWM_CMD_WANT_SKB
|IWM_CMD_SYNC
), ("invalid flags"));
423 sc
->sc_wantresp
= -1;
424 wakeup(&sc
->sc_wantresp
);
427 #if !defined(__DragonFly__)
429 iwm_dma_map_addr(void *arg
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
433 KASSERT(nsegs
== 1, ("too many DMA segments, %d should be 1", nsegs
));
434 *(bus_addr_t
*)arg
= segs
[0].ds_addr
;
439 iwm_dma_contig_alloc(bus_dma_tag_t tag
, struct iwm_dma_info
*dma
,
440 bus_size_t size
, bus_size_t alignment
)
449 #if defined(__DragonFly__)
451 error
= bus_dmamem_coherent(tag
, alignment
, 0,
452 BUS_SPACE_MAXADDR_32BIT
,
454 size
, BUS_DMA_NOWAIT
, &dmem
);
458 dma
->tag
= dmem
.dmem_tag
;
459 dma
->map
= dmem
.dmem_map
;
460 dma
->vaddr
= dmem
.dmem_addr
;
461 dma
->paddr
= dmem
.dmem_busaddr
;
463 error
= bus_dma_tag_create(tag
, alignment
,
464 0, BUS_SPACE_MAXADDR_32BIT
, BUS_SPACE_MAXADDR
, NULL
, NULL
, size
,
465 1, size
, 0, NULL
, NULL
, &dma
->tag
);
469 error
= bus_dmamem_alloc(dma
->tag
, (void **)&dma
->vaddr
,
470 BUS_DMA_NOWAIT
| BUS_DMA_ZERO
| BUS_DMA_COHERENT
, &dma
->map
);
474 error
= bus_dmamap_load(dma
->tag
, dma
->map
, dma
->vaddr
, size
,
475 iwm_dma_map_addr
, &dma
->paddr
, BUS_DMA_NOWAIT
);
477 bus_dmamem_free(dma
->tag
, dma
->vaddr
, dma
->map
);
483 bus_dmamap_sync(dma
->tag
, dma
->map
, BUS_DMASYNC_PREWRITE
);
488 iwm_dma_contig_free(dma
);
494 iwm_dma_contig_free(struct iwm_dma_info
*dma
)
496 if (dma
->vaddr
!= NULL
) {
497 bus_dmamap_sync(dma
->tag
, dma
->map
,
498 BUS_DMASYNC_POSTREAD
| BUS_DMASYNC_POSTWRITE
);
499 bus_dmamap_unload(dma
->tag
, dma
->map
);
500 bus_dmamem_free(dma
->tag
, dma
->vaddr
, dma
->map
);
503 if (dma
->tag
!= NULL
) {
504 bus_dma_tag_destroy(dma
->tag
);
510 * iwm_mvm_send_lq_cmd() - Send link quality command
511 * @init: This command is sent as part of station initialization right
512 * after station has been added.
514 * The link quality command is sent as the last step of station creation.
515 * This is the special case in which init is set and we call a callback in
516 * this case to clear the state indicating that station creation is in
520 iwm_mvm_send_lq_cmd(struct iwm_softc
*sc
, struct iwm_lq_cmd
*lq
, boolean_t init
)
522 struct iwm_host_cmd cmd
= {
524 .len
= { sizeof(struct iwm_lq_cmd
), },
525 .flags
= init
? 0 : IWM_CMD_ASYNC
,
529 if (lq
->sta_id
== IWM_MVM_STATION_COUNT
)
532 return iwm_send_cmd(sc
, &cmd
);
536 iwm_mvm_rx_diversity_allowed(struct iwm_softc
*sc
)
538 if (num_of_ant(iwm_mvm_get_valid_rx_ant(sc
)) == 1)
542 * XXX Also return FALSE when SMPS (Spatial Multiplexing Powersave)
543 * is used on any vap (in the future).