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/param.h>
107 #include <sys/conf.h>
108 #include <sys/endian.h>
109 #include <sys/firmware.h>
110 #include <sys/kernel.h>
111 #include <sys/malloc.h>
112 #include <sys/mbuf.h>
113 #include <sys/rman.h>
114 #include <sys/sysctl.h>
115 #include <sys/linker.h>
117 #include <machine/endian.h>
119 #include <bus/pci/pcivar.h>
120 #include <bus/pci/pcireg.h>
125 #include <net/if_var.h>
126 #include <net/if_arp.h>
127 #include <net/if_dl.h>
128 #include <net/if_media.h>
129 #include <net/if_types.h>
131 #include <netinet/in.h>
132 #include <netinet/in_systm.h>
133 #include <netinet/if_ether.h>
134 #include <netinet/ip.h>
136 #include <netproto/802_11/ieee80211_var.h>
137 #include <netproto/802_11/ieee80211_regdomain.h>
138 #include <netproto/802_11/ieee80211_ratectl.h>
139 #include <netproto/802_11/ieee80211_radiotap.h>
141 #include "if_iwmreg.h"
142 #include "if_iwmvar.h"
143 #include "if_iwm_debug.h"
144 #include "if_iwm_util.h"
145 #include "if_iwm_phy_db.h"
147 #define CHANNEL_NUM_SIZE 4 /* num of channels in calib_ch size */
149 struct iwm_phy_db_entry
{
155 * struct iwm_phy_db - stores phy configuration and calibration data.
157 * @cfg: phy configuration.
158 * @calib_nch: non channel specific calibration data.
159 * @calib_ch: channel specific calibration data.
160 * @n_group_papd: number of entries in papd channel group.
161 * @calib_ch_group_papd: calibration data related to papd channel group.
162 * @n_group_txp: number of entries in tx power channel group.
163 * @calib_ch_group_txp: calibration data related to tx power chanel group.
166 struct iwm_phy_db_entry cfg
;
167 struct iwm_phy_db_entry calib_nch
;
169 struct iwm_phy_db_entry
*calib_ch_group_papd
;
171 struct iwm_phy_db_entry
*calib_ch_group_txp
;
173 struct iwm_softc
*sc
;
177 iwm_phy_db_init(struct iwm_softc
*sc
)
179 struct iwm_phy_db
*phy_db
= kmalloc(sizeof(struct iwm_phy_db
),
180 M_DEVBUF
, M_WAITOK
| M_ZERO
);
187 phy_db
->n_group_txp
= -1;
188 phy_db
->n_group_papd
= -1;
190 /* TODO: add default values of the phy db. */
195 * get phy db section: returns a pointer to a phy db section specified by
196 * type and channel group id.
198 static struct iwm_phy_db_entry
*
199 iwm_phy_db_get_section(struct iwm_phy_db
*phy_db
,
200 enum iwm_phy_db_section_type type
,
203 if (!phy_db
|| type
>= IWM_PHY_DB_MAX
)
209 case IWM_PHY_DB_CALIB_NCH
:
210 return &phy_db
->calib_nch
;
211 case IWM_PHY_DB_CALIB_CHG_PAPD
:
212 if (chg_id
>= phy_db
->n_group_papd
)
214 return &phy_db
->calib_ch_group_papd
[chg_id
];
215 case IWM_PHY_DB_CALIB_CHG_TXP
:
216 if (chg_id
>= phy_db
->n_group_txp
)
218 return &phy_db
->calib_ch_group_txp
[chg_id
];
226 iwm_phy_db_free_section(struct iwm_phy_db
*phy_db
,
227 enum iwm_phy_db_section_type type
, uint16_t chg_id
)
229 struct iwm_phy_db_entry
*entry
=
230 iwm_phy_db_get_section(phy_db
, type
, chg_id
);
234 if (entry
->data
!= NULL
)
235 kfree(entry
->data
, M_DEVBUF
);
241 iwm_phy_db_free(struct iwm_phy_db
*phy_db
)
248 iwm_phy_db_free_section(phy_db
, IWM_PHY_DB_CFG
, 0);
249 iwm_phy_db_free_section(phy_db
, IWM_PHY_DB_CALIB_NCH
, 0);
251 for (i
= 0; i
< phy_db
->n_group_papd
; i
++)
252 iwm_phy_db_free_section(phy_db
, IWM_PHY_DB_CALIB_CHG_PAPD
, i
);
253 if (phy_db
->calib_ch_group_papd
!= NULL
)
254 kfree(phy_db
->calib_ch_group_papd
, M_DEVBUF
);
256 for (i
= 0; i
< phy_db
->n_group_txp
; i
++)
257 iwm_phy_db_free_section(phy_db
, IWM_PHY_DB_CALIB_CHG_TXP
, i
);
258 if (phy_db
->calib_ch_group_txp
!= NULL
)
259 kfree(phy_db
->calib_ch_group_txp
, M_DEVBUF
);
261 kfree(phy_db
, M_DEVBUF
);
265 iwm_phy_db_set_section(struct iwm_phy_db
*phy_db
,
266 struct iwm_rx_packet
*pkt
)
268 struct iwm_calib_res_notif_phy_db
*phy_db_notif
=
269 (struct iwm_calib_res_notif_phy_db
*)pkt
->data
;
270 enum iwm_phy_db_section_type type
= le16toh(phy_db_notif
->type
);
271 uint16_t size
= le16toh(phy_db_notif
->length
);
272 struct iwm_phy_db_entry
*entry
;
278 if (type
== IWM_PHY_DB_CALIB_CHG_PAPD
) {
279 chg_id
= le16toh(*(uint16_t *)phy_db_notif
->data
);
280 if (phy_db
&& !phy_db
->calib_ch_group_papd
) {
282 * Firmware sends the largest index first, so we can use
283 * it to know how much we should allocate.
285 phy_db
->calib_ch_group_papd
= kmalloc(
286 (chg_id
+ 1) * sizeof(struct iwm_phy_db_entry
),
287 M_DEVBUF
, M_WAITOK
| M_ZERO
);
288 if (!phy_db
->calib_ch_group_papd
)
290 phy_db
->n_group_papd
= chg_id
+ 1;
292 } else if (type
== IWM_PHY_DB_CALIB_CHG_TXP
) {
293 chg_id
= le16toh(*(uint16_t *)phy_db_notif
->data
);
294 if (phy_db
&& !phy_db
->calib_ch_group_txp
) {
296 * Firmware sends the largest index first, so we can use
297 * it to know how much we should allocate.
299 phy_db
->calib_ch_group_txp
= kmalloc(
300 (chg_id
+ 1) * sizeof(struct iwm_phy_db_entry
),
301 M_DEVBUF
, M_WAITOK
| M_ZERO
);
302 if (!phy_db
->calib_ch_group_txp
)
304 phy_db
->n_group_txp
= chg_id
+ 1;
308 entry
= iwm_phy_db_get_section(phy_db
, type
, chg_id
);
312 if (entry
->data
!= NULL
)
313 kfree(entry
->data
, M_DEVBUF
);
314 entry
->data
= kmalloc(size
, M_DEVBUF
, M_WAITOK
);
319 memcpy(entry
->data
, phy_db_notif
->data
, size
);
323 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_RESET
,
324 "%s(%d): [PHYDB]SET: Type %d , Size: %d\n",
325 __func__
, __LINE__
, type
, size
);
331 is_valid_channel(uint16_t ch_id
)
334 (36 <= ch_id
&& ch_id
<= 64 && ch_id
% 4 == 0) ||
335 (100 <= ch_id
&& ch_id
<= 140 && ch_id
% 4 == 0) ||
336 (145 <= ch_id
&& ch_id
<= 165 && ch_id
% 4 == 1))
342 ch_id_to_ch_index(uint16_t ch_id
)
344 if (!is_valid_channel(ch_id
))
350 return (ch_id
+ 20) / 4;
352 return (ch_id
- 12) / 4;
353 return (ch_id
- 13) / 4;
358 channel_id_to_papd(uint16_t ch_id
)
360 if (!is_valid_channel(ch_id
))
363 if (1 <= ch_id
&& ch_id
<= 14)
365 if (36 <= ch_id
&& ch_id
<= 64)
367 if (100 <= ch_id
&& ch_id
<= 140)
373 channel_id_to_txp(struct iwm_phy_db
*phy_db
, uint16_t ch_id
)
375 struct iwm_phy_db_chg_txp
*txp_chg
;
377 uint8_t ch_index
= ch_id_to_ch_index(ch_id
);
378 if (ch_index
== 0xff)
381 for (i
= 0; i
< phy_db
->n_group_txp
; i
++) {
382 txp_chg
= (void *)phy_db
->calib_ch_group_txp
[i
].data
;
386 * Looking for the first channel group that its max channel is
387 * higher then wanted channel.
389 if (le16toh(txp_chg
->max_channel_idx
) >= ch_index
)
396 iwm_phy_db_get_section_data(struct iwm_phy_db
*phy_db
,
397 uint32_t type
, uint8_t **data
, uint16_t *size
,
400 struct iwm_phy_db_entry
*entry
;
401 uint16_t ch_group_id
= 0;
406 /* find wanted channel group */
407 if (type
== IWM_PHY_DB_CALIB_CHG_PAPD
)
408 ch_group_id
= channel_id_to_papd(ch_id
);
409 else if (type
== IWM_PHY_DB_CALIB_CHG_TXP
)
410 ch_group_id
= channel_id_to_txp(phy_db
, ch_id
);
412 entry
= iwm_phy_db_get_section(phy_db
, type
, ch_group_id
);
419 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_RESET
,
420 "%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
421 __func__
, __LINE__
, type
, *size
);
427 iwm_send_phy_db_cmd(struct iwm_phy_db
*phy_db
, uint16_t type
,
428 uint16_t length
, void *data
)
430 struct iwm_phy_db_cmd phy_db_cmd
;
431 struct iwm_host_cmd cmd
= {
432 .id
= IWM_PHY_DB_CMD
,
435 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_RESET
,
436 "Sending PHY-DB hcmd of type %d, of length %d\n",
439 /* Set phy db cmd variables */
440 phy_db_cmd
.type
= htole16(type
);
441 phy_db_cmd
.length
= htole16(length
);
443 /* Set hcmd variables */
444 cmd
.data
[0] = &phy_db_cmd
;
445 cmd
.len
[0] = sizeof(struct iwm_phy_db_cmd
);
449 cmd
.dataflags
[1] = IWM_HCMD_DFL_NOCOPY
;
452 return iwm_send_cmd(phy_db
->sc
, &cmd
);
456 iwm_phy_db_send_all_channel_groups(struct iwm_phy_db
*phy_db
,
457 enum iwm_phy_db_section_type type
,
458 uint8_t max_ch_groups
)
462 struct iwm_phy_db_entry
*entry
;
464 /* Send all the channel specific groups to operational fw */
465 for (i
= 0; i
< max_ch_groups
; i
++) {
466 entry
= iwm_phy_db_get_section(phy_db
,
475 /* Send the requested PHY DB section */
476 err
= iwm_send_phy_db_cmd(phy_db
,
481 device_printf(phy_db
->sc
->sc_dev
,
482 "Can't SEND phy_db section %d (%d), err %d\n",
487 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_CMD
,
488 "Sent PHY_DB HCMD, type = %d num = %d\n", type
, i
);
495 iwm_send_phy_db_data(struct iwm_phy_db
*phy_db
)
497 uint8_t *data
= NULL
;
501 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_CMD
| IWM_DEBUG_RESET
,
502 "%s: Sending phy db data and configuration to runtime image\n",
505 /* Send PHY DB CFG section */
506 err
= iwm_phy_db_get_section_data(phy_db
, IWM_PHY_DB_CFG
,
509 device_printf(phy_db
->sc
->sc_dev
,
510 "%s: Cannot get Phy DB cfg section, %d\n",
515 err
= iwm_send_phy_db_cmd(phy_db
, IWM_PHY_DB_CFG
, size
, data
);
517 device_printf(phy_db
->sc
->sc_dev
,
518 "%s: Cannot send HCMD of Phy DB cfg section, %d\n",
523 err
= iwm_phy_db_get_section_data(phy_db
, IWM_PHY_DB_CALIB_NCH
,
526 device_printf(phy_db
->sc
->sc_dev
,
527 "%s: Cannot get Phy DB non specific channel section, "
528 "%d\n", __func__
, err
);
532 err
= iwm_send_phy_db_cmd(phy_db
, IWM_PHY_DB_CALIB_NCH
, size
, data
);
534 device_printf(phy_db
->sc
->sc_dev
,
535 "%s: Cannot send HCMD of Phy DB non specific channel "
536 "sect, %d\n", __func__
, err
);
540 /* Send all the TXP channel specific data */
541 err
= iwm_phy_db_send_all_channel_groups(phy_db
,
542 IWM_PHY_DB_CALIB_CHG_PAPD
, phy_db
->n_group_papd
);
544 device_printf(phy_db
->sc
->sc_dev
,
545 "%s: Cannot send channel specific PAPD groups, %d\n",
550 /* Send all the TXP channel specific data */
551 err
= iwm_phy_db_send_all_channel_groups(phy_db
,
552 IWM_PHY_DB_CALIB_CHG_TXP
, phy_db
->n_group_txp
);
554 device_printf(phy_db
->sc
->sc_dev
,
555 "%s: Cannot send channel specific TX power groups, "
556 "%d\n", __func__
, err
);
560 IWM_DPRINTF(phy_db
->sc
, IWM_DEBUG_CMD
| IWM_DEBUG_RESET
,
561 "%s: Finished sending phy db non channel data\n",