diff options
| author | David S. Miller <davem@davemloft.net> | 2009-03-27 20:35:07 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-03-27 20:35:07 -0400 |
| commit | 0870352bc6e0dee485c86a0c99dd60e7089c8917 (patch) | |
| tree | 0c6259b663350594bff4f128e12f8bd6d4c769c1 /drivers | |
| parent | c44a4366649aca4f5b4a51ff71d4c9cde3b7c9da (diff) | |
| parent | 8a5117d80fe93de5df5b56480054f7df1fd20755 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Diffstat (limited to 'drivers')
80 files changed, 7825 insertions, 925 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 612fffe100a6..8a0823588c51 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
| @@ -485,6 +485,7 @@ config MWL8K | |||
| 485 | source "drivers/net/wireless/p54/Kconfig" | 485 | source "drivers/net/wireless/p54/Kconfig" |
| 486 | source "drivers/net/wireless/ath5k/Kconfig" | 486 | source "drivers/net/wireless/ath5k/Kconfig" |
| 487 | source "drivers/net/wireless/ath9k/Kconfig" | 487 | source "drivers/net/wireless/ath9k/Kconfig" |
| 488 | source "drivers/net/wireless/ar9170/Kconfig" | ||
| 488 | source "drivers/net/wireless/ipw2x00/Kconfig" | 489 | source "drivers/net/wireless/ipw2x00/Kconfig" |
| 489 | source "drivers/net/wireless/iwlwifi/Kconfig" | 490 | source "drivers/net/wireless/iwlwifi/Kconfig" |
| 490 | source "drivers/net/wireless/hostap/Kconfig" | 491 | source "drivers/net/wireless/hostap/Kconfig" |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index d780487c420f..50e7fba7f0ea 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
| @@ -57,5 +57,6 @@ obj-$(CONFIG_P54_COMMON) += p54/ | |||
| 57 | 57 | ||
| 58 | obj-$(CONFIG_ATH5K) += ath5k/ | 58 | obj-$(CONFIG_ATH5K) += ath5k/ |
| 59 | obj-$(CONFIG_ATH9K) += ath9k/ | 59 | obj-$(CONFIG_ATH9K) += ath9k/ |
| 60 | obj-$(CONFIG_AR9170_USB) += ar9170/ | ||
| 60 | 61 | ||
| 61 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o | 62 | obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o |
diff --git a/drivers/net/wireless/ar9170/Kconfig b/drivers/net/wireless/ar9170/Kconfig new file mode 100644 index 000000000000..de4281fda129 --- /dev/null +++ b/drivers/net/wireless/ar9170/Kconfig | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | config AR9170_USB | ||
| 2 | tristate "Atheros AR9170 802.11n USB support" | ||
| 3 | depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL | ||
| 4 | select FW_LOADER | ||
| 5 | help | ||
| 6 | This is a driver for the Atheros "otus" 802.11n USB devices. | ||
| 7 | |||
| 8 | These devices require additional firmware (2 files). | ||
| 9 | For now, these files can be downloaded from here: | ||
| 10 | http://wireless.kernel.org/en/users/Drivers/ar9170 | ||
| 11 | |||
| 12 | If you choose to build a module, it'll be called ar9170usb. | ||
| 13 | |||
| 14 | config AR9170_LEDS | ||
| 15 | bool | ||
| 16 | depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB) | ||
| 17 | default y | ||
diff --git a/drivers/net/wireless/ar9170/Makefile b/drivers/net/wireless/ar9170/Makefile new file mode 100644 index 000000000000..8d91c7ee3215 --- /dev/null +++ b/drivers/net/wireless/ar9170/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o | ||
| 2 | |||
| 3 | obj-$(CONFIG_AR9170_USB) += ar9170usb.o | ||
diff --git a/drivers/net/wireless/ar9170/ar9170.h b/drivers/net/wireless/ar9170/ar9170.h new file mode 100644 index 000000000000..f4fb2e94aea0 --- /dev/null +++ b/drivers/net/wireless/ar9170/ar9170.h | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * Driver specific definitions | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | #ifndef __AR9170_H | ||
| 39 | #define __AR9170_H | ||
| 40 | |||
| 41 | #include <linux/completion.h> | ||
| 42 | #include <linux/spinlock.h> | ||
| 43 | #include <net/wireless.h> | ||
| 44 | #include <net/mac80211.h> | ||
| 45 | #ifdef CONFIG_AR9170_LEDS | ||
| 46 | #include <linux/leds.h> | ||
| 47 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 48 | #include "eeprom.h" | ||
| 49 | #include "hw.h" | ||
| 50 | |||
| 51 | #define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1) | ||
| 52 | |||
| 53 | enum ar9170_bw { | ||
| 54 | AR9170_BW_20, | ||
| 55 | AR9170_BW_40_BELOW, | ||
| 56 | AR9170_BW_40_ABOVE, | ||
| 57 | |||
| 58 | __AR9170_NUM_BW, | ||
| 59 | }; | ||
| 60 | |||
| 61 | enum ar9170_rf_init_mode { | ||
| 62 | AR9170_RFI_NONE, | ||
| 63 | AR9170_RFI_WARM, | ||
| 64 | AR9170_RFI_COLD, | ||
| 65 | }; | ||
| 66 | |||
| 67 | #define AR9170_MAX_RX_BUFFER_SIZE 8192 | ||
| 68 | |||
| 69 | #ifdef CONFIG_AR9170_LEDS | ||
| 70 | struct ar9170; | ||
| 71 | |||
| 72 | struct ar9170_led { | ||
| 73 | struct ar9170 *ar; | ||
| 74 | struct led_classdev l; | ||
| 75 | char name[32]; | ||
| 76 | unsigned int toggled; | ||
| 77 | bool registered; | ||
| 78 | }; | ||
| 79 | |||
| 80 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 81 | |||
| 82 | enum ar9170_device_state { | ||
| 83 | AR9170_UNKNOWN_STATE, | ||
| 84 | AR9170_STOPPED, | ||
| 85 | AR9170_IDLE, | ||
| 86 | AR9170_STARTED, | ||
| 87 | AR9170_ASSOCIATED, | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct ar9170 { | ||
| 91 | struct ieee80211_hw *hw; | ||
| 92 | struct mutex mutex; | ||
| 93 | enum ar9170_device_state state; | ||
| 94 | |||
| 95 | int (*open)(struct ar9170 *); | ||
| 96 | void (*stop)(struct ar9170 *); | ||
| 97 | int (*tx)(struct ar9170 *, struct sk_buff *, bool, unsigned int); | ||
| 98 | int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 , | ||
| 99 | void *, u32 , void *); | ||
| 100 | void (*callback_cmd)(struct ar9170 *, u32 , void *); | ||
| 101 | |||
| 102 | /* interface mode settings */ | ||
| 103 | struct ieee80211_vif *vif; | ||
| 104 | u8 mac_addr[ETH_ALEN]; | ||
| 105 | u8 bssid[ETH_ALEN]; | ||
| 106 | |||
| 107 | /* beaconing */ | ||
| 108 | struct sk_buff *beacon; | ||
| 109 | struct work_struct beacon_work; | ||
| 110 | |||
| 111 | /* cryptographic engine */ | ||
| 112 | u64 usedkeys; | ||
| 113 | bool rx_software_decryption; | ||
| 114 | bool disable_offload; | ||
| 115 | |||
| 116 | /* filter settings */ | ||
| 117 | struct work_struct filter_config_work; | ||
| 118 | u64 cur_mc_hash, want_mc_hash; | ||
| 119 | u32 cur_filter, want_filter; | ||
| 120 | unsigned int filter_changed; | ||
| 121 | bool sniffer_enabled; | ||
| 122 | |||
| 123 | /* PHY */ | ||
| 124 | struct ieee80211_channel *channel; | ||
| 125 | int noise[4]; | ||
| 126 | |||
| 127 | /* power calibration data */ | ||
| 128 | u8 power_5G_leg[4]; | ||
| 129 | u8 power_2G_cck[4]; | ||
| 130 | u8 power_2G_ofdm[4]; | ||
| 131 | u8 power_5G_ht20[8]; | ||
| 132 | u8 power_5G_ht40[8]; | ||
| 133 | u8 power_2G_ht20[8]; | ||
| 134 | u8 power_2G_ht40[8]; | ||
| 135 | |||
| 136 | #ifdef CONFIG_AR9170_LEDS | ||
| 137 | struct delayed_work led_work; | ||
| 138 | struct ar9170_led leds[AR9170_NUM_LEDS]; | ||
| 139 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 140 | |||
| 141 | /* qos queue settings */ | ||
| 142 | spinlock_t tx_stats_lock; | ||
| 143 | struct ieee80211_tx_queue_stats tx_stats[5]; | ||
| 144 | struct ieee80211_tx_queue_params edcf[5]; | ||
| 145 | |||
| 146 | spinlock_t cmdlock; | ||
| 147 | __le32 cmdbuf[PAYLOAD_MAX + 1]; | ||
| 148 | |||
| 149 | /* MAC statistics */ | ||
| 150 | struct ieee80211_low_level_stats stats; | ||
| 151 | |||
| 152 | /* EEPROM */ | ||
| 153 | struct ar9170_eeprom eeprom; | ||
| 154 | |||
| 155 | /* global tx status for unregistered Stations. */ | ||
| 156 | struct sk_buff_head global_tx_status; | ||
| 157 | struct sk_buff_head global_tx_status_waste; | ||
| 158 | struct delayed_work tx_status_janitor; | ||
| 159 | }; | ||
| 160 | |||
| 161 | struct ar9170_sta_info { | ||
| 162 | struct sk_buff_head tx_status[__AR9170_NUM_TXQ]; | ||
| 163 | }; | ||
| 164 | |||
| 165 | #define IS_STARTED(a) (a->state >= AR9170_STARTED) | ||
| 166 | #define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE) | ||
| 167 | |||
| 168 | #define AR9170_FILTER_CHANGED_PROMISC BIT(0) | ||
| 169 | #define AR9170_FILTER_CHANGED_MULTICAST BIT(1) | ||
| 170 | #define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2) | ||
| 171 | |||
| 172 | /* exported interface */ | ||
| 173 | void *ar9170_alloc(size_t priv_size); | ||
| 174 | int ar9170_register(struct ar9170 *ar, struct device *pdev); | ||
| 175 | void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb); | ||
| 176 | void ar9170_unregister(struct ar9170 *ar); | ||
| 177 | void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, | ||
| 178 | bool update_statistics, u16 tx_status); | ||
| 179 | |||
| 180 | /* MAC */ | ||
| 181 | int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | ||
| 182 | int ar9170_init_mac(struct ar9170 *ar); | ||
| 183 | int ar9170_set_qos(struct ar9170 *ar); | ||
| 184 | int ar9170_update_multicast(struct ar9170 *ar); | ||
| 185 | int ar9170_update_frame_filter(struct ar9170 *ar); | ||
| 186 | int ar9170_set_operating_mode(struct ar9170 *ar); | ||
| 187 | int ar9170_set_beacon_timers(struct ar9170 *ar); | ||
| 188 | int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry); | ||
| 189 | int ar9170_update_beacon(struct ar9170 *ar); | ||
| 190 | void ar9170_new_beacon(struct work_struct *work); | ||
| 191 | int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, | ||
| 192 | u8 keyidx, u8 *keydata, int keylen); | ||
| 193 | int ar9170_disable_key(struct ar9170 *ar, u8 id); | ||
| 194 | |||
| 195 | /* LEDs */ | ||
| 196 | #ifdef CONFIG_AR9170_LEDS | ||
| 197 | int ar9170_register_leds(struct ar9170 *ar); | ||
| 198 | void ar9170_unregister_leds(struct ar9170 *ar); | ||
| 199 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 200 | int ar9170_init_leds(struct ar9170 *ar); | ||
| 201 | int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state); | ||
| 202 | |||
| 203 | /* PHY / RF */ | ||
| 204 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band); | ||
| 205 | int ar9170_init_rf(struct ar9170 *ar); | ||
| 206 | int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | ||
| 207 | enum ar9170_rf_init_mode rfi, enum ar9170_bw bw); | ||
| 208 | |||
| 209 | #endif /* __AR9170_H */ | ||
diff --git a/drivers/net/wireless/ar9170/cmd.c b/drivers/net/wireless/ar9170/cmd.c new file mode 100644 index 000000000000..f57a6200167b --- /dev/null +++ b/drivers/net/wireless/ar9170/cmd.c | |||
| @@ -0,0 +1,129 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * Basic HW register/memory/command access functions | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | |||
| 39 | #include "ar9170.h" | ||
| 40 | #include "cmd.h" | ||
| 41 | |||
| 42 | int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len) | ||
| 43 | { | ||
| 44 | int err; | ||
| 45 | |||
| 46 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 47 | return 0; | ||
| 48 | |||
| 49 | err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL); | ||
| 50 | if (err) | ||
| 51 | printk(KERN_DEBUG "%s: writing memory failed\n", | ||
| 52 | wiphy_name(ar->hw->wiphy)); | ||
| 53 | return err; | ||
| 54 | } | ||
| 55 | |||
| 56 | int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val) | ||
| 57 | { | ||
| 58 | __le32 buf[2] = { | ||
| 59 | cpu_to_le32(reg), | ||
| 60 | cpu_to_le32(val), | ||
| 61 | }; | ||
| 62 | int err; | ||
| 63 | |||
| 64 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 65 | return 0; | ||
| 66 | |||
| 67 | err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf), | ||
| 68 | (u8 *) buf, 0, NULL); | ||
| 69 | if (err) | ||
| 70 | printk(KERN_DEBUG "%s: writing reg %#x (val %#x) failed\n", | ||
| 71 | wiphy_name(ar->hw->wiphy), reg, val); | ||
| 72 | return err; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int ar9170_read_mreg(struct ar9170 *ar, int nregs, | ||
| 76 | const u32 *regs, u32 *out) | ||
| 77 | { | ||
| 78 | int i, err; | ||
| 79 | __le32 *offs, *res; | ||
| 80 | |||
| 81 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 82 | return 0; | ||
| 83 | |||
| 84 | /* abuse "out" for the register offsets, must be same length */ | ||
| 85 | offs = (__le32 *)out; | ||
| 86 | for (i = 0; i < nregs; i++) | ||
| 87 | offs[i] = cpu_to_le32(regs[i]); | ||
| 88 | |||
| 89 | /* also use the same buffer for the input */ | ||
| 90 | res = (__le32 *)out; | ||
| 91 | |||
| 92 | err = ar->exec_cmd(ar, AR9170_CMD_RREG, | ||
| 93 | 4 * nregs, (u8 *)offs, | ||
| 94 | 4 * nregs, (u8 *)res); | ||
| 95 | if (err) | ||
| 96 | return err; | ||
| 97 | |||
| 98 | /* convert result to cpu endian */ | ||
| 99 | for (i = 0; i < nregs; i++) | ||
| 100 | out[i] = le32_to_cpu(res[i]); | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val) | ||
| 106 | { | ||
| 107 | return ar9170_read_mreg(ar, 1, ®, val); | ||
| 108 | } | ||
| 109 | |||
| 110 | int ar9170_echo_test(struct ar9170 *ar, u32 v) | ||
| 111 | { | ||
| 112 | __le32 echobuf = cpu_to_le32(v); | ||
| 113 | __le32 echores; | ||
| 114 | int err; | ||
| 115 | |||
| 116 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 117 | return -ENODEV; | ||
| 118 | |||
| 119 | err = ar->exec_cmd(ar, AR9170_CMD_ECHO, | ||
| 120 | 4, (u8 *)&echobuf, | ||
| 121 | 4, (u8 *)&echores); | ||
| 122 | if (err) | ||
| 123 | return err; | ||
| 124 | |||
| 125 | if (echobuf != echores) | ||
| 126 | return -EINVAL; | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
diff --git a/drivers/net/wireless/ar9170/cmd.h b/drivers/net/wireless/ar9170/cmd.h new file mode 100644 index 000000000000..a4f0e50e52b4 --- /dev/null +++ b/drivers/net/wireless/ar9170/cmd.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * Basic HW register/memory/command access functions | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | #ifndef __CMD_H | ||
| 39 | #define __CMD_H | ||
| 40 | |||
| 41 | #include "ar9170.h" | ||
| 42 | |||
| 43 | /* basic HW access */ | ||
| 44 | int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len); | ||
| 45 | int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); | ||
| 46 | int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val); | ||
| 47 | int ar9170_echo_test(struct ar9170 *ar, u32 v); | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Macros to facilitate writing multiple registers in a single | ||
| 51 | * write-combining USB command. Note that when the first group | ||
| 52 | * fails the whole thing will fail without any others attempted, | ||
| 53 | * but you won't know which write in the group failed. | ||
| 54 | */ | ||
| 55 | #define ar9170_regwrite_begin(ar) \ | ||
| 56 | do { \ | ||
| 57 | int __nreg = 0, __err = 0; \ | ||
| 58 | struct ar9170 *__ar = ar; | ||
| 59 | |||
| 60 | #define ar9170_regwrite(r, v) do { \ | ||
| 61 | __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \ | ||
| 62 | __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \ | ||
| 63 | __nreg++; \ | ||
| 64 | if ((__nreg >= PAYLOAD_MAX/2)) { \ | ||
| 65 | if (IS_ACCEPTING_CMD(__ar)) \ | ||
| 66 | __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ | ||
| 67 | 8 * __nreg, \ | ||
| 68 | (u8 *) &__ar->cmdbuf[1], \ | ||
| 69 | 0, NULL); \ | ||
| 70 | __nreg = 0; \ | ||
| 71 | if (__err) \ | ||
| 72 | goto __regwrite_out; \ | ||
| 73 | } \ | ||
| 74 | } while (0) | ||
| 75 | |||
| 76 | #define ar9170_regwrite_finish() \ | ||
| 77 | __regwrite_out : \ | ||
| 78 | if (__nreg) { \ | ||
| 79 | if (IS_ACCEPTING_CMD(__ar)) \ | ||
| 80 | __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \ | ||
| 81 | 8 * __nreg, \ | ||
| 82 | (u8 *) &__ar->cmdbuf[1], \ | ||
| 83 | 0, NULL); \ | ||
| 84 | __nreg = 0; \ | ||
| 85 | } | ||
| 86 | |||
| 87 | #define ar9170_regwrite_result() \ | ||
| 88 | __err; \ | ||
| 89 | } while (0); | ||
| 90 | |||
| 91 | #endif /* __CMD_H */ | ||
diff --git a/drivers/net/wireless/ar9170/eeprom.h b/drivers/net/wireless/ar9170/eeprom.h new file mode 100644 index 000000000000..d2c8cc83f1dd --- /dev/null +++ b/drivers/net/wireless/ar9170/eeprom.h | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * EEPROM layout | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | #ifndef __AR9170_EEPROM_H | ||
| 39 | #define __AR9170_EEPROM_H | ||
| 40 | |||
| 41 | #define AR5416_MAX_CHAINS 2 | ||
| 42 | #define AR5416_MODAL_SPURS 5 | ||
| 43 | |||
| 44 | struct ar9170_eeprom_modal { | ||
| 45 | __le32 antCtrlChain[AR5416_MAX_CHAINS]; | ||
| 46 | __le32 antCtrlCommon; | ||
| 47 | s8 antennaGainCh[AR5416_MAX_CHAINS]; | ||
| 48 | u8 switchSettling; | ||
| 49 | u8 txRxAttenCh[AR5416_MAX_CHAINS]; | ||
| 50 | u8 rxTxMarginCh[AR5416_MAX_CHAINS]; | ||
| 51 | s8 adcDesiredSize; | ||
| 52 | s8 pgaDesiredSize; | ||
| 53 | u8 xlnaGainCh[AR5416_MAX_CHAINS]; | ||
| 54 | u8 txEndToXpaOff; | ||
| 55 | u8 txEndToRxOn; | ||
| 56 | u8 txFrameToXpaOn; | ||
| 57 | u8 thresh62; | ||
| 58 | s8 noiseFloorThreshCh[AR5416_MAX_CHAINS]; | ||
| 59 | u8 xpdGain; | ||
| 60 | u8 xpd; | ||
| 61 | s8 iqCalICh[AR5416_MAX_CHAINS]; | ||
| 62 | s8 iqCalQCh[AR5416_MAX_CHAINS]; | ||
| 63 | u8 pdGainOverlap; | ||
| 64 | u8 ob; | ||
| 65 | u8 db; | ||
| 66 | u8 xpaBiasLvl; | ||
| 67 | u8 pwrDecreaseFor2Chain; | ||
| 68 | u8 pwrDecreaseFor3Chain; | ||
| 69 | u8 txFrameToDataStart; | ||
| 70 | u8 txFrameToPaOn; | ||
| 71 | u8 ht40PowerIncForPdadc; | ||
| 72 | u8 bswAtten[AR5416_MAX_CHAINS]; | ||
| 73 | u8 bswMargin[AR5416_MAX_CHAINS]; | ||
| 74 | u8 swSettleHt40; | ||
| 75 | u8 reserved[22]; | ||
| 76 | struct spur_channel { | ||
| 77 | __le16 spurChan; | ||
| 78 | u8 spurRangeLow; | ||
| 79 | u8 spurRangeHigh; | ||
| 80 | } __packed spur_channels[AR5416_MODAL_SPURS]; | ||
| 81 | } __packed; | ||
| 82 | |||
| 83 | #define AR5416_NUM_PD_GAINS 4 | ||
| 84 | #define AR5416_PD_GAIN_ICEPTS 5 | ||
| 85 | |||
| 86 | struct ar9170_calibration_data_per_freq { | ||
| 87 | u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | ||
| 88 | u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; | ||
| 89 | } __packed; | ||
| 90 | |||
| 91 | #define AR5416_NUM_5G_CAL_PIERS 8 | ||
| 92 | #define AR5416_NUM_2G_CAL_PIERS 4 | ||
| 93 | |||
| 94 | #define AR5416_NUM_5G_TARGET_PWRS 8 | ||
| 95 | #define AR5416_NUM_2G_CCK_TARGET_PWRS 3 | ||
| 96 | #define AR5416_NUM_2G_OFDM_TARGET_PWRS 4 | ||
| 97 | #define AR5416_MAX_NUM_TGT_PWRS 8 | ||
| 98 | |||
| 99 | struct ar9170_calibration_target_power_legacy { | ||
| 100 | u8 freq; | ||
| 101 | u8 power[4]; | ||
| 102 | } __packed; | ||
| 103 | |||
| 104 | struct ar9170_calibration_target_power_ht { | ||
| 105 | u8 freq; | ||
| 106 | u8 power[8]; | ||
| 107 | } __packed; | ||
| 108 | |||
| 109 | #define AR5416_NUM_CTLS 24 | ||
| 110 | |||
| 111 | struct ar9170_calctl_edges { | ||
| 112 | u8 channel; | ||
| 113 | #define AR9170_CALCTL_EDGE_FLAGS 0xC0 | ||
| 114 | u8 power_flags; | ||
| 115 | } __packed; | ||
| 116 | |||
| 117 | #define AR5416_NUM_BAND_EDGES 8 | ||
| 118 | |||
| 119 | struct ar9170_calctl_data { | ||
| 120 | struct ar9170_calctl_edges | ||
| 121 | control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; | ||
| 122 | } __packed; | ||
| 123 | |||
| 124 | |||
| 125 | struct ar9170_eeprom { | ||
| 126 | __le16 length; | ||
| 127 | __le16 checksum; | ||
| 128 | __le16 version; | ||
| 129 | u8 operating_flags; | ||
| 130 | #define AR9170_OPFLAG_5GHZ 1 | ||
| 131 | #define AR9170_OPFLAG_2GHZ 2 | ||
| 132 | u8 misc; | ||
| 133 | __le16 reg_domain[2]; | ||
| 134 | u8 mac_address[6]; | ||
| 135 | u8 rx_mask; | ||
| 136 | u8 tx_mask; | ||
| 137 | __le16 rf_silent; | ||
| 138 | __le16 bluetooth_options; | ||
| 139 | __le16 device_capabilities; | ||
| 140 | __le32 build_number; | ||
| 141 | u8 deviceType; | ||
| 142 | u8 reserved[33]; | ||
| 143 | |||
| 144 | u8 customer_data[64]; | ||
| 145 | |||
| 146 | struct ar9170_eeprom_modal | ||
| 147 | modal_header[2]; | ||
| 148 | |||
| 149 | u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS]; | ||
| 150 | u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS]; | ||
| 151 | |||
| 152 | struct ar9170_calibration_data_per_freq | ||
| 153 | cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS], | ||
| 154 | cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS]; | ||
| 155 | |||
| 156 | /* power calibration data */ | ||
| 157 | struct ar9170_calibration_target_power_legacy | ||
| 158 | cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS]; | ||
| 159 | struct ar9170_calibration_target_power_ht | ||
| 160 | cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS], | ||
| 161 | cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS]; | ||
| 162 | |||
| 163 | struct ar9170_calibration_target_power_legacy | ||
| 164 | cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS], | ||
| 165 | cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS]; | ||
| 166 | struct ar9170_calibration_target_power_ht | ||
| 167 | cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS], | ||
| 168 | cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS]; | ||
| 169 | |||
| 170 | /* conformance testing limits */ | ||
| 171 | u8 ctl_index[AR5416_NUM_CTLS]; | ||
| 172 | struct ar9170_calctl_data | ||
| 173 | ctl_data[AR5416_NUM_CTLS]; | ||
| 174 | |||
| 175 | u8 pad; | ||
| 176 | __le16 subsystem_id; | ||
| 177 | } __packed; | ||
| 178 | |||
| 179 | #endif /* __AR9170_EEPROM_H */ | ||
diff --git a/drivers/net/wireless/ar9170/hw.h b/drivers/net/wireless/ar9170/hw.h new file mode 100644 index 000000000000..13091bd9d815 --- /dev/null +++ b/drivers/net/wireless/ar9170/hw.h | |||
| @@ -0,0 +1,417 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * Hardware-specific definitions | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | #ifndef __AR9170_HW_H | ||
| 39 | #define __AR9170_HW_H | ||
| 40 | |||
| 41 | #define AR9170_MAX_CMD_LEN 64 | ||
| 42 | |||
| 43 | enum ar9170_cmd { | ||
| 44 | AR9170_CMD_RREG = 0x00, | ||
| 45 | AR9170_CMD_WREG = 0x01, | ||
| 46 | AR9170_CMD_RMEM = 0x02, | ||
| 47 | AR9170_CMD_WMEM = 0x03, | ||
| 48 | AR9170_CMD_BITAND = 0x04, | ||
| 49 | AR9170_CMD_BITOR = 0x05, | ||
| 50 | AR9170_CMD_EKEY = 0x28, | ||
| 51 | AR9170_CMD_DKEY = 0x29, | ||
| 52 | AR9170_CMD_FREQUENCY = 0x30, | ||
| 53 | AR9170_CMD_RF_INIT = 0x31, | ||
| 54 | AR9170_CMD_SYNTH = 0x32, | ||
| 55 | AR9170_CMD_FREQ_START = 0x33, | ||
| 56 | AR9170_CMD_ECHO = 0x80, | ||
| 57 | AR9170_CMD_TALLY = 0x81, | ||
| 58 | AR9170_CMD_TALLY_APD = 0x82, | ||
| 59 | AR9170_CMD_CONFIG = 0x83, | ||
| 60 | AR9170_CMD_RESET = 0x90, | ||
| 61 | AR9170_CMD_DKRESET = 0x91, | ||
| 62 | AR9170_CMD_DKTX_STATUS = 0x92, | ||
| 63 | AR9170_CMD_FDC = 0xA0, | ||
| 64 | AR9170_CMD_WREEPROM = 0xB0, | ||
| 65 | AR9170_CMD_WFLASH = 0xB0, | ||
| 66 | AR9170_CMD_FLASH_ERASE = 0xB1, | ||
| 67 | AR9170_CMD_FLASH_PROG = 0xB2, | ||
| 68 | AR9170_CMD_FLASH_CHKSUM = 0xB3, | ||
| 69 | AR9170_CMD_FLASH_READ = 0xB4, | ||
| 70 | AR9170_CMD_FW_DL_INIT = 0xB5, | ||
| 71 | AR9170_CMD_MEM_WREEPROM = 0xBB, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* endpoints */ | ||
| 75 | #define AR9170_EP_TX 1 | ||
| 76 | #define AR9170_EP_RX 2 | ||
| 77 | #define AR9170_EP_IRQ 3 | ||
| 78 | #define AR9170_EP_CMD 4 | ||
| 79 | |||
| 80 | #define AR9170_EEPROM_START 0x1600 | ||
| 81 | |||
| 82 | #define AR9170_GPIO_REG_BASE 0x1d0100 | ||
| 83 | #define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE | ||
| 84 | #define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4) | ||
| 85 | #define AR9170_NUM_LEDS 2 | ||
| 86 | |||
| 87 | |||
| 88 | #define AR9170_USB_REG_BASE 0x1e1000 | ||
| 89 | #define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108) | ||
| 90 | #define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1 | ||
| 91 | #define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2 | ||
| 92 | #define AR9170_DMA_CTL_HIGH_SPEED 0x4 | ||
| 93 | #define AR9170_DMA_CTL_PACKET_MODE 0x8 | ||
| 94 | |||
| 95 | #define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110) | ||
| 96 | #define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114) | ||
| 97 | |||
| 98 | |||
| 99 | |||
| 100 | #define AR9170_MAC_REG_BASE 0x1c3000 | ||
| 101 | |||
| 102 | #define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514) | ||
| 103 | #define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518) | ||
| 104 | |||
| 105 | #define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C) | ||
| 106 | #define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520) | ||
| 107 | #define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524) | ||
| 108 | |||
| 109 | #define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610) | ||
| 110 | #define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614) | ||
| 111 | #define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618) | ||
| 112 | #define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c) | ||
| 113 | |||
| 114 | #define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624) | ||
| 115 | #define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628) | ||
| 116 | |||
| 117 | #define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C) | ||
| 118 | |||
| 119 | #define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630) | ||
| 120 | #define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634) | ||
| 121 | #define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638) | ||
| 122 | #define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c) | ||
| 123 | #define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640) | ||
| 124 | #define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C) | ||
| 125 | |||
| 126 | #define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658) | ||
| 127 | #define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674) | ||
| 128 | #define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0) | ||
| 129 | #define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000 | ||
| 130 | #define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678) | ||
| 131 | #define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3) | ||
| 132 | #define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70 | ||
| 133 | |||
| 134 | #define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680) | ||
| 135 | #define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688) | ||
| 136 | |||
| 137 | #define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c) | ||
| 138 | #define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0) | ||
| 139 | #define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1) | ||
| 140 | #define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2) | ||
| 141 | #define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3) | ||
| 142 | #define AR9170_MAC_REG_FTF_PRB_REQ BIT(4) | ||
| 143 | #define AR9170_MAC_REG_FTF_PRB_RESP BIT(5) | ||
| 144 | #define AR9170_MAC_REG_FTF_BIT6 BIT(6) | ||
| 145 | #define AR9170_MAC_REG_FTF_BIT7 BIT(7) | ||
| 146 | #define AR9170_MAC_REG_FTF_BEACON BIT(8) | ||
| 147 | #define AR9170_MAC_REG_FTF_ATIM BIT(9) | ||
| 148 | #define AR9170_MAC_REG_FTF_DEASSOC BIT(10) | ||
| 149 | #define AR9170_MAC_REG_FTF_AUTH BIT(11) | ||
| 150 | #define AR9170_MAC_REG_FTF_DEAUTH BIT(12) | ||
| 151 | #define AR9170_MAC_REG_FTF_BIT13 BIT(13) | ||
| 152 | #define AR9170_MAC_REG_FTF_BIT14 BIT(14) | ||
| 153 | #define AR9170_MAC_REG_FTF_BIT15 BIT(15) | ||
| 154 | #define AR9170_MAC_REG_FTF_BAR BIT(24) | ||
| 155 | #define AR9170_MAC_REG_FTF_BIT25 BIT(25) | ||
| 156 | #define AR9170_MAC_REG_FTF_PSPOLL BIT(26) | ||
| 157 | #define AR9170_MAC_REG_FTF_RTS BIT(27) | ||
| 158 | #define AR9170_MAC_REG_FTF_CTS BIT(28) | ||
| 159 | #define AR9170_MAC_REG_FTF_ACK BIT(29) | ||
| 160 | #define AR9170_MAC_REG_FTF_CFE BIT(30) | ||
| 161 | #define AR9170_MAC_REG_FTF_CFE_ACK BIT(31) | ||
| 162 | #define AR9170_MAC_REG_FTF_DEFAULTS 0x0500ffff | ||
| 163 | #define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff | ||
| 164 | |||
| 165 | #define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0) | ||
| 166 | #define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4) | ||
| 167 | #define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8) | ||
| 168 | #define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC) | ||
| 169 | #define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0) | ||
| 170 | #define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC) | ||
| 171 | #define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC) | ||
| 172 | #define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4) | ||
| 173 | |||
| 174 | |||
| 175 | #define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690) | ||
| 176 | #define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698) | ||
| 177 | |||
| 178 | #define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0) | ||
| 179 | |||
| 180 | #define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700) | ||
| 181 | #define AR9170_MAC_REG_POWERMGT_IBSS 0xe0 | ||
| 182 | #define AR9170_MAC_REG_POWERMGT_AP 0xa1 | ||
| 183 | #define AR9170_MAC_REG_POWERMGT_STA 0x2 | ||
| 184 | #define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3 | ||
| 185 | #define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24) | ||
| 186 | |||
| 187 | #define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704) | ||
| 188 | #define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708) | ||
| 189 | |||
| 190 | #define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00) | ||
| 191 | #define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04) | ||
| 192 | #define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08) | ||
| 193 | #define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C) | ||
| 194 | #define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10) | ||
| 195 | #define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14) | ||
| 196 | #define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18) | ||
| 197 | |||
| 198 | #define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28) | ||
| 199 | |||
| 200 | #define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0) | ||
| 201 | #define AR9170_MAC_FCS_SWFCS 0x1 | ||
| 202 | #define AR9170_MAC_FCS_FIFO_PROT 0x4 | ||
| 203 | |||
| 204 | |||
| 205 | #define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30) | ||
| 206 | |||
| 207 | #define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44) | ||
| 208 | #define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48) | ||
| 209 | |||
| 210 | #define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00) | ||
| 211 | #define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50) | ||
| 212 | |||
| 213 | #define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C) | ||
| 214 | #define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f | ||
| 215 | #define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0 | ||
| 216 | #define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000 | ||
| 217 | #define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000 | ||
| 218 | |||
| 219 | #define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84) | ||
| 220 | #define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88) | ||
| 221 | #define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90) | ||
| 222 | #define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94) | ||
| 223 | #define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0) | ||
| 224 | #define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4) | ||
| 225 | |||
| 226 | |||
| 227 | #define AR9170_PWR_REG_BASE 0x1D4000 | ||
| 228 | |||
| 229 | #define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008) | ||
| 230 | #define AR9170_PWR_CLK_AHB_40MHZ 0 | ||
| 231 | #define AR9170_PWR_CLK_AHB_20_22MHZ 1 | ||
| 232 | #define AR9170_PWR_CLK_AHB_40_44MHZ 2 | ||
| 233 | #define AR9170_PWR_CLK_AHB_80_88MHZ 3 | ||
| 234 | #define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70 | ||
| 235 | |||
| 236 | |||
| 237 | /* put beacon here in memory */ | ||
| 238 | #define AR9170_BEACON_BUFFER_ADDRESS 0x117900 | ||
| 239 | |||
| 240 | |||
| 241 | struct ar9170_tx_control { | ||
| 242 | __le16 length; | ||
| 243 | __le16 mac_control; | ||
| 244 | __le32 phy_control; | ||
| 245 | u8 frame_data[0]; | ||
| 246 | } __packed; | ||
| 247 | |||
| 248 | /* these are either-or */ | ||
| 249 | #define AR9170_TX_MAC_PROT_RTS 0x0001 | ||
| 250 | #define AR9170_TX_MAC_PROT_CTS 0x0002 | ||
| 251 | |||
| 252 | #define AR9170_TX_MAC_NO_ACK 0x0004 | ||
| 253 | /* if unset, MAC will only do SIFS space before frame */ | ||
| 254 | #define AR9170_TX_MAC_BACKOFF 0x0008 | ||
| 255 | #define AR9170_TX_MAC_BURST 0x0010 | ||
| 256 | #define AR9170_TX_MAC_AGGR 0x0020 | ||
| 257 | |||
| 258 | /* encryption is a two-bit field */ | ||
| 259 | #define AR9170_TX_MAC_ENCR_NONE 0x0000 | ||
| 260 | #define AR9170_TX_MAC_ENCR_RC4 0x0040 | ||
| 261 | #define AR9170_TX_MAC_ENCR_CENC 0x0080 | ||
| 262 | #define AR9170_TX_MAC_ENCR_AES 0x00c0 | ||
| 263 | |||
| 264 | #define AR9170_TX_MAC_MMIC 0x0100 | ||
| 265 | #define AR9170_TX_MAC_HW_DURATION 0x0200 | ||
| 266 | #define AR9170_TX_MAC_QOS_SHIFT 10 | ||
| 267 | #define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT) | ||
| 268 | #define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400 | ||
| 269 | #define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800 | ||
| 270 | #define AR9170_TX_MAC_DISABLE_TXOP 0x1000 | ||
| 271 | #define AR9170_TX_MAC_TXOP_RIFS 0x2000 | ||
| 272 | #define AR9170_TX_MAC_IMM_AMPDU 0x4000 | ||
| 273 | #define AR9170_TX_MAC_RATE_PROBE 0x8000 | ||
| 274 | |||
| 275 | /* either-or */ | ||
| 276 | #define AR9170_TX_PHY_MOD_CCK 0x00000000 | ||
| 277 | #define AR9170_TX_PHY_MOD_OFDM 0x00000001 | ||
| 278 | #define AR9170_TX_PHY_MOD_HT 0x00000002 | ||
| 279 | |||
| 280 | /* depends on modulation */ | ||
| 281 | #define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004 | ||
| 282 | #define AR9170_TX_PHY_GREENFIELD 0x00000004 | ||
| 283 | |||
| 284 | #define AR9170_TX_PHY_BW_SHIFT 3 | ||
| 285 | #define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT) | ||
| 286 | #define AR9170_TX_PHY_BW_20MHZ 0 | ||
| 287 | #define AR9170_TX_PHY_BW_40MHZ 2 | ||
| 288 | #define AR9170_TX_PHY_BW_40MHZ_DUP 3 | ||
| 289 | |||
| 290 | #define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6 | ||
| 291 | #define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT) | ||
| 292 | |||
| 293 | #define AR9170_TX_PHY_TX_PWR_SHIFT 9 | ||
| 294 | #define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT) | ||
| 295 | |||
| 296 | /* not part of the hw-spec */ | ||
| 297 | #define AR9170_TX_PHY_QOS_SHIFT 25 | ||
| 298 | #define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT) | ||
| 299 | |||
| 300 | #define AR9170_TX_PHY_TXCHAIN_SHIFT 15 | ||
| 301 | #define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT) | ||
| 302 | #define AR9170_TX_PHY_TXCHAIN_1 1 | ||
| 303 | /* use for cck, ofdm 6/9/12/18/24 and HT if capable */ | ||
| 304 | #define AR9170_TX_PHY_TXCHAIN_2 5 | ||
| 305 | |||
| 306 | #define AR9170_TX_PHY_MCS_SHIFT 18 | ||
| 307 | #define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT) | ||
| 308 | |||
| 309 | #define AR9170_TX_PHY_SHORT_GI 0x80000000 | ||
| 310 | |||
| 311 | struct ar9170_rx_head { | ||
| 312 | u8 plcp[12]; | ||
| 313 | }; | ||
| 314 | |||
| 315 | struct ar9170_rx_tail { | ||
| 316 | union { | ||
| 317 | struct { | ||
| 318 | u8 rssi_ant0, rssi_ant1, rssi_ant2, | ||
| 319 | rssi_ant0x, rssi_ant1x, rssi_ant2x, | ||
| 320 | rssi_combined; | ||
| 321 | }; | ||
| 322 | u8 rssi[7]; | ||
| 323 | }; | ||
| 324 | |||
| 325 | u8 evm_stream0[6], evm_stream1[6]; | ||
| 326 | u8 phy_err; | ||
| 327 | u8 SAidx, DAidx; | ||
| 328 | u8 error; | ||
| 329 | u8 status; | ||
| 330 | }; | ||
| 331 | |||
| 332 | #define AR9170_ENC_ALG_NONE 0x0 | ||
| 333 | #define AR9170_ENC_ALG_WEP64 0x1 | ||
| 334 | #define AR9170_ENC_ALG_TKIP 0x2 | ||
| 335 | #define AR9170_ENC_ALG_AESCCMP 0x4 | ||
| 336 | #define AR9170_ENC_ALG_WEP128 0x5 | ||
| 337 | #define AR9170_ENC_ALG_WEP256 0x6 | ||
| 338 | #define AR9170_ENC_ALG_CENC 0x7 | ||
| 339 | |||
| 340 | #define AR9170_RX_ENC_SOFTWARE 0x8 | ||
| 341 | |||
| 342 | static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_tail *t) | ||
| 343 | { | ||
| 344 | return (t->SAidx & 0xc0) >> 4 | | ||
| 345 | (t->DAidx & 0xc0) >> 6; | ||
| 346 | } | ||
| 347 | |||
| 348 | #define AR9170_RX_STATUS_MODULATION_MASK 0x03 | ||
| 349 | #define AR9170_RX_STATUS_MODULATION_CCK 0x00 | ||
| 350 | #define AR9170_RX_STATUS_MODULATION_OFDM 0x01 | ||
| 351 | #define AR9170_RX_STATUS_MODULATION_HT 0x02 | ||
| 352 | #define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03 | ||
| 353 | |||
| 354 | /* depends on modulation */ | ||
| 355 | #define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08 | ||
| 356 | #define AR9170_RX_STATUS_GREENFIELD 0x08 | ||
| 357 | |||
| 358 | #define AR9170_RX_STATUS_MPDU_MASK 0x30 | ||
| 359 | #define AR9170_RX_STATUS_MPDU_SINGLE 0x00 | ||
| 360 | #define AR9170_RX_STATUS_MPDU_FIRST 0x10 | ||
| 361 | #define AR9170_RX_STATUS_MPDU_MIDDLE 0x20 | ||
| 362 | #define AR9170_RX_STATUS_MPDU_LAST 0x30 | ||
| 363 | |||
| 364 | |||
| 365 | #define AR9170_RX_ERROR_RXTO 0x01 | ||
| 366 | #define AR9170_RX_ERROR_OVERRUN 0x02 | ||
| 367 | #define AR9170_RX_ERROR_DECRYPT 0x04 | ||
| 368 | #define AR9170_RX_ERROR_FCS 0x08 | ||
| 369 | #define AR9170_RX_ERROR_WRONG_RA 0x10 | ||
| 370 | #define AR9170_RX_ERROR_PLCP 0x20 | ||
| 371 | #define AR9170_RX_ERROR_MMIC 0x40 | ||
| 372 | |||
| 373 | struct ar9170_cmd_tx_status { | ||
| 374 | __le16 unkn; | ||
| 375 | u8 dst[ETH_ALEN]; | ||
| 376 | __le32 rate; | ||
| 377 | __le16 status; | ||
| 378 | } __packed; | ||
| 379 | |||
| 380 | #define AR9170_TX_STATUS_COMPLETE 0x00 | ||
| 381 | #define AR9170_TX_STATUS_RETRY 0x01 | ||
| 382 | #define AR9170_TX_STATUS_FAILED 0x02 | ||
| 383 | |||
| 384 | struct ar9170_cmd_ba_failed_count { | ||
| 385 | __le16 failed; | ||
| 386 | __le16 rate; | ||
| 387 | } __packed; | ||
| 388 | |||
| 389 | struct ar9170_cmd_response { | ||
| 390 | u8 flag; | ||
| 391 | u8 type; | ||
| 392 | |||
| 393 | union { | ||
| 394 | struct ar9170_cmd_tx_status tx_status; | ||
| 395 | struct ar9170_cmd_ba_failed_count ba_fail_cnt; | ||
| 396 | u8 data[0]; | ||
| 397 | }; | ||
| 398 | } __packed; | ||
| 399 | |||
| 400 | /* QoS */ | ||
| 401 | |||
| 402 | /* mac80211 queue to HW/FW map */ | ||
| 403 | static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 }; | ||
| 404 | |||
| 405 | /* HW/FW queue to mac80211 map */ | ||
| 406 | static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 }; | ||
| 407 | |||
| 408 | enum ar9170_txq { | ||
| 409 | AR9170_TXQ_BE, | ||
| 410 | AR9170_TXQ_BK, | ||
| 411 | AR9170_TXQ_VI, | ||
| 412 | AR9170_TXQ_VO, | ||
| 413 | |||
| 414 | __AR9170_NUM_TXQ, | ||
| 415 | }; | ||
| 416 | |||
| 417 | #endif /* __AR9170_HW_H */ | ||
diff --git a/drivers/net/wireless/ar9170/led.c b/drivers/net/wireless/ar9170/led.c new file mode 100644 index 000000000000..341cead7f606 --- /dev/null +++ b/drivers/net/wireless/ar9170/led.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * LED handling | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | |||
| 39 | #include "ar9170.h" | ||
| 40 | #include "cmd.h" | ||
| 41 | |||
| 42 | int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state) | ||
| 43 | { | ||
| 44 | return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state); | ||
| 45 | } | ||
| 46 | |||
| 47 | int ar9170_init_leds(struct ar9170 *ar) | ||
| 48 | { | ||
| 49 | int err; | ||
| 50 | |||
| 51 | /* disable LEDs */ | ||
| 52 | /* GPIO [0/1 mode: output, 2/3: input] */ | ||
| 53 | err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3); | ||
| 54 | if (err) | ||
| 55 | goto out; | ||
| 56 | |||
| 57 | /* GPIO 0/1 value: off */ | ||
| 58 | err = ar9170_set_leds_state(ar, 0); | ||
| 59 | |||
| 60 | out: | ||
| 61 | return err; | ||
| 62 | } | ||
| 63 | |||
| 64 | #ifdef CONFIG_AR9170_LEDS | ||
| 65 | static void ar9170_update_leds(struct work_struct *work) | ||
| 66 | { | ||
| 67 | struct ar9170 *ar = container_of(work, struct ar9170, led_work.work); | ||
| 68 | int i, tmp, blink_delay = 1000; | ||
| 69 | u32 led_val = 0; | ||
| 70 | bool rerun = false; | ||
| 71 | |||
| 72 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 73 | return ; | ||
| 74 | |||
| 75 | mutex_lock(&ar->mutex); | ||
| 76 | for (i = 0; i < AR9170_NUM_LEDS; i++) | ||
| 77 | if (ar->leds[i].toggled) { | ||
| 78 | led_val |= 1 << i; | ||
| 79 | |||
| 80 | tmp = 70 + 200 / (ar->leds[i].toggled); | ||
| 81 | if (tmp < blink_delay) | ||
| 82 | blink_delay = tmp; | ||
| 83 | |||
| 84 | if (ar->leds[i].toggled > 1) | ||
| 85 | ar->leds[i].toggled = 0; | ||
| 86 | |||
| 87 | rerun = true; | ||
| 88 | } | ||
| 89 | |||
| 90 | ar9170_set_leds_state(ar, led_val); | ||
| 91 | mutex_unlock(&ar->mutex); | ||
| 92 | |||
| 93 | if (rerun) | ||
| 94 | queue_delayed_work(ar->hw->workqueue, &ar->led_work, | ||
| 95 | msecs_to_jiffies(blink_delay)); | ||
| 96 | } | ||
| 97 | |||
| 98 | static void ar9170_led_brightness_set(struct led_classdev *led, | ||
| 99 | enum led_brightness brightness) | ||
| 100 | { | ||
| 101 | struct ar9170_led *arl = container_of(led, struct ar9170_led, l); | ||
| 102 | struct ar9170 *ar = arl->ar; | ||
| 103 | |||
| 104 | arl->toggled++; | ||
| 105 | |||
| 106 | if (likely(IS_ACCEPTING_CMD(ar) && brightness)) | ||
| 107 | queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10); | ||
| 108 | } | ||
| 109 | |||
| 110 | static int ar9170_register_led(struct ar9170 *ar, int i, char *name, | ||
| 111 | char *trigger) | ||
| 112 | { | ||
| 113 | int err; | ||
| 114 | |||
| 115 | snprintf(ar->leds[i].name, sizeof(ar->leds[i].name), | ||
| 116 | "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name); | ||
| 117 | |||
| 118 | ar->leds[i].ar = ar; | ||
| 119 | ar->leds[i].l.name = ar->leds[i].name; | ||
| 120 | ar->leds[i].l.brightness_set = ar9170_led_brightness_set; | ||
| 121 | ar->leds[i].l.brightness = 0; | ||
| 122 | ar->leds[i].l.default_trigger = trigger; | ||
| 123 | |||
| 124 | err = led_classdev_register(wiphy_dev(ar->hw->wiphy), | ||
| 125 | &ar->leds[i].l); | ||
| 126 | if (err) | ||
| 127 | printk(KERN_ERR "%s: failed to register %s LED (%d).\n", | ||
| 128 | wiphy_name(ar->hw->wiphy), ar->leds[i].name, err); | ||
| 129 | else | ||
| 130 | ar->leds[i].registered = true; | ||
| 131 | |||
| 132 | return err; | ||
| 133 | } | ||
| 134 | |||
| 135 | void ar9170_unregister_leds(struct ar9170 *ar) | ||
| 136 | { | ||
| 137 | int i; | ||
| 138 | |||
| 139 | cancel_delayed_work_sync(&ar->led_work); | ||
| 140 | |||
| 141 | for (i = 0; i < AR9170_NUM_LEDS; i++) | ||
| 142 | if (ar->leds[i].registered) { | ||
| 143 | led_classdev_unregister(&ar->leds[i].l); | ||
| 144 | ar->leds[i].registered = false; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | int ar9170_register_leds(struct ar9170 *ar) | ||
| 149 | { | ||
| 150 | int err; | ||
| 151 | |||
| 152 | INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds); | ||
| 153 | |||
| 154 | err = ar9170_register_led(ar, 0, "tx", | ||
| 155 | ieee80211_get_tx_led_name(ar->hw)); | ||
| 156 | if (err) | ||
| 157 | goto fail; | ||
| 158 | |||
| 159 | err = ar9170_register_led(ar, 1, "assoc", | ||
| 160 | ieee80211_get_assoc_led_name(ar->hw)); | ||
| 161 | if (err) | ||
| 162 | goto fail; | ||
| 163 | |||
| 164 | return 0; | ||
| 165 | |||
| 166 | fail: | ||
| 167 | ar9170_unregister_leds(ar); | ||
| 168 | return err; | ||
| 169 | } | ||
| 170 | |||
| 171 | #endif /* CONFIG_AR9170_LEDS */ | ||
diff --git a/drivers/net/wireless/ar9170/mac.c b/drivers/net/wireless/ar9170/mac.c new file mode 100644 index 000000000000..c8fa3073169f --- /dev/null +++ b/drivers/net/wireless/ar9170/mac.c | |||
| @@ -0,0 +1,452 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * MAC programming | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | #include "ar9170.h" | ||
| 39 | #include "cmd.h" | ||
| 40 | |||
| 41 | int ar9170_set_qos(struct ar9170 *ar) | ||
| 42 | { | ||
| 43 | ar9170_regwrite_begin(ar); | ||
| 44 | |||
| 45 | ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min | | ||
| 46 | (ar->edcf[0].cw_max << 16)); | ||
| 47 | ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min | | ||
| 48 | (ar->edcf[1].cw_max << 16)); | ||
| 49 | ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min | | ||
| 50 | (ar->edcf[2].cw_max << 16)); | ||
| 51 | ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min | | ||
| 52 | (ar->edcf[3].cw_max << 16)); | ||
| 53 | ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min | | ||
| 54 | (ar->edcf[4].cw_max << 16)); | ||
| 55 | |||
| 56 | ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS, | ||
| 57 | ((ar->edcf[0].aifs * 9 + 10)) | | ||
| 58 | ((ar->edcf[1].aifs * 9 + 10) << 12) | | ||
| 59 | ((ar->edcf[2].aifs * 9 + 10) << 24)); | ||
| 60 | ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS, | ||
| 61 | ((ar->edcf[2].aifs * 9 + 10) >> 8) | | ||
| 62 | ((ar->edcf[3].aifs * 9 + 10) << 4) | | ||
| 63 | ((ar->edcf[4].aifs * 9 + 10) << 16)); | ||
| 64 | |||
| 65 | ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP, | ||
| 66 | ar->edcf[0].txop | ar->edcf[1].txop << 16); | ||
| 67 | ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP, | ||
| 68 | ar->edcf[1].txop | ar->edcf[3].txop << 16); | ||
| 69 | |||
| 70 | ar9170_regwrite_finish(); | ||
| 71 | |||
| 72 | return ar9170_regwrite_result(); | ||
| 73 | } | ||
| 74 | |||
| 75 | int ar9170_init_mac(struct ar9170 *ar) | ||
| 76 | { | ||
| 77 | ar9170_regwrite_begin(ar); | ||
| 78 | |||
| 79 | ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40); | ||
| 80 | |||
| 81 | ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0); | ||
| 82 | |||
| 83 | /* enable MMIC */ | ||
| 84 | ar9170_regwrite(AR9170_MAC_REG_SNIFFER, | ||
| 85 | AR9170_MAC_REG_SNIFFER_DEFAULTS); | ||
| 86 | |||
| 87 | ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80); | ||
| 88 | |||
| 89 | ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70); | ||
| 90 | ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000); | ||
| 91 | ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10); | ||
| 92 | |||
| 93 | /* CF-END mode */ | ||
| 94 | ar9170_regwrite(0x1c3b2c, 0x19000000); | ||
| 95 | |||
| 96 | /* NAV protects ACK only (in TXOP) */ | ||
| 97 | ar9170_regwrite(0x1c3b38, 0x201); | ||
| 98 | |||
| 99 | /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */ | ||
| 100 | /* OTUS set AM to 0x1 */ | ||
| 101 | ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170); | ||
| 102 | |||
| 103 | ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); | ||
| 104 | |||
| 105 | /* AGG test code*/ | ||
| 106 | /* Aggregation MAX number and timeout */ | ||
| 107 | ar9170_regwrite(0x1c3b9c, 0x10000a); | ||
| 108 | |||
| 109 | ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, | ||
| 110 | AR9170_MAC_REG_FTF_DEFAULTS); | ||
| 111 | |||
| 112 | /* Enable deaggregator, response in sniffer mode */ | ||
| 113 | ar9170_regwrite(0x1c3c40, 0x1 | 1<<30); | ||
| 114 | |||
| 115 | /* rate sets */ | ||
| 116 | ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f); | ||
| 117 | ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f); | ||
| 118 | ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb); | ||
| 119 | |||
| 120 | /* MIMO response control */ | ||
| 121 | ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */ | ||
| 122 | |||
| 123 | /* switch MAC to OTUS interface */ | ||
| 124 | ar9170_regwrite(0x1c3600, 0x3); | ||
| 125 | |||
| 126 | ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff); | ||
| 127 | |||
| 128 | /* set PHY register read timeout (??) */ | ||
| 129 | ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008); | ||
| 130 | |||
| 131 | /* Disable Rx TimeOut, workaround for BB. */ | ||
| 132 | ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0); | ||
| 133 | |||
| 134 | /* Set CPU clock frequency to 88/80MHz */ | ||
| 135 | ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL, | ||
| 136 | AR9170_PWR_CLK_AHB_80_88MHZ | | ||
| 137 | AR9170_PWR_CLK_DAC_160_INV_DLY); | ||
| 138 | |||
| 139 | /* Set WLAN DMA interrupt mode: generate int per packet */ | ||
| 140 | ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011); | ||
| 141 | |||
| 142 | ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT, | ||
| 143 | AR9170_MAC_FCS_FIFO_PROT); | ||
| 144 | |||
| 145 | /* Disables the CF_END frame, undocumented register */ | ||
| 146 | ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND, | ||
| 147 | 0x141E0F48); | ||
| 148 | |||
| 149 | ar9170_regwrite_finish(); | ||
| 150 | |||
| 151 | return ar9170_regwrite_result(); | ||
| 152 | } | ||
| 153 | |||
| 154 | static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac) | ||
| 155 | { | ||
| 156 | static const u8 zero[ETH_ALEN] = { 0 }; | ||
| 157 | |||
| 158 | if (!mac) | ||
| 159 | mac = zero; | ||
| 160 | |||
| 161 | ar9170_regwrite_begin(ar); | ||
| 162 | |||
| 163 | ar9170_regwrite(reg, | ||
| 164 | (mac[3] << 24) | (mac[2] << 16) | | ||
| 165 | (mac[1] << 8) | mac[0]); | ||
| 166 | |||
| 167 | ar9170_regwrite(reg + 4, (mac[5] << 8) | mac[4]); | ||
| 168 | |||
| 169 | ar9170_regwrite_finish(); | ||
| 170 | |||
| 171 | return ar9170_regwrite_result(); | ||
| 172 | } | ||
| 173 | |||
| 174 | int ar9170_update_multicast(struct ar9170 *ar) | ||
| 175 | { | ||
| 176 | int err; | ||
| 177 | |||
| 178 | ar9170_regwrite_begin(ar); | ||
| 179 | ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, | ||
| 180 | ar->want_mc_hash >> 32); | ||
| 181 | ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, | ||
| 182 | ar->want_mc_hash); | ||
| 183 | |||
| 184 | ar9170_regwrite_finish(); | ||
| 185 | err = ar9170_regwrite_result(); | ||
| 186 | |||
| 187 | if (err) | ||
| 188 | return err; | ||
| 189 | |||
| 190 | ar->cur_mc_hash = ar->want_mc_hash; | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | int ar9170_update_frame_filter(struct ar9170 *ar) | ||
| 196 | { | ||
| 197 | int err; | ||
| 198 | |||
| 199 | err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, | ||
| 200 | ar->want_filter); | ||
| 201 | |||
| 202 | if (err) | ||
| 203 | return err; | ||
| 204 | |||
| 205 | ar->cur_filter = ar->want_filter; | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static int ar9170_set_promiscouous(struct ar9170 *ar) | ||
| 211 | { | ||
| 212 | u32 encr_mode, sniffer; | ||
| 213 | int err; | ||
| 214 | |||
| 215 | err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer); | ||
| 216 | if (err) | ||
| 217 | return err; | ||
| 218 | |||
| 219 | err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode); | ||
| 220 | if (err) | ||
| 221 | return err; | ||
| 222 | |||
| 223 | if (ar->sniffer_enabled) { | ||
| 224 | sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Rx decryption works in place. | ||
| 228 | * | ||
| 229 | * If we don't disable it, the hardware will render all | ||
| 230 | * encrypted frames which are encrypted with an unknown | ||
| 231 | * key useless. | ||
| 232 | */ | ||
| 233 | |||
| 234 | encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
| 235 | ar->sniffer_enabled = true; | ||
| 236 | } else { | ||
| 237 | sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC; | ||
| 238 | |||
| 239 | if (ar->rx_software_decryption) | ||
| 240 | encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
| 241 | else | ||
| 242 | encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE; | ||
| 243 | } | ||
| 244 | |||
| 245 | ar9170_regwrite_begin(ar); | ||
| 246 | ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode); | ||
| 247 | ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer); | ||
| 248 | ar9170_regwrite_finish(); | ||
| 249 | |||
| 250 | return ar9170_regwrite_result(); | ||
| 251 | } | ||
| 252 | |||
| 253 | int ar9170_set_operating_mode(struct ar9170 *ar) | ||
| 254 | { | ||
| 255 | u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS; | ||
| 256 | u8 *mac_addr, *bssid; | ||
| 257 | int err; | ||
| 258 | |||
| 259 | if (ar->vif) { | ||
| 260 | mac_addr = ar->mac_addr; | ||
| 261 | bssid = ar->bssid; | ||
| 262 | |||
| 263 | switch (ar->vif->type) { | ||
| 264 | case NL80211_IFTYPE_MESH_POINT: | ||
| 265 | case NL80211_IFTYPE_ADHOC: | ||
| 266 | pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS; | ||
| 267 | break; | ||
| 268 | /* case NL80211_IFTYPE_AP: | ||
| 269 | pm_mode |= AR9170_MAC_REG_POWERMGT_AP; | ||
| 270 | break;*/ | ||
| 271 | case NL80211_IFTYPE_WDS: | ||
| 272 | pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS; | ||
| 273 | break; | ||
| 274 | case NL80211_IFTYPE_MONITOR: | ||
| 275 | ar->sniffer_enabled = true; | ||
| 276 | ar->rx_software_decryption = true; | ||
| 277 | break; | ||
| 278 | default: | ||
| 279 | pm_mode |= AR9170_MAC_REG_POWERMGT_STA; | ||
| 280 | break; | ||
| 281 | } | ||
| 282 | } else { | ||
| 283 | mac_addr = NULL; | ||
| 284 | bssid = NULL; | ||
| 285 | } | ||
| 286 | |||
| 287 | err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr); | ||
| 288 | if (err) | ||
| 289 | return err; | ||
| 290 | |||
| 291 | err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid); | ||
| 292 | if (err) | ||
| 293 | return err; | ||
| 294 | |||
| 295 | err = ar9170_set_promiscouous(ar); | ||
| 296 | if (err) | ||
| 297 | return err; | ||
| 298 | |||
| 299 | ar9170_regwrite_begin(ar); | ||
| 300 | |||
| 301 | ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode); | ||
| 302 | ar9170_regwrite_finish(); | ||
| 303 | |||
| 304 | return ar9170_regwrite_result(); | ||
| 305 | } | ||
| 306 | |||
| 307 | int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry) | ||
| 308 | { | ||
| 309 | u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111); | ||
| 310 | |||
| 311 | return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp); | ||
| 312 | } | ||
| 313 | |||
| 314 | int ar9170_set_beacon_timers(struct ar9170 *ar) | ||
| 315 | { | ||
| 316 | u32 v = 0; | ||
| 317 | u32 pretbtt = 0; | ||
| 318 | |||
| 319 | v |= ar->hw->conf.beacon_int; | ||
| 320 | |||
| 321 | if (ar->vif) { | ||
| 322 | switch (ar->vif->type) { | ||
| 323 | case NL80211_IFTYPE_MESH_POINT: | ||
| 324 | case NL80211_IFTYPE_ADHOC: | ||
| 325 | v |= BIT(25); | ||
| 326 | break; | ||
| 327 | case NL80211_IFTYPE_AP: | ||
| 328 | v |= BIT(24); | ||
| 329 | pretbtt = (ar->hw->conf.beacon_int - 6) << 16; | ||
| 330 | break; | ||
| 331 | default: | ||
| 332 | break; | ||
| 333 | } | ||
| 334 | |||
| 335 | v |= ar->vif->bss_conf.dtim_period << 16; | ||
| 336 | } | ||
| 337 | |||
| 338 | ar9170_regwrite_begin(ar); | ||
| 339 | |||
| 340 | ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt); | ||
| 341 | ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v); | ||
| 342 | ar9170_regwrite_finish(); | ||
| 343 | return ar9170_regwrite_result(); | ||
| 344 | } | ||
| 345 | |||
| 346 | int ar9170_update_beacon(struct ar9170 *ar) | ||
| 347 | { | ||
| 348 | struct sk_buff *skb; | ||
| 349 | __le32 *data, *old = NULL; | ||
| 350 | u32 word; | ||
| 351 | int i; | ||
| 352 | |||
| 353 | skb = ieee80211_beacon_get(ar->hw, ar->vif); | ||
| 354 | if (!skb) | ||
| 355 | return -ENOMEM; | ||
| 356 | |||
| 357 | data = (__le32 *)skb->data; | ||
| 358 | if (ar->beacon) | ||
| 359 | old = (__le32 *)ar->beacon->data; | ||
| 360 | |||
| 361 | ar9170_regwrite_begin(ar); | ||
| 362 | for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { | ||
| 363 | /* | ||
| 364 | * XXX: This accesses beyond skb data for up | ||
| 365 | * to the last 3 bytes!! | ||
| 366 | */ | ||
| 367 | |||
| 368 | if (old && (data[i] == old[i])) | ||
| 369 | continue; | ||
| 370 | |||
| 371 | word = le32_to_cpu(data[i]); | ||
| 372 | ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word); | ||
| 373 | } | ||
| 374 | |||
| 375 | /* XXX: use skb->cb info */ | ||
| 376 | if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) | ||
| 377 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | ||
| 378 | ((skb->len + 4) << (3+16)) + 0x0400); | ||
| 379 | else | ||
| 380 | ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP, | ||
| 381 | ((skb->len + 4) << (3+16)) + 0x0400); | ||
| 382 | |||
| 383 | ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4); | ||
| 384 | ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS); | ||
| 385 | ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1); | ||
| 386 | |||
| 387 | ar9170_regwrite_finish(); | ||
| 388 | |||
| 389 | dev_kfree_skb(ar->beacon); | ||
| 390 | ar->beacon = skb; | ||
| 391 | |||
| 392 | return ar9170_regwrite_result(); | ||
| 393 | } | ||
| 394 | |||
| 395 | void ar9170_new_beacon(struct work_struct *work) | ||
| 396 | { | ||
| 397 | struct ar9170 *ar = container_of(work, struct ar9170, | ||
| 398 | beacon_work); | ||
| 399 | struct sk_buff *skb; | ||
| 400 | |||
| 401 | if (unlikely(!IS_STARTED(ar))) | ||
| 402 | return ; | ||
| 403 | |||
| 404 | mutex_lock(&ar->mutex); | ||
| 405 | |||
| 406 | if (!ar->vif) | ||
| 407 | goto out; | ||
| 408 | |||
| 409 | ar9170_update_beacon(ar); | ||
| 410 | |||
| 411 | rcu_read_lock(); | ||
| 412 | while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif))) | ||
| 413 | ar9170_op_tx(ar->hw, skb); | ||
| 414 | |||
| 415 | rcu_read_unlock(); | ||
| 416 | |||
| 417 | out: | ||
| 418 | mutex_unlock(&ar->mutex); | ||
| 419 | } | ||
| 420 | |||
| 421 | int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype, | ||
| 422 | u8 keyidx, u8 *keydata, int keylen) | ||
| 423 | { | ||
| 424 | __le32 vals[7]; | ||
| 425 | static const u8 bcast[ETH_ALEN] = | ||
| 426 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
| 427 | u8 dummy; | ||
| 428 | |||
| 429 | mac = mac ? : bcast; | ||
| 430 | |||
| 431 | vals[0] = cpu_to_le32((keyidx << 16) + id); | ||
| 432 | vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype); | ||
| 433 | vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 | | ||
| 434 | mac[3] << 8 | mac[2]); | ||
| 435 | memset(&vals[3], 0, 16); | ||
| 436 | if (keydata) | ||
| 437 | memcpy(&vals[3], keydata, keylen); | ||
| 438 | |||
| 439 | return ar->exec_cmd(ar, AR9170_CMD_EKEY, | ||
| 440 | sizeof(vals), (u8 *)vals, | ||
| 441 | 1, &dummy); | ||
| 442 | } | ||
| 443 | |||
| 444 | int ar9170_disable_key(struct ar9170 *ar, u8 id) | ||
| 445 | { | ||
| 446 | __le32 val = cpu_to_le32(id); | ||
| 447 | u8 dummy; | ||
| 448 | |||
| 449 | return ar->exec_cmd(ar, AR9170_CMD_EKEY, | ||
| 450 | sizeof(val), (u8 *)&val, | ||
| 451 | 1, &dummy); | ||
| 452 | } | ||
diff --git a/drivers/net/wireless/ar9170/main.c b/drivers/net/wireless/ar9170/main.c new file mode 100644 index 000000000000..5996ff9f7f47 --- /dev/null +++ b/drivers/net/wireless/ar9170/main.c | |||
| @@ -0,0 +1,1671 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * mac80211 interaction code | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; see the file COPYING. If not, see | ||
| 21 | * http://www.gnu.org/licenses/. | ||
| 22 | * | ||
| 23 | * This file incorporates work covered by the following copyright and | ||
| 24 | * permission notice: | ||
| 25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 26 | * | ||
| 27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 28 | * purpose with or without fee is hereby granted, provided that the above | ||
| 29 | * copyright notice and this permission notice appear in all copies. | ||
| 30 | * | ||
| 31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <linux/init.h> | ||
| 41 | #include <linux/module.h> | ||
| 42 | #include <linux/etherdevice.h> | ||
| 43 | #include <net/mac80211.h> | ||
| 44 | #include "ar9170.h" | ||
| 45 | #include "hw.h" | ||
| 46 | #include "cmd.h" | ||
| 47 | |||
| 48 | static int modparam_nohwcrypt; | ||
| 49 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | ||
| 50 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | ||
| 51 | |||
| 52 | #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ | ||
| 53 | .bitrate = (_bitrate), \ | ||
| 54 | .flags = (_flags), \ | ||
| 55 | .hw_value = (_hw_rate) | (_txpidx) << 4, \ | ||
| 56 | } | ||
| 57 | |||
| 58 | static struct ieee80211_rate __ar9170_ratetable[] = { | ||
| 59 | RATE(10, 0, 0, 0), | ||
| 60 | RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE), | ||
| 61 | RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE), | ||
| 62 | RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE), | ||
| 63 | RATE(60, 0xb, 0, 0), | ||
| 64 | RATE(90, 0xf, 0, 0), | ||
| 65 | RATE(120, 0xa, 0, 0), | ||
| 66 | RATE(180, 0xe, 0, 0), | ||
| 67 | RATE(240, 0x9, 0, 0), | ||
| 68 | RATE(360, 0xd, 1, 0), | ||
| 69 | RATE(480, 0x8, 2, 0), | ||
| 70 | RATE(540, 0xc, 3, 0), | ||
| 71 | }; | ||
| 72 | #undef RATE | ||
| 73 | |||
| 74 | #define ar9170_g_ratetable (__ar9170_ratetable + 0) | ||
| 75 | #define ar9170_g_ratetable_size 12 | ||
| 76 | #define ar9170_a_ratetable (__ar9170_ratetable + 4) | ||
| 77 | #define ar9170_a_ratetable_size 8 | ||
| 78 | |||
| 79 | /* | ||
| 80 | * NB: The hw_value is used as an index into the ar9170_phy_freq_params | ||
| 81 | * array in phy.c so that we don't have to do frequency lookups! | ||
| 82 | */ | ||
| 83 | #define CHAN(_freq, _idx) { \ | ||
| 84 | .center_freq = (_freq), \ | ||
| 85 | .hw_value = (_idx), \ | ||
| 86 | .max_power = 18, /* XXX */ \ | ||
| 87 | } | ||
| 88 | |||
| 89 | static struct ieee80211_channel ar9170_2ghz_chantable[] = { | ||
| 90 | CHAN(2412, 0), | ||
| 91 | CHAN(2417, 1), | ||
| 92 | CHAN(2422, 2), | ||
| 93 | CHAN(2427, 3), | ||
| 94 | CHAN(2432, 4), | ||
| 95 | CHAN(2437, 5), | ||
| 96 | CHAN(2442, 6), | ||
| 97 | CHAN(2447, 7), | ||
| 98 | CHAN(2452, 8), | ||
| 99 | CHAN(2457, 9), | ||
| 100 | CHAN(2462, 10), | ||
| 101 | CHAN(2467, 11), | ||
| 102 | CHAN(2472, 12), | ||
| 103 | CHAN(2484, 13), | ||
| 104 | }; | ||
| 105 | |||
| 106 | static struct ieee80211_channel ar9170_5ghz_chantable[] = { | ||
| 107 | CHAN(4920, 14), | ||
| 108 | CHAN(4940, 15), | ||
| 109 | CHAN(4960, 16), | ||
| 110 | CHAN(4980, 17), | ||
| 111 | CHAN(5040, 18), | ||
| 112 | CHAN(5060, 19), | ||
| 113 | CHAN(5080, 20), | ||
| 114 | CHAN(5180, 21), | ||
| 115 | CHAN(5200, 22), | ||
| 116 | CHAN(5220, 23), | ||
| 117 | CHAN(5240, 24), | ||
| 118 | CHAN(5260, 25), | ||
| 119 | CHAN(5280, 26), | ||
| 120 | CHAN(5300, 27), | ||
| 121 | CHAN(5320, 28), | ||
| 122 | CHAN(5500, 29), | ||
| 123 | CHAN(5520, 30), | ||
| 124 | CHAN(5540, 31), | ||
| 125 | CHAN(5560, 32), | ||
| 126 | CHAN(5580, 33), | ||
| 127 | CHAN(5600, 34), | ||
| 128 | CHAN(5620, 35), | ||
| 129 | CHAN(5640, 36), | ||
| 130 | CHAN(5660, 37), | ||
| 131 | CHAN(5680, 38), | ||
| 132 | CHAN(5700, 39), | ||
| 133 | CHAN(5745, 40), | ||
| 134 | CHAN(5765, 41), | ||
| 135 | CHAN(5785, 42), | ||
| 136 | CHAN(5805, 43), | ||
| 137 | CHAN(5825, 44), | ||
| 138 | CHAN(5170, 45), | ||
| 139 | CHAN(5190, 46), | ||
| 140 | CHAN(5210, 47), | ||
| 141 | CHAN(5230, 48), | ||
| 142 | }; | ||
| 143 | #undef CHAN | ||
| 144 | |||
| 145 | static struct ieee80211_supported_band ar9170_band_2GHz = { | ||
| 146 | .channels = ar9170_2ghz_chantable, | ||
| 147 | .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable), | ||
| 148 | .bitrates = ar9170_g_ratetable, | ||
| 149 | .n_bitrates = ar9170_g_ratetable_size, | ||
| 150 | }; | ||
| 151 | |||
| 152 | #ifdef AR9170_QUEUE_DEBUG | ||
| 153 | /* | ||
| 154 | * In case some wants works with AR9170's crazy tx_status queueing techniques. | ||
| 155 | * He might need this rather useful probing function. | ||
| 156 | * | ||
| 157 | * NOTE: caller must hold the queue's spinlock! | ||
| 158 | */ | ||
| 159 | |||
| 160 | static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb) | ||
| 161 | { | ||
| 162 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
| 163 | struct ieee80211_hdr *hdr = (void *)txc->frame_data; | ||
| 164 | |||
| 165 | printk(KERN_DEBUG "%s: => FRAME [skb:%p, queue:%d, DA:[%pM] " | ||
| 166 | "mac_control:%04x, phy_control:%08x]\n", | ||
| 167 | wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb), | ||
| 168 | ieee80211_get_DA(hdr), le16_to_cpu(txc->mac_control), | ||
| 169 | le32_to_cpu(txc->phy_control)); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void ar9170_dump_station_tx_status_queue(struct ar9170 *ar, | ||
| 173 | struct sk_buff_head *queue) | ||
| 174 | { | ||
| 175 | struct sk_buff *skb; | ||
| 176 | int i = 0; | ||
| 177 | |||
| 178 | printk(KERN_DEBUG "---[ cut here ]---\n"); | ||
| 179 | printk(KERN_DEBUG "%s: %d entries in tx_status queue.\n", | ||
| 180 | wiphy_name(ar->hw->wiphy), skb_queue_len(queue)); | ||
| 181 | |||
| 182 | skb_queue_walk(queue, skb) { | ||
| 183 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
| 184 | struct ieee80211_hdr *hdr = (void *)txc->frame_data; | ||
| 185 | |||
| 186 | printk(KERN_DEBUG "index:%d => \n", i); | ||
| 187 | ar9170_print_txheader(ar, skb); | ||
| 188 | } | ||
| 189 | printk(KERN_DEBUG "---[ end ]---\n"); | ||
| 190 | } | ||
| 191 | #endif /* AR9170_QUEUE_DEBUG */ | ||
| 192 | |||
| 193 | static struct ieee80211_supported_band ar9170_band_5GHz = { | ||
| 194 | .channels = ar9170_5ghz_chantable, | ||
| 195 | .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable), | ||
| 196 | .bitrates = ar9170_a_ratetable, | ||
| 197 | .n_bitrates = ar9170_a_ratetable_size, | ||
| 198 | }; | ||
| 199 | |||
| 200 | void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb, | ||
| 201 | bool valid_status, u16 tx_status) | ||
| 202 | { | ||
| 203 | struct ieee80211_tx_info *txinfo; | ||
| 204 | unsigned int retries = 0, queue = skb_get_queue_mapping(skb); | ||
| 205 | unsigned long flags; | ||
| 206 | |||
| 207 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
| 208 | ar->tx_stats[queue].len--; | ||
| 209 | if (ieee80211_queue_stopped(ar->hw, queue)) | ||
| 210 | ieee80211_wake_queue(ar->hw, queue); | ||
| 211 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
| 212 | |||
| 213 | txinfo = IEEE80211_SKB_CB(skb); | ||
| 214 | ieee80211_tx_info_clear_status(txinfo); | ||
| 215 | |||
| 216 | switch (tx_status) { | ||
| 217 | case AR9170_TX_STATUS_RETRY: | ||
| 218 | retries = 2; | ||
| 219 | case AR9170_TX_STATUS_COMPLETE: | ||
| 220 | txinfo->flags |= IEEE80211_TX_STAT_ACK; | ||
| 221 | break; | ||
| 222 | |||
| 223 | case AR9170_TX_STATUS_FAILED: | ||
| 224 | retries = ar->hw->conf.long_frame_max_tx_count; | ||
| 225 | break; | ||
| 226 | |||
| 227 | default: | ||
| 228 | printk(KERN_ERR "%s: invalid tx_status response (%x).\n", | ||
| 229 | wiphy_name(ar->hw->wiphy), tx_status); | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | |||
| 233 | if (valid_status) | ||
| 234 | txinfo->status.rates[0].count = retries + 1; | ||
| 235 | |||
| 236 | skb_pull(skb, sizeof(struct ar9170_tx_control)); | ||
| 237 | ieee80211_tx_status_irqsafe(ar->hw, skb); | ||
| 238 | } | ||
| 239 | |||
| 240 | static struct sk_buff *ar9170_find_skb_in_queue(struct ar9170 *ar, | ||
| 241 | const u8 *mac, | ||
| 242 | const u32 queue, | ||
| 243 | struct sk_buff_head *q) | ||
| 244 | { | ||
| 245 | unsigned long flags; | ||
| 246 | struct sk_buff *skb; | ||
| 247 | |||
| 248 | spin_lock_irqsave(&q->lock, flags); | ||
| 249 | skb_queue_walk(q, skb) { | ||
| 250 | struct ar9170_tx_control *txc = (void *) skb->data; | ||
| 251 | struct ieee80211_hdr *hdr = (void *) txc->frame_data; | ||
| 252 | u32 txc_queue = (le32_to_cpu(txc->phy_control) & | ||
| 253 | AR9170_TX_PHY_QOS_MASK) >> | ||
| 254 | AR9170_TX_PHY_QOS_SHIFT; | ||
| 255 | |||
| 256 | if ((queue != txc_queue) || | ||
| 257 | (compare_ether_addr(ieee80211_get_DA(hdr), mac))) | ||
| 258 | continue; | ||
| 259 | |||
| 260 | __skb_unlink(skb, q); | ||
| 261 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 262 | return skb; | ||
| 263 | } | ||
| 264 | spin_unlock_irqrestore(&q->lock, flags); | ||
| 265 | return NULL; | ||
| 266 | } | ||
| 267 | |||
| 268 | static struct sk_buff *ar9170_find_queued_skb(struct ar9170 *ar, const u8 *mac, | ||
| 269 | const u32 queue) | ||
| 270 | { | ||
| 271 | struct ieee80211_sta *sta; | ||
| 272 | struct sk_buff *skb; | ||
| 273 | |||
| 274 | /* | ||
| 275 | * Unfortunately, the firmware does not tell to which (queued) frame | ||
| 276 | * this transmission status report belongs to. | ||
| 277 | * | ||
| 278 | * So we have to make risky guesses - with the scarce information | ||
| 279 | * the firmware provided (-> destination MAC, and phy_control) - | ||
| 280 | * and hope that we picked the right one... | ||
| 281 | */ | ||
| 282 | rcu_read_lock(); | ||
| 283 | sta = ieee80211_find_sta(ar->hw, mac); | ||
| 284 | |||
| 285 | if (likely(sta)) { | ||
| 286 | struct ar9170_sta_info *sta_priv = (void *) sta->drv_priv; | ||
| 287 | skb = skb_dequeue(&sta_priv->tx_status[queue]); | ||
| 288 | rcu_read_unlock(); | ||
| 289 | if (likely(skb)) | ||
| 290 | return skb; | ||
| 291 | } else | ||
| 292 | rcu_read_unlock(); | ||
| 293 | |||
| 294 | /* scan the waste queue for candidates */ | ||
| 295 | skb = ar9170_find_skb_in_queue(ar, mac, queue, | ||
| 296 | &ar->global_tx_status_waste); | ||
| 297 | if (!skb) { | ||
| 298 | /* so it still _must_ be in the global list. */ | ||
| 299 | skb = ar9170_find_skb_in_queue(ar, mac, queue, | ||
| 300 | &ar->global_tx_status); | ||
| 301 | } | ||
| 302 | |||
| 303 | #ifdef AR9170_QUEUE_DEBUG | ||
| 304 | if (unlikely((!skb) && net_ratelimit())) { | ||
| 305 | printk(KERN_ERR "%s: ESS:[%pM] does not have any " | ||
| 306 | "outstanding frames in this queue (%d).\n", | ||
| 307 | wiphy_name(ar->hw->wiphy), mac, queue); | ||
| 308 | } | ||
| 309 | #endif /* AR9170_QUEUE_DEBUG */ | ||
| 310 | return skb; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* | ||
| 314 | * This worker tries to keep the global tx_status queue empty. | ||
| 315 | * So we can guarantee that incoming tx_status reports for | ||
| 316 | * unregistered stations are always synced with the actual | ||
| 317 | * frame - which we think - belongs to. | ||
| 318 | */ | ||
| 319 | |||
| 320 | static void ar9170_tx_status_janitor(struct work_struct *work) | ||
| 321 | { | ||
| 322 | struct ar9170 *ar = container_of(work, struct ar9170, | ||
| 323 | tx_status_janitor.work); | ||
| 324 | struct sk_buff *skb; | ||
| 325 | |||
| 326 | if (unlikely(!IS_STARTED(ar))) | ||
| 327 | return ; | ||
| 328 | |||
| 329 | mutex_lock(&ar->mutex); | ||
| 330 | /* recycle the garbage back to mac80211... one by one. */ | ||
| 331 | while ((skb = skb_dequeue(&ar->global_tx_status_waste))) { | ||
| 332 | #ifdef AR9170_QUEUE_DEBUG | ||
| 333 | printk(KERN_DEBUG "%s: dispose queued frame =>\n", | ||
| 334 | wiphy_name(ar->hw->wiphy)); | ||
| 335 | ar9170_print_txheader(ar, skb); | ||
| 336 | #endif /* AR9170_QUEUE_DEBUG */ | ||
| 337 | ar9170_handle_tx_status(ar, skb, false, | ||
| 338 | AR9170_TX_STATUS_FAILED); | ||
| 339 | } | ||
| 340 | |||
| 341 | while ((skb = skb_dequeue(&ar->global_tx_status))) { | ||
| 342 | #ifdef AR9170_QUEUE_DEBUG | ||
| 343 | printk(KERN_DEBUG "%s: moving frame into waste queue =>\n", | ||
| 344 | wiphy_name(ar->hw->wiphy)); | ||
| 345 | |||
| 346 | ar9170_print_txheader(ar, skb); | ||
| 347 | #endif /* AR9170_QUEUE_DEBUG */ | ||
| 348 | skb_queue_tail(&ar->global_tx_status_waste, skb); | ||
| 349 | } | ||
| 350 | |||
| 351 | /* recall the janitor in 100ms - if there's garbage in the can. */ | ||
| 352 | if (skb_queue_len(&ar->global_tx_status_waste) > 0) | ||
| 353 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, | ||
| 354 | msecs_to_jiffies(100)); | ||
| 355 | |||
| 356 | mutex_unlock(&ar->mutex); | ||
| 357 | } | ||
| 358 | |||
| 359 | static void ar9170_handle_command_response(struct ar9170 *ar, | ||
| 360 | void *buf, u32 len) | ||
| 361 | { | ||
| 362 | struct ar9170_cmd_response *cmd = (void *) buf; | ||
| 363 | |||
| 364 | if ((cmd->type & 0xc0) != 0xc0) { | ||
| 365 | ar->callback_cmd(ar, len, buf); | ||
| 366 | return; | ||
| 367 | } | ||
| 368 | |||
| 369 | /* hardware event handlers */ | ||
| 370 | switch (cmd->type) { | ||
| 371 | case 0xc1: { | ||
| 372 | /* | ||
| 373 | * TX status notification: | ||
| 374 | * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1 | ||
| 375 | * | ||
| 376 | * XX always 81 | ||
| 377 | * YY always 00 | ||
| 378 | * M1-M6 is the MAC address | ||
| 379 | * R1-R4 is the transmit rate | ||
| 380 | * S1-S2 is the transmit status | ||
| 381 | */ | ||
| 382 | |||
| 383 | struct sk_buff *skb; | ||
| 384 | u32 queue = (le32_to_cpu(cmd->tx_status.rate) & | ||
| 385 | AR9170_TX_PHY_QOS_MASK) >> AR9170_TX_PHY_QOS_SHIFT; | ||
| 386 | |||
| 387 | skb = ar9170_find_queued_skb(ar, cmd->tx_status.dst, queue); | ||
| 388 | if (unlikely(!skb)) | ||
| 389 | return ; | ||
| 390 | |||
| 391 | ar9170_handle_tx_status(ar, skb, true, | ||
| 392 | le16_to_cpu(cmd->tx_status.status)); | ||
| 393 | break; | ||
| 394 | } | ||
| 395 | |||
| 396 | case 0xc0: | ||
| 397 | /* | ||
| 398 | * pre-TBTT event | ||
| 399 | */ | ||
| 400 | if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP) | ||
| 401 | queue_work(ar->hw->workqueue, &ar->beacon_work); | ||
| 402 | break; | ||
| 403 | |||
| 404 | case 0xc2: | ||
| 405 | /* | ||
| 406 | * (IBSS) beacon send notification | ||
| 407 | * bytes: 04 c2 XX YY B4 B3 B2 B1 | ||
| 408 | * | ||
| 409 | * XX always 80 | ||
| 410 | * YY always 00 | ||
| 411 | * B1-B4 "should" be the number of send out beacons. | ||
| 412 | */ | ||
| 413 | break; | ||
| 414 | |||
| 415 | case 0xc3: | ||
| 416 | /* End of Atim Window */ | ||
| 417 | break; | ||
| 418 | |||
| 419 | case 0xc4: | ||
| 420 | case 0xc5: | ||
| 421 | /* BlockACK events */ | ||
| 422 | break; | ||
| 423 | |||
| 424 | case 0xc6: | ||
| 425 | /* Watchdog Interrupt */ | ||
| 426 | break; | ||
| 427 | |||
| 428 | case 0xc9: | ||
| 429 | /* retransmission issue / SIFS/EIFS collision ?! */ | ||
| 430 | break; | ||
| 431 | |||
| 432 | default: | ||
| 433 | printk(KERN_INFO "received unhandled event %x\n", cmd->type); | ||
| 434 | print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); | ||
| 435 | break; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | /* | ||
| 440 | * If the frame alignment is right (or the kernel has | ||
| 441 | * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there | ||
| 442 | * is only a single MPDU in the USB frame, then we can | ||
| 443 | * submit to mac80211 the SKB directly. However, since | ||
| 444 | * there may be multiple packets in one SKB in stream | ||
| 445 | * mode, and we need to observe the proper ordering, | ||
| 446 | * this is non-trivial. | ||
| 447 | */ | ||
| 448 | static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) | ||
| 449 | { | ||
| 450 | struct sk_buff *skb; | ||
| 451 | struct ar9170_rx_head *head = (void *)buf; | ||
| 452 | struct ar9170_rx_tail *tail; | ||
| 453 | struct ieee80211_rx_status status; | ||
| 454 | int mpdu_len, i; | ||
| 455 | u8 error, antennas = 0, decrypt; | ||
| 456 | __le16 fc; | ||
| 457 | int reserved; | ||
| 458 | |||
| 459 | if (unlikely(!IS_STARTED(ar))) | ||
| 460 | return ; | ||
| 461 | |||
| 462 | /* Received MPDU */ | ||
| 463 | mpdu_len = len; | ||
| 464 | mpdu_len -= sizeof(struct ar9170_rx_head); | ||
| 465 | mpdu_len -= sizeof(struct ar9170_rx_tail); | ||
| 466 | BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12); | ||
| 467 | BUILD_BUG_ON(sizeof(struct ar9170_rx_tail) != 24); | ||
| 468 | |||
| 469 | if (mpdu_len <= FCS_LEN) | ||
| 470 | return; | ||
| 471 | |||
| 472 | tail = (void *)(buf + sizeof(struct ar9170_rx_head) + mpdu_len); | ||
| 473 | |||
| 474 | for (i = 0; i < 3; i++) | ||
| 475 | if (tail->rssi[i] != 0x80) | ||
| 476 | antennas |= BIT(i); | ||
| 477 | |||
| 478 | /* post-process RSSI */ | ||
| 479 | for (i = 0; i < 7; i++) | ||
| 480 | if (tail->rssi[i] & 0x80) | ||
| 481 | tail->rssi[i] = ((tail->rssi[i] & 0x7f) + 1) & 0x7f; | ||
| 482 | |||
| 483 | memset(&status, 0, sizeof(status)); | ||
| 484 | |||
| 485 | status.band = ar->channel->band; | ||
| 486 | status.freq = ar->channel->center_freq; | ||
| 487 | status.signal = ar->noise[0] + tail->rssi_combined; | ||
| 488 | status.noise = ar->noise[0]; | ||
| 489 | status.antenna = antennas; | ||
| 490 | |||
| 491 | switch (tail->status & AR9170_RX_STATUS_MODULATION_MASK) { | ||
| 492 | case AR9170_RX_STATUS_MODULATION_CCK: | ||
| 493 | if (tail->status & AR9170_RX_STATUS_SHORT_PREAMBLE) | ||
| 494 | status.flag |= RX_FLAG_SHORTPRE; | ||
| 495 | switch (head->plcp[0]) { | ||
| 496 | case 0x0a: | ||
| 497 | status.rate_idx = 0; | ||
| 498 | break; | ||
| 499 | case 0x14: | ||
| 500 | status.rate_idx = 1; | ||
| 501 | break; | ||
| 502 | case 0x37: | ||
| 503 | status.rate_idx = 2; | ||
| 504 | break; | ||
| 505 | case 0x6e: | ||
| 506 | status.rate_idx = 3; | ||
| 507 | break; | ||
| 508 | default: | ||
| 509 | if ((!ar->sniffer_enabled) && (net_ratelimit())) | ||
| 510 | printk(KERN_ERR "%s: invalid plcp cck rate " | ||
| 511 | "(%x).\n", wiphy_name(ar->hw->wiphy), | ||
| 512 | head->plcp[0]); | ||
| 513 | return; | ||
| 514 | } | ||
| 515 | break; | ||
| 516 | case AR9170_RX_STATUS_MODULATION_OFDM: | ||
| 517 | switch (head->plcp[0] & 0xF) { | ||
| 518 | case 0xB: | ||
| 519 | status.rate_idx = 0; | ||
| 520 | break; | ||
| 521 | case 0xF: | ||
| 522 | status.rate_idx = 1; | ||
| 523 | break; | ||
| 524 | case 0xA: | ||
| 525 | status.rate_idx = 2; | ||
| 526 | break; | ||
| 527 | case 0xE: | ||
| 528 | status.rate_idx = 3; | ||
| 529 | break; | ||
| 530 | case 0x9: | ||
| 531 | status.rate_idx = 4; | ||
| 532 | break; | ||
| 533 | case 0xD: | ||
| 534 | status.rate_idx = 5; | ||
| 535 | break; | ||
| 536 | case 0x8: | ||
| 537 | status.rate_idx = 6; | ||
| 538 | break; | ||
| 539 | case 0xC: | ||
| 540 | status.rate_idx = 7; | ||
| 541 | break; | ||
| 542 | default: | ||
| 543 | if ((!ar->sniffer_enabled) && (net_ratelimit())) | ||
| 544 | printk(KERN_ERR "%s: invalid plcp ofdm rate " | ||
| 545 | "(%x).\n", wiphy_name(ar->hw->wiphy), | ||
| 546 | head->plcp[0]); | ||
| 547 | return; | ||
| 548 | } | ||
| 549 | if (status.band == IEEE80211_BAND_2GHZ) | ||
| 550 | status.rate_idx += 4; | ||
| 551 | break; | ||
| 552 | case AR9170_RX_STATUS_MODULATION_HT: | ||
| 553 | case AR9170_RX_STATUS_MODULATION_DUPOFDM: | ||
| 554 | /* XXX */ | ||
| 555 | |||
| 556 | if (net_ratelimit()) | ||
| 557 | printk(KERN_ERR "%s: invalid modulation\n", | ||
| 558 | wiphy_name(ar->hw->wiphy)); | ||
| 559 | return; | ||
| 560 | } | ||
| 561 | |||
| 562 | error = tail->error; | ||
| 563 | |||
| 564 | if (error & AR9170_RX_ERROR_MMIC) { | ||
| 565 | status.flag |= RX_FLAG_MMIC_ERROR; | ||
| 566 | error &= ~AR9170_RX_ERROR_MMIC; | ||
| 567 | } | ||
| 568 | |||
| 569 | if (error & AR9170_RX_ERROR_PLCP) { | ||
| 570 | status.flag |= RX_FLAG_FAILED_PLCP_CRC; | ||
| 571 | error &= ~AR9170_RX_ERROR_PLCP; | ||
| 572 | } | ||
| 573 | |||
| 574 | if (error & AR9170_RX_ERROR_FCS) { | ||
| 575 | status.flag |= RX_FLAG_FAILED_FCS_CRC; | ||
| 576 | error &= ~AR9170_RX_ERROR_FCS; | ||
| 577 | } | ||
| 578 | |||
| 579 | decrypt = ar9170_get_decrypt_type(tail); | ||
| 580 | if (!(decrypt & AR9170_RX_ENC_SOFTWARE) && | ||
| 581 | decrypt != AR9170_ENC_ALG_NONE) | ||
| 582 | status.flag |= RX_FLAG_DECRYPTED; | ||
| 583 | |||
| 584 | /* ignore wrong RA errors */ | ||
| 585 | error &= ~AR9170_RX_ERROR_WRONG_RA; | ||
| 586 | |||
| 587 | if (error & AR9170_RX_ERROR_DECRYPT) { | ||
| 588 | error &= ~AR9170_RX_ERROR_DECRYPT; | ||
| 589 | |||
| 590 | /* | ||
| 591 | * Rx decryption is done in place, | ||
| 592 | * the original data is lost anyway. | ||
| 593 | */ | ||
| 594 | return ; | ||
| 595 | } | ||
| 596 | |||
| 597 | /* drop any other error frames */ | ||
| 598 | if ((error) && (net_ratelimit())) { | ||
| 599 | printk(KERN_DEBUG "%s: errors: %#x\n", | ||
| 600 | wiphy_name(ar->hw->wiphy), error); | ||
| 601 | return; | ||
| 602 | } | ||
| 603 | |||
| 604 | buf += sizeof(struct ar9170_rx_head); | ||
| 605 | fc = *(__le16 *)buf; | ||
| 606 | |||
| 607 | if (ieee80211_is_data_qos(fc) ^ ieee80211_has_a4(fc)) | ||
| 608 | reserved = 32 + 2; | ||
| 609 | else | ||
| 610 | reserved = 32; | ||
| 611 | |||
| 612 | skb = dev_alloc_skb(mpdu_len + reserved); | ||
| 613 | if (!skb) | ||
| 614 | return; | ||
| 615 | |||
| 616 | skb_reserve(skb, reserved); | ||
| 617 | memcpy(skb_put(skb, mpdu_len), buf, mpdu_len); | ||
| 618 | ieee80211_rx_irqsafe(ar->hw, skb, &status); | ||
| 619 | } | ||
| 620 | |||
| 621 | void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) | ||
| 622 | { | ||
| 623 | unsigned int i, tlen, resplen; | ||
| 624 | u8 *tbuf, *respbuf; | ||
| 625 | |||
| 626 | tbuf = skb->data; | ||
| 627 | tlen = skb->len; | ||
| 628 | |||
| 629 | while (tlen >= 4) { | ||
| 630 | int clen = tbuf[1] << 8 | tbuf[0]; | ||
| 631 | int wlen = (clen + 3) & ~3; | ||
| 632 | |||
| 633 | /* | ||
| 634 | * parse stream (if any) | ||
| 635 | */ | ||
| 636 | if (tbuf[2] != 0 || tbuf[3] != 0x4e) { | ||
| 637 | printk(KERN_ERR "%s: missing tag!\n", | ||
| 638 | wiphy_name(ar->hw->wiphy)); | ||
| 639 | return ; | ||
| 640 | } | ||
| 641 | if (wlen > tlen - 4) { | ||
| 642 | printk(KERN_ERR "%s: invalid RX (%d, %d, %d)\n", | ||
| 643 | wiphy_name(ar->hw->wiphy), clen, wlen, tlen); | ||
| 644 | print_hex_dump(KERN_DEBUG, "data: ", | ||
| 645 | DUMP_PREFIX_OFFSET, | ||
| 646 | 16, 1, tbuf, tlen, true); | ||
| 647 | return ; | ||
| 648 | } | ||
| 649 | resplen = clen; | ||
| 650 | respbuf = tbuf + 4; | ||
| 651 | tbuf += wlen + 4; | ||
| 652 | tlen -= wlen + 4; | ||
| 653 | |||
| 654 | i = 0; | ||
| 655 | |||
| 656 | /* weird thing, but this is the same in the original driver */ | ||
| 657 | while (resplen > 2 && i < 12 && | ||
| 658 | respbuf[0] == 0xff && respbuf[1] == 0xff) { | ||
| 659 | i += 2; | ||
| 660 | resplen -= 2; | ||
| 661 | respbuf += 2; | ||
| 662 | } | ||
| 663 | |||
| 664 | if (resplen < 4) | ||
| 665 | continue; | ||
| 666 | |||
| 667 | /* found the 6 * 0xffff marker? */ | ||
| 668 | if (i == 12) | ||
| 669 | ar9170_handle_command_response(ar, respbuf, resplen); | ||
| 670 | else | ||
| 671 | ar9170_handle_mpdu(ar, respbuf, resplen); | ||
| 672 | } | ||
| 673 | |||
| 674 | if (tlen) | ||
| 675 | printk(KERN_ERR "%s: buffer remains!\n", | ||
| 676 | wiphy_name(ar->hw->wiphy)); | ||
| 677 | } | ||
| 678 | |||
| 679 | #define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \ | ||
| 680 | do { \ | ||
| 681 | queue.aifs = ai_fs; \ | ||
| 682 | queue.cw_min = cwmin; \ | ||
| 683 | queue.cw_max = cwmax; \ | ||
| 684 | queue.txop = _txop; \ | ||
| 685 | } while (0) | ||
| 686 | |||
| 687 | static int ar9170_op_start(struct ieee80211_hw *hw) | ||
| 688 | { | ||
| 689 | struct ar9170 *ar = hw->priv; | ||
| 690 | int err, i; | ||
| 691 | |||
| 692 | mutex_lock(&ar->mutex); | ||
| 693 | |||
| 694 | /* reinitialize queues statistics */ | ||
| 695 | memset(&ar->tx_stats, 0, sizeof(ar->tx_stats)); | ||
| 696 | for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++) | ||
| 697 | ar->tx_stats[i].limit = 8; | ||
| 698 | |||
| 699 | /* reset QoS defaults */ | ||
| 700 | AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/ | ||
| 701 | AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */ | ||
| 702 | AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */ | ||
| 703 | AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */ | ||
| 704 | AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */ | ||
| 705 | |||
| 706 | err = ar->open(ar); | ||
| 707 | if (err) | ||
| 708 | goto out; | ||
| 709 | |||
| 710 | err = ar9170_init_mac(ar); | ||
| 711 | if (err) | ||
| 712 | goto out; | ||
| 713 | |||
| 714 | err = ar9170_set_qos(ar); | ||
| 715 | if (err) | ||
| 716 | goto out; | ||
| 717 | |||
| 718 | err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ); | ||
| 719 | if (err) | ||
| 720 | goto out; | ||
| 721 | |||
| 722 | err = ar9170_init_rf(ar); | ||
| 723 | if (err) | ||
| 724 | goto out; | ||
| 725 | |||
| 726 | /* start DMA */ | ||
| 727 | err = ar9170_write_reg(ar, 0x1c3d30, 0x100); | ||
| 728 | if (err) | ||
| 729 | goto out; | ||
| 730 | |||
| 731 | ar->state = AR9170_STARTED; | ||
| 732 | |||
| 733 | out: | ||
| 734 | mutex_unlock(&ar->mutex); | ||
| 735 | return err; | ||
| 736 | } | ||
| 737 | |||
| 738 | static void ar9170_op_stop(struct ieee80211_hw *hw) | ||
| 739 | { | ||
| 740 | struct ar9170 *ar = hw->priv; | ||
| 741 | |||
| 742 | if (IS_STARTED(ar)) | ||
| 743 | ar->state = AR9170_IDLE; | ||
| 744 | |||
| 745 | mutex_lock(&ar->mutex); | ||
| 746 | |||
| 747 | cancel_delayed_work_sync(&ar->tx_status_janitor); | ||
| 748 | cancel_work_sync(&ar->filter_config_work); | ||
| 749 | cancel_work_sync(&ar->beacon_work); | ||
| 750 | skb_queue_purge(&ar->global_tx_status_waste); | ||
| 751 | skb_queue_purge(&ar->global_tx_status); | ||
| 752 | |||
| 753 | if (IS_ACCEPTING_CMD(ar)) { | ||
| 754 | ar9170_set_leds_state(ar, 0); | ||
| 755 | |||
| 756 | /* stop DMA */ | ||
| 757 | ar9170_write_reg(ar, 0x1c3d30, 0); | ||
| 758 | ar->stop(ar); | ||
| 759 | } | ||
| 760 | |||
| 761 | mutex_unlock(&ar->mutex); | ||
| 762 | } | ||
| 763 | |||
| 764 | int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
| 765 | { | ||
| 766 | struct ar9170 *ar = hw->priv; | ||
| 767 | struct ieee80211_hdr *hdr; | ||
| 768 | struct ar9170_tx_control *txc; | ||
| 769 | struct ieee80211_tx_info *info; | ||
| 770 | struct ieee80211_rate *rate = NULL; | ||
| 771 | struct ieee80211_tx_rate *txrate; | ||
| 772 | unsigned int queue = skb_get_queue_mapping(skb); | ||
| 773 | unsigned long flags = 0; | ||
| 774 | struct ar9170_sta_info *sta_info = NULL; | ||
| 775 | u32 power, chains; | ||
| 776 | u16 keytype = 0; | ||
| 777 | u16 len, icv = 0; | ||
| 778 | int err; | ||
| 779 | bool tx_status; | ||
| 780 | |||
| 781 | if (unlikely(!IS_STARTED(ar))) | ||
| 782 | goto err_free; | ||
| 783 | |||
| 784 | hdr = (void *)skb->data; | ||
| 785 | info = IEEE80211_SKB_CB(skb); | ||
| 786 | len = skb->len; | ||
| 787 | |||
| 788 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
| 789 | if (ar->tx_stats[queue].limit < ar->tx_stats[queue].len) { | ||
| 790 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
| 791 | return NETDEV_TX_OK; | ||
| 792 | } | ||
| 793 | |||
| 794 | ar->tx_stats[queue].len++; | ||
| 795 | ar->tx_stats[queue].count++; | ||
| 796 | if (ar->tx_stats[queue].limit == ar->tx_stats[queue].len) | ||
| 797 | ieee80211_stop_queue(hw, queue); | ||
| 798 | |||
| 799 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
| 800 | |||
| 801 | txc = (void *)skb_push(skb, sizeof(*txc)); | ||
| 802 | |||
| 803 | tx_status = (((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) != 0) || | ||
| 804 | ((info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) != 0)); | ||
| 805 | |||
| 806 | if (info->control.hw_key) { | ||
| 807 | icv = info->control.hw_key->icv_len; | ||
| 808 | |||
| 809 | switch (info->control.hw_key->alg) { | ||
| 810 | case ALG_WEP: | ||
| 811 | keytype = AR9170_TX_MAC_ENCR_RC4; | ||
| 812 | break; | ||
| 813 | case ALG_TKIP: | ||
| 814 | keytype = AR9170_TX_MAC_ENCR_RC4; | ||
| 815 | break; | ||
| 816 | case ALG_CCMP: | ||
| 817 | keytype = AR9170_TX_MAC_ENCR_AES; | ||
| 818 | break; | ||
| 819 | default: | ||
| 820 | WARN_ON(1); | ||
| 821 | goto err_dequeue; | ||
| 822 | } | ||
| 823 | } | ||
| 824 | |||
| 825 | /* Length */ | ||
| 826 | txc->length = cpu_to_le16(len + icv + 4); | ||
| 827 | |||
| 828 | txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION | | ||
| 829 | AR9170_TX_MAC_BACKOFF); | ||
| 830 | txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] << | ||
| 831 | AR9170_TX_MAC_QOS_SHIFT); | ||
| 832 | txc->mac_control |= cpu_to_le16(keytype); | ||
| 833 | txc->phy_control = cpu_to_le32(0); | ||
| 834 | |||
| 835 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
| 836 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK); | ||
| 837 | |||
| 838 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | ||
| 839 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR); | ||
| 840 | |||
| 841 | txrate = &info->control.rates[0]; | ||
| 842 | |||
| 843 | if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) | ||
| 844 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS); | ||
| 845 | else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS) | ||
| 846 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS); | ||
| 847 | |||
| 848 | if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD) | ||
| 849 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD); | ||
| 850 | |||
| 851 | if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) | ||
| 852 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE); | ||
| 853 | |||
| 854 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | ||
| 855 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ); | ||
| 856 | /* this works because 40 MHz is 2 and dup is 3 */ | ||
| 857 | if (txrate->flags & IEEE80211_TX_RC_DUP_DATA) | ||
| 858 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP); | ||
| 859 | |||
| 860 | if (txrate->flags & IEEE80211_TX_RC_SHORT_GI) | ||
| 861 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI); | ||
| 862 | |||
| 863 | if (txrate->flags & IEEE80211_TX_RC_MCS) { | ||
| 864 | u32 r = txrate->idx; | ||
| 865 | u8 *txpower; | ||
| 866 | |||
| 867 | r <<= AR9170_TX_PHY_MCS_SHIFT; | ||
| 868 | if (WARN_ON(r & ~AR9170_TX_PHY_MCS_MASK)) | ||
| 869 | goto err_dequeue; | ||
| 870 | txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK); | ||
| 871 | txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT); | ||
| 872 | |||
| 873 | if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) { | ||
| 874 | if (info->band == IEEE80211_BAND_5GHZ) | ||
| 875 | txpower = ar->power_5G_ht40; | ||
| 876 | else | ||
| 877 | txpower = ar->power_2G_ht40; | ||
| 878 | } else { | ||
| 879 | if (info->band == IEEE80211_BAND_5GHZ) | ||
| 880 | txpower = ar->power_5G_ht20; | ||
| 881 | else | ||
| 882 | txpower = ar->power_2G_ht20; | ||
| 883 | } | ||
| 884 | |||
| 885 | power = txpower[(txrate->idx) & 7]; | ||
| 886 | } else { | ||
| 887 | u8 *txpower; | ||
| 888 | u32 mod; | ||
| 889 | u32 phyrate; | ||
| 890 | u8 idx = txrate->idx; | ||
| 891 | |||
| 892 | if (info->band != IEEE80211_BAND_2GHZ) { | ||
| 893 | idx += 4; | ||
| 894 | txpower = ar->power_5G_leg; | ||
| 895 | mod = AR9170_TX_PHY_MOD_OFDM; | ||
| 896 | } else { | ||
| 897 | if (idx < 4) { | ||
| 898 | txpower = ar->power_2G_cck; | ||
| 899 | mod = AR9170_TX_PHY_MOD_CCK; | ||
| 900 | } else { | ||
| 901 | mod = AR9170_TX_PHY_MOD_OFDM; | ||
| 902 | txpower = ar->power_2G_ofdm; | ||
| 903 | } | ||
| 904 | } | ||
| 905 | |||
| 906 | rate = &__ar9170_ratetable[idx]; | ||
| 907 | |||
| 908 | phyrate = rate->hw_value & 0xF; | ||
| 909 | power = txpower[(rate->hw_value & 0x30) >> 4]; | ||
| 910 | phyrate <<= AR9170_TX_PHY_MCS_SHIFT; | ||
| 911 | |||
| 912 | txc->phy_control |= cpu_to_le32(mod); | ||
| 913 | txc->phy_control |= cpu_to_le32(phyrate); | ||
| 914 | } | ||
| 915 | |||
| 916 | power <<= AR9170_TX_PHY_TX_PWR_SHIFT; | ||
| 917 | power &= AR9170_TX_PHY_TX_PWR_MASK; | ||
| 918 | txc->phy_control |= cpu_to_le32(power); | ||
| 919 | |||
| 920 | /* set TX chains */ | ||
| 921 | if (ar->eeprom.tx_mask == 1) { | ||
| 922 | chains = AR9170_TX_PHY_TXCHAIN_1; | ||
| 923 | } else { | ||
| 924 | chains = AR9170_TX_PHY_TXCHAIN_2; | ||
| 925 | |||
| 926 | /* >= 36M legacy OFDM - use only one chain */ | ||
| 927 | if (rate && rate->bitrate >= 360) | ||
| 928 | chains = AR9170_TX_PHY_TXCHAIN_1; | ||
| 929 | } | ||
| 930 | txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT); | ||
| 931 | |||
| 932 | if (tx_status) { | ||
| 933 | txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE); | ||
| 934 | /* | ||
| 935 | * WARNING: | ||
| 936 | * Putting the QoS queue bits into an unexplored territory is | ||
| 937 | * certainly not elegant. | ||
| 938 | * | ||
| 939 | * In my defense: This idea provides a reasonable way to | ||
| 940 | * smuggle valuable information to the tx_status callback. | ||
| 941 | * Also, the idea behind this bit-abuse came straight from | ||
| 942 | * the original driver code. | ||
| 943 | */ | ||
| 944 | |||
| 945 | txc->phy_control |= | ||
| 946 | cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT); | ||
| 947 | |||
| 948 | if (info->control.sta) { | ||
| 949 | sta_info = (void *) info->control.sta->drv_priv; | ||
| 950 | skb_queue_tail(&sta_info->tx_status[queue], skb); | ||
| 951 | } else { | ||
| 952 | skb_queue_tail(&ar->global_tx_status, skb); | ||
| 953 | |||
| 954 | queue_delayed_work(ar->hw->workqueue, | ||
| 955 | &ar->tx_status_janitor, | ||
| 956 | msecs_to_jiffies(100)); | ||
| 957 | } | ||
| 958 | } | ||
| 959 | |||
| 960 | err = ar->tx(ar, skb, tx_status, 0); | ||
| 961 | if (unlikely(tx_status && err)) { | ||
| 962 | if (info->control.sta) | ||
| 963 | skb_unlink(skb, &sta_info->tx_status[queue]); | ||
| 964 | else | ||
| 965 | skb_unlink(skb, &ar->global_tx_status); | ||
| 966 | } | ||
| 967 | |||
| 968 | return NETDEV_TX_OK; | ||
| 969 | |||
| 970 | err_dequeue: | ||
| 971 | spin_lock_irqsave(&ar->tx_stats_lock, flags); | ||
| 972 | ar->tx_stats[queue].len--; | ||
| 973 | ar->tx_stats[queue].count--; | ||
| 974 | spin_unlock_irqrestore(&ar->tx_stats_lock, flags); | ||
| 975 | |||
| 976 | err_free: | ||
| 977 | dev_kfree_skb(skb); | ||
| 978 | return NETDEV_TX_OK; | ||
| 979 | } | ||
| 980 | |||
| 981 | static int ar9170_op_add_interface(struct ieee80211_hw *hw, | ||
| 982 | struct ieee80211_if_init_conf *conf) | ||
| 983 | { | ||
| 984 | struct ar9170 *ar = hw->priv; | ||
| 985 | int err = 0; | ||
| 986 | |||
| 987 | mutex_lock(&ar->mutex); | ||
| 988 | |||
| 989 | if (ar->vif) { | ||
| 990 | err = -EBUSY; | ||
| 991 | goto unlock; | ||
| 992 | } | ||
| 993 | |||
| 994 | ar->vif = conf->vif; | ||
| 995 | memcpy(ar->mac_addr, conf->mac_addr, ETH_ALEN); | ||
| 996 | |||
| 997 | if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { | ||
| 998 | ar->rx_software_decryption = true; | ||
| 999 | ar->disable_offload = true; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | ar->cur_filter = 0; | ||
| 1003 | ar->want_filter = AR9170_MAC_REG_FTF_DEFAULTS; | ||
| 1004 | err = ar9170_update_frame_filter(ar); | ||
| 1005 | if (err) | ||
| 1006 | goto unlock; | ||
| 1007 | |||
| 1008 | err = ar9170_set_operating_mode(ar); | ||
| 1009 | |||
| 1010 | unlock: | ||
| 1011 | mutex_unlock(&ar->mutex); | ||
| 1012 | return err; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | static void ar9170_op_remove_interface(struct ieee80211_hw *hw, | ||
| 1016 | struct ieee80211_if_init_conf *conf) | ||
| 1017 | { | ||
| 1018 | struct ar9170 *ar = hw->priv; | ||
| 1019 | |||
| 1020 | mutex_lock(&ar->mutex); | ||
| 1021 | ar->vif = NULL; | ||
| 1022 | ar->want_filter = 0; | ||
| 1023 | ar9170_update_frame_filter(ar); | ||
| 1024 | ar9170_set_beacon_timers(ar); | ||
| 1025 | dev_kfree_skb(ar->beacon); | ||
| 1026 | ar->beacon = NULL; | ||
| 1027 | ar->sniffer_enabled = false; | ||
| 1028 | ar->rx_software_decryption = false; | ||
| 1029 | ar9170_set_operating_mode(ar); | ||
| 1030 | mutex_unlock(&ar->mutex); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed) | ||
| 1034 | { | ||
| 1035 | struct ar9170 *ar = hw->priv; | ||
| 1036 | int err = 0; | ||
| 1037 | |||
| 1038 | mutex_lock(&ar->mutex); | ||
| 1039 | |||
| 1040 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { | ||
| 1041 | /* TODO */ | ||
| 1042 | err = 0; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { | ||
| 1046 | /* TODO */ | ||
| 1047 | err = 0; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | if (changed & IEEE80211_CONF_CHANGE_PS) { | ||
| 1051 | /* TODO */ | ||
| 1052 | err = 0; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | ||
| 1056 | /* TODO */ | ||
| 1057 | err = 0; | ||
| 1058 | } | ||
| 1059 | |||
| 1060 | if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { | ||
| 1061 | /* | ||
| 1062 | * is it long_frame_max_tx_count or short_frame_max_tx_count? | ||
| 1063 | */ | ||
| 1064 | |||
| 1065 | err = ar9170_set_hwretry_limit(ar, | ||
| 1066 | ar->hw->conf.long_frame_max_tx_count); | ||
| 1067 | if (err) | ||
| 1068 | goto out; | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) { | ||
| 1072 | err = ar9170_set_beacon_timers(ar); | ||
| 1073 | if (err) | ||
| 1074 | goto out; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { | ||
| 1078 | err = ar9170_set_channel(ar, hw->conf.channel, | ||
| 1079 | AR9170_RFI_NONE, AR9170_BW_20); | ||
| 1080 | if (err) | ||
| 1081 | goto out; | ||
| 1082 | /* adjust slot time for 5 GHz */ | ||
| 1083 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) | ||
| 1084 | err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, | ||
| 1085 | 9 << 10); | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | out: | ||
| 1089 | mutex_unlock(&ar->mutex); | ||
| 1090 | return err; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static int ar9170_op_config_interface(struct ieee80211_hw *hw, | ||
| 1094 | struct ieee80211_vif *vif, | ||
| 1095 | struct ieee80211_if_conf *conf) | ||
| 1096 | { | ||
| 1097 | struct ar9170 *ar = hw->priv; | ||
| 1098 | int err = 0; | ||
| 1099 | |||
| 1100 | mutex_lock(&ar->mutex); | ||
| 1101 | |||
| 1102 | if (conf->changed & IEEE80211_IFCC_BSSID) { | ||
| 1103 | memcpy(ar->bssid, conf->bssid, ETH_ALEN); | ||
| 1104 | err = ar9170_set_operating_mode(ar); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | if (conf->changed & IEEE80211_IFCC_BEACON) { | ||
| 1108 | err = ar9170_update_beacon(ar); | ||
| 1109 | |||
| 1110 | if (err) | ||
| 1111 | goto out; | ||
| 1112 | err = ar9170_set_beacon_timers(ar); | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | out: | ||
| 1116 | mutex_unlock(&ar->mutex); | ||
| 1117 | return err; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | static void ar9170_set_filters(struct work_struct *work) | ||
| 1121 | { | ||
| 1122 | struct ar9170 *ar = container_of(work, struct ar9170, | ||
| 1123 | filter_config_work); | ||
| 1124 | int err; | ||
| 1125 | |||
| 1126 | mutex_lock(&ar->mutex); | ||
| 1127 | if (unlikely(!IS_STARTED(ar))) | ||
| 1128 | goto unlock; | ||
| 1129 | |||
| 1130 | if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) { | ||
| 1131 | err = ar9170_set_operating_mode(ar); | ||
| 1132 | if (err) | ||
| 1133 | goto unlock; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) { | ||
| 1137 | err = ar9170_update_multicast(ar); | ||
| 1138 | if (err) | ||
| 1139 | goto unlock; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER) | ||
| 1143 | err = ar9170_update_frame_filter(ar); | ||
| 1144 | |||
| 1145 | unlock: | ||
| 1146 | mutex_unlock(&ar->mutex); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | static void ar9170_op_configure_filter(struct ieee80211_hw *hw, | ||
| 1150 | unsigned int changed_flags, | ||
| 1151 | unsigned int *new_flags, | ||
| 1152 | int mc_count, struct dev_mc_list *mclist) | ||
| 1153 | { | ||
| 1154 | struct ar9170 *ar = hw->priv; | ||
| 1155 | |||
| 1156 | /* mask supported flags */ | ||
| 1157 | *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC | | ||
| 1158 | FIF_PROMISC_IN_BSS; | ||
| 1159 | |||
| 1160 | /* | ||
| 1161 | * We can support more by setting the sniffer bit and | ||
| 1162 | * then checking the error flags, later. | ||
| 1163 | */ | ||
| 1164 | |||
| 1165 | if (changed_flags & FIF_ALLMULTI) { | ||
| 1166 | if (*new_flags & FIF_ALLMULTI) { | ||
| 1167 | ar->want_mc_hash = ~0ULL; | ||
| 1168 | } else { | ||
| 1169 | u64 mchash; | ||
| 1170 | int i; | ||
| 1171 | |||
| 1172 | /* always get broadcast frames */ | ||
| 1173 | mchash = 1ULL << (0xff>>2); | ||
| 1174 | |||
| 1175 | for (i = 0; i < mc_count; i++) { | ||
| 1176 | if (WARN_ON(!mclist)) | ||
| 1177 | break; | ||
| 1178 | mchash |= 1ULL << (mclist->dmi_addr[5] >> 2); | ||
| 1179 | mclist = mclist->next; | ||
| 1180 | } | ||
| 1181 | ar->want_mc_hash = mchash; | ||
| 1182 | } | ||
| 1183 | ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST; | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | if (changed_flags & FIF_CONTROL) { | ||
| 1187 | u32 filter = AR9170_MAC_REG_FTF_PSPOLL | | ||
| 1188 | AR9170_MAC_REG_FTF_RTS | | ||
| 1189 | AR9170_MAC_REG_FTF_CTS | | ||
| 1190 | AR9170_MAC_REG_FTF_ACK | | ||
| 1191 | AR9170_MAC_REG_FTF_CFE | | ||
| 1192 | AR9170_MAC_REG_FTF_CFE_ACK; | ||
| 1193 | |||
| 1194 | if (*new_flags & FIF_CONTROL) | ||
| 1195 | ar->want_filter = ar->cur_filter | filter; | ||
| 1196 | else | ||
| 1197 | ar->want_filter = ar->cur_filter & ~filter; | ||
| 1198 | |||
| 1199 | ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | if (changed_flags & FIF_PROMISC_IN_BSS) { | ||
| 1203 | ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0; | ||
| 1204 | ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC; | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | if (likely(IS_STARTED(ar))) | ||
| 1208 | queue_work(ar->hw->workqueue, &ar->filter_config_work); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw, | ||
| 1212 | struct ieee80211_vif *vif, | ||
| 1213 | struct ieee80211_bss_conf *bss_conf, | ||
| 1214 | u32 changed) | ||
| 1215 | { | ||
| 1216 | struct ar9170 *ar = hw->priv; | ||
| 1217 | int err = 0; | ||
| 1218 | |||
| 1219 | mutex_lock(&ar->mutex); | ||
| 1220 | |||
| 1221 | ar9170_regwrite_begin(ar); | ||
| 1222 | |||
| 1223 | if (changed & BSS_CHANGED_ASSOC) { | ||
| 1224 | ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state; | ||
| 1225 | |||
| 1226 | #ifndef CONFIG_AR9170_LEDS | ||
| 1227 | /* enable assoc LED. */ | ||
| 1228 | err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0); | ||
| 1229 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | if (changed & BSS_CHANGED_HT) { | ||
| 1233 | /* TODO */ | ||
| 1234 | err = 0; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | if (changed & BSS_CHANGED_ERP_SLOT) { | ||
| 1238 | u32 slottime = 20; | ||
| 1239 | |||
| 1240 | if (bss_conf->use_short_slot) | ||
| 1241 | slottime = 9; | ||
| 1242 | |||
| 1243 | ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | if (changed & BSS_CHANGED_BASIC_RATES) { | ||
| 1247 | u32 cck, ofdm; | ||
| 1248 | |||
| 1249 | if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) { | ||
| 1250 | ofdm = bss_conf->basic_rates; | ||
| 1251 | cck = 0; | ||
| 1252 | } else { | ||
| 1253 | /* four cck rates */ | ||
| 1254 | cck = bss_conf->basic_rates & 0xf; | ||
| 1255 | ofdm = bss_conf->basic_rates >> 4; | ||
| 1256 | } | ||
| 1257 | ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, | ||
| 1258 | ofdm << 8 | cck); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | ar9170_regwrite_finish(); | ||
| 1262 | err = ar9170_regwrite_result(); | ||
| 1263 | mutex_unlock(&ar->mutex); | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw) | ||
| 1267 | { | ||
| 1268 | struct ar9170 *ar = hw->priv; | ||
| 1269 | int err; | ||
| 1270 | u32 tsf_low; | ||
| 1271 | u32 tsf_high; | ||
| 1272 | u64 tsf; | ||
| 1273 | |||
| 1274 | mutex_lock(&ar->mutex); | ||
| 1275 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_L, &tsf_low); | ||
| 1276 | if (!err) | ||
| 1277 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TSF_H, &tsf_high); | ||
| 1278 | mutex_unlock(&ar->mutex); | ||
| 1279 | |||
| 1280 | if (WARN_ON(err)) | ||
| 1281 | return 0; | ||
| 1282 | |||
| 1283 | tsf = tsf_high; | ||
| 1284 | tsf = (tsf << 32) | tsf_low; | ||
| 1285 | return tsf; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
| 1289 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
| 1290 | struct ieee80211_key_conf *key) | ||
| 1291 | { | ||
| 1292 | struct ar9170 *ar = hw->priv; | ||
| 1293 | int err = 0, i; | ||
| 1294 | u8 ktype; | ||
| 1295 | |||
| 1296 | if ((!ar->vif) || (ar->disable_offload)) | ||
| 1297 | return -EOPNOTSUPP; | ||
| 1298 | |||
| 1299 | switch (key->alg) { | ||
| 1300 | case ALG_WEP: | ||
| 1301 | if (key->keylen == LEN_WEP40) | ||
| 1302 | ktype = AR9170_ENC_ALG_WEP64; | ||
| 1303 | else | ||
| 1304 | ktype = AR9170_ENC_ALG_WEP128; | ||
| 1305 | break; | ||
| 1306 | case ALG_TKIP: | ||
| 1307 | ktype = AR9170_ENC_ALG_TKIP; | ||
| 1308 | break; | ||
| 1309 | case ALG_CCMP: | ||
| 1310 | ktype = AR9170_ENC_ALG_AESCCMP; | ||
| 1311 | break; | ||
| 1312 | default: | ||
| 1313 | return -EOPNOTSUPP; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | mutex_lock(&ar->mutex); | ||
| 1317 | if (cmd == SET_KEY) { | ||
| 1318 | if (unlikely(!IS_STARTED(ar))) { | ||
| 1319 | err = -EOPNOTSUPP; | ||
| 1320 | goto out; | ||
| 1321 | } | ||
| 1322 | |||
| 1323 | /* group keys need all-zeroes address */ | ||
| 1324 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | ||
| 1325 | sta = NULL; | ||
| 1326 | |||
| 1327 | if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { | ||
| 1328 | for (i = 0; i < 64; i++) | ||
| 1329 | if (!(ar->usedkeys & BIT(i))) | ||
| 1330 | break; | ||
| 1331 | if (i == 64) { | ||
| 1332 | ar->rx_software_decryption = true; | ||
| 1333 | ar9170_set_operating_mode(ar); | ||
| 1334 | err = -ENOSPC; | ||
| 1335 | goto out; | ||
| 1336 | } | ||
| 1337 | } else { | ||
| 1338 | i = 64 + key->keyidx; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | key->hw_key_idx = i; | ||
| 1342 | |||
| 1343 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0, | ||
| 1344 | key->key, min_t(u8, 16, key->keylen)); | ||
| 1345 | if (err) | ||
| 1346 | goto out; | ||
| 1347 | |||
| 1348 | if (key->alg == ALG_TKIP) { | ||
| 1349 | err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, | ||
| 1350 | ktype, 1, key->key + 16, 16); | ||
| 1351 | if (err) | ||
| 1352 | goto out; | ||
| 1353 | |||
| 1354 | /* | ||
| 1355 | * hardware is not capable generating the MMIC | ||
| 1356 | * for fragmented frames! | ||
| 1357 | */ | ||
| 1358 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | if (i < 64) | ||
| 1362 | ar->usedkeys |= BIT(i); | ||
| 1363 | |||
| 1364 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; | ||
| 1365 | } else { | ||
| 1366 | if (unlikely(!IS_STARTED(ar))) { | ||
| 1367 | /* The device is gone... together with the key ;-) */ | ||
| 1368 | err = 0; | ||
| 1369 | goto out; | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | err = ar9170_disable_key(ar, key->hw_key_idx); | ||
| 1373 | if (err) | ||
| 1374 | goto out; | ||
| 1375 | |||
| 1376 | if (key->hw_key_idx < 64) { | ||
| 1377 | ar->usedkeys &= ~BIT(key->hw_key_idx); | ||
| 1378 | } else { | ||
| 1379 | err = ar9170_upload_key(ar, key->hw_key_idx, NULL, | ||
| 1380 | AR9170_ENC_ALG_NONE, 0, | ||
| 1381 | NULL, 0); | ||
| 1382 | if (err) | ||
| 1383 | goto out; | ||
| 1384 | |||
| 1385 | if (key->alg == ALG_TKIP) { | ||
| 1386 | err = ar9170_upload_key(ar, key->hw_key_idx, | ||
| 1387 | NULL, | ||
| 1388 | AR9170_ENC_ALG_NONE, 1, | ||
| 1389 | NULL, 0); | ||
| 1390 | if (err) | ||
| 1391 | goto out; | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | } | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | ar9170_regwrite_begin(ar); | ||
| 1398 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys); | ||
| 1399 | ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32); | ||
| 1400 | ar9170_regwrite_finish(); | ||
| 1401 | err = ar9170_regwrite_result(); | ||
| 1402 | |||
| 1403 | out: | ||
| 1404 | mutex_unlock(&ar->mutex); | ||
| 1405 | |||
| 1406 | return err; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | static void ar9170_sta_notify(struct ieee80211_hw *hw, | ||
| 1410 | struct ieee80211_vif *vif, | ||
| 1411 | enum sta_notify_cmd cmd, | ||
| 1412 | struct ieee80211_sta *sta) | ||
| 1413 | { | ||
| 1414 | struct ar9170 *ar = hw->priv; | ||
| 1415 | struct ar9170_sta_info *info = (void *) sta->drv_priv; | ||
| 1416 | struct sk_buff *skb; | ||
| 1417 | unsigned int i; | ||
| 1418 | |||
| 1419 | switch (cmd) { | ||
| 1420 | case STA_NOTIFY_ADD: | ||
| 1421 | for (i = 0; i < ar->hw->queues; i++) | ||
| 1422 | skb_queue_head_init(&info->tx_status[i]); | ||
| 1423 | break; | ||
| 1424 | |||
| 1425 | case STA_NOTIFY_REMOVE: | ||
| 1426 | |||
| 1427 | /* | ||
| 1428 | * transfer all outstanding frames that need a tx_status | ||
| 1429 | * reports to the global tx_status queue | ||
| 1430 | */ | ||
| 1431 | |||
| 1432 | for (i = 0; i < ar->hw->queues; i++) { | ||
| 1433 | while ((skb = skb_dequeue(&info->tx_status[i]))) { | ||
| 1434 | #ifdef AR9170_QUEUE_DEBUG | ||
| 1435 | printk(KERN_DEBUG "%s: queueing frame in " | ||
| 1436 | "global tx_status queue =>\n", | ||
| 1437 | wiphy_name(ar->hw->wiphy)); | ||
| 1438 | |||
| 1439 | ar9170_print_txheader(ar, skb); | ||
| 1440 | #endif /* AR9170_QUEUE_DEBUG */ | ||
| 1441 | skb_queue_tail(&ar->global_tx_status, skb); | ||
| 1442 | } | ||
| 1443 | } | ||
| 1444 | queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor, | ||
| 1445 | msecs_to_jiffies(100)); | ||
| 1446 | break; | ||
| 1447 | |||
| 1448 | default: | ||
| 1449 | break; | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1453 | static int ar9170_get_stats(struct ieee80211_hw *hw, | ||
| 1454 | struct ieee80211_low_level_stats *stats) | ||
| 1455 | { | ||
| 1456 | struct ar9170 *ar = hw->priv; | ||
| 1457 | u32 val; | ||
| 1458 | int err; | ||
| 1459 | |||
| 1460 | mutex_lock(&ar->mutex); | ||
| 1461 | err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val); | ||
| 1462 | ar->stats.dot11ACKFailureCount += val; | ||
| 1463 | |||
| 1464 | memcpy(stats, &ar->stats, sizeof(*stats)); | ||
| 1465 | mutex_unlock(&ar->mutex); | ||
| 1466 | |||
| 1467 | return 0; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | static int ar9170_get_tx_stats(struct ieee80211_hw *hw, | ||
| 1471 | struct ieee80211_tx_queue_stats *tx_stats) | ||
| 1472 | { | ||
| 1473 | struct ar9170 *ar = hw->priv; | ||
| 1474 | |||
| 1475 | spin_lock_bh(&ar->tx_stats_lock); | ||
| 1476 | memcpy(tx_stats, ar->tx_stats, sizeof(tx_stats[0]) * hw->queues); | ||
| 1477 | spin_unlock_bh(&ar->tx_stats_lock); | ||
| 1478 | |||
| 1479 | return 0; | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | static int ar9170_conf_tx(struct ieee80211_hw *hw, u16 queue, | ||
| 1483 | const struct ieee80211_tx_queue_params *param) | ||
| 1484 | { | ||
| 1485 | struct ar9170 *ar = hw->priv; | ||
| 1486 | int ret; | ||
| 1487 | |||
| 1488 | mutex_lock(&ar->mutex); | ||
| 1489 | if ((param) && !(queue > ar->hw->queues)) { | ||
| 1490 | memcpy(&ar->edcf[ar9170_qos_hwmap[queue]], | ||
| 1491 | param, sizeof(*param)); | ||
| 1492 | |||
| 1493 | ret = ar9170_set_qos(ar); | ||
| 1494 | } else | ||
| 1495 | ret = -EINVAL; | ||
| 1496 | |||
| 1497 | mutex_unlock(&ar->mutex); | ||
| 1498 | return ret; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | static const struct ieee80211_ops ar9170_ops = { | ||
| 1502 | .start = ar9170_op_start, | ||
| 1503 | .stop = ar9170_op_stop, | ||
| 1504 | .tx = ar9170_op_tx, | ||
| 1505 | .add_interface = ar9170_op_add_interface, | ||
| 1506 | .remove_interface = ar9170_op_remove_interface, | ||
| 1507 | .config = ar9170_op_config, | ||
| 1508 | .config_interface = ar9170_op_config_interface, | ||
| 1509 | .configure_filter = ar9170_op_configure_filter, | ||
| 1510 | .conf_tx = ar9170_conf_tx, | ||
| 1511 | .bss_info_changed = ar9170_op_bss_info_changed, | ||
| 1512 | .get_tsf = ar9170_op_get_tsf, | ||
| 1513 | .set_key = ar9170_set_key, | ||
| 1514 | .sta_notify = ar9170_sta_notify, | ||
| 1515 | .get_stats = ar9170_get_stats, | ||
| 1516 | .get_tx_stats = ar9170_get_tx_stats, | ||
| 1517 | }; | ||
| 1518 | |||
| 1519 | void *ar9170_alloc(size_t priv_size) | ||
| 1520 | { | ||
| 1521 | struct ieee80211_hw *hw; | ||
| 1522 | struct ar9170 *ar; | ||
| 1523 | int i; | ||
| 1524 | |||
| 1525 | hw = ieee80211_alloc_hw(priv_size, &ar9170_ops); | ||
| 1526 | if (!hw) | ||
| 1527 | return ERR_PTR(-ENOMEM); | ||
| 1528 | |||
| 1529 | ar = hw->priv; | ||
| 1530 | ar->hw = hw; | ||
| 1531 | |||
| 1532 | mutex_init(&ar->mutex); | ||
| 1533 | spin_lock_init(&ar->cmdlock); | ||
| 1534 | spin_lock_init(&ar->tx_stats_lock); | ||
| 1535 | skb_queue_head_init(&ar->global_tx_status); | ||
| 1536 | skb_queue_head_init(&ar->global_tx_status_waste); | ||
| 1537 | INIT_WORK(&ar->filter_config_work, ar9170_set_filters); | ||
| 1538 | INIT_WORK(&ar->beacon_work, ar9170_new_beacon); | ||
| 1539 | INIT_DELAYED_WORK(&ar->tx_status_janitor, ar9170_tx_status_janitor); | ||
| 1540 | |||
| 1541 | /* all hw supports 2.4 GHz, so set channel to 1 by default */ | ||
| 1542 | ar->channel = &ar9170_2ghz_chantable[0]; | ||
| 1543 | |||
| 1544 | /* first part of wiphy init */ | ||
| 1545 | ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||
| 1546 | BIT(NL80211_IFTYPE_WDS) | | ||
| 1547 | BIT(NL80211_IFTYPE_ADHOC); | ||
| 1548 | ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS | | ||
| 1549 | IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||
| 1550 | IEEE80211_HW_SIGNAL_DBM | | ||
| 1551 | IEEE80211_HW_NOISE_DBM; | ||
| 1552 | |||
| 1553 | ar->hw->queues = __AR9170_NUM_TXQ; | ||
| 1554 | ar->hw->extra_tx_headroom = 8; | ||
| 1555 | ar->hw->sta_data_size = sizeof(struct ar9170_sta_info); | ||
| 1556 | |||
| 1557 | ar->hw->max_rates = 1; | ||
| 1558 | ar->hw->max_rate_tries = 3; | ||
| 1559 | |||
| 1560 | for (i = 0; i < ARRAY_SIZE(ar->noise); i++) | ||
| 1561 | ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */ | ||
| 1562 | |||
| 1563 | return ar; | ||
| 1564 | } | ||
| 1565 | |||
| 1566 | static int ar9170_read_eeprom(struct ar9170 *ar) | ||
| 1567 | { | ||
| 1568 | #define RW 8 /* number of words to read at once */ | ||
| 1569 | #define RB (sizeof(u32) * RW) | ||
| 1570 | DECLARE_MAC_BUF(mbuf); | ||
| 1571 | u8 *eeprom = (void *)&ar->eeprom; | ||
| 1572 | u8 *addr = ar->eeprom.mac_address; | ||
| 1573 | __le32 offsets[RW]; | ||
| 1574 | int i, j, err, bands = 0; | ||
| 1575 | |||
| 1576 | BUILD_BUG_ON(sizeof(ar->eeprom) & 3); | ||
| 1577 | |||
| 1578 | BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4); | ||
| 1579 | #ifndef __CHECKER__ | ||
| 1580 | /* don't want to handle trailing remains */ | ||
| 1581 | BUILD_BUG_ON(sizeof(ar->eeprom) % RB); | ||
| 1582 | #endif | ||
| 1583 | |||
| 1584 | for (i = 0; i < sizeof(ar->eeprom)/RB; i++) { | ||
| 1585 | for (j = 0; j < RW; j++) | ||
| 1586 | offsets[j] = cpu_to_le32(AR9170_EEPROM_START + | ||
| 1587 | RB * i + 4 * j); | ||
| 1588 | |||
| 1589 | err = ar->exec_cmd(ar, AR9170_CMD_RREG, | ||
| 1590 | RB, (u8 *) &offsets, | ||
| 1591 | RB, eeprom + RB * i); | ||
| 1592 | if (err) | ||
| 1593 | return err; | ||
| 1594 | } | ||
| 1595 | |||
| 1596 | #undef RW | ||
| 1597 | #undef RB | ||
| 1598 | |||
| 1599 | if (ar->eeprom.length == cpu_to_le16(0xFFFF)) | ||
| 1600 | return -ENODATA; | ||
| 1601 | |||
| 1602 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { | ||
| 1603 | ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz; | ||
| 1604 | bands++; | ||
| 1605 | } | ||
| 1606 | if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { | ||
| 1607 | ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz; | ||
| 1608 | bands++; | ||
| 1609 | } | ||
| 1610 | /* | ||
| 1611 | * I measured this, a bandswitch takes roughly | ||
| 1612 | * 135 ms and a frequency switch about 80. | ||
| 1613 | * | ||
| 1614 | * FIXME: measure these values again once EEPROM settings | ||
| 1615 | * are used, that will influence them! | ||
| 1616 | */ | ||
| 1617 | if (bands == 2) | ||
| 1618 | ar->hw->channel_change_time = 135 * 1000; | ||
| 1619 | else | ||
| 1620 | ar->hw->channel_change_time = 80 * 1000; | ||
| 1621 | |||
| 1622 | /* second part of wiphy init */ | ||
| 1623 | SET_IEEE80211_PERM_ADDR(ar->hw, addr); | ||
| 1624 | |||
| 1625 | return bands ? 0 : -EINVAL; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | int ar9170_register(struct ar9170 *ar, struct device *pdev) | ||
| 1629 | { | ||
| 1630 | int err; | ||
| 1631 | |||
| 1632 | /* try to read EEPROM, init MAC addr */ | ||
| 1633 | err = ar9170_read_eeprom(ar); | ||
| 1634 | if (err) | ||
| 1635 | goto err_out; | ||
| 1636 | |||
| 1637 | err = ieee80211_register_hw(ar->hw); | ||
| 1638 | if (err) | ||
| 1639 | goto err_out; | ||
| 1640 | |||
| 1641 | err = ar9170_init_leds(ar); | ||
| 1642 | if (err) | ||
| 1643 | goto err_unreg; | ||
| 1644 | |||
| 1645 | #ifdef CONFIG_AR9170_LEDS | ||
| 1646 | err = ar9170_register_leds(ar); | ||
| 1647 | if (err) | ||
| 1648 | goto err_unreg; | ||
| 1649 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 1650 | |||
| 1651 | dev_info(pdev, "Atheros AR9170 is registered as '%s'\n", | ||
| 1652 | wiphy_name(ar->hw->wiphy)); | ||
| 1653 | |||
| 1654 | return err; | ||
| 1655 | |||
| 1656 | err_unreg: | ||
| 1657 | ieee80211_unregister_hw(ar->hw); | ||
| 1658 | |||
| 1659 | err_out: | ||
| 1660 | return err; | ||
| 1661 | } | ||
| 1662 | |||
| 1663 | void ar9170_unregister(struct ar9170 *ar) | ||
| 1664 | { | ||
| 1665 | #ifdef CONFIG_AR9170_LEDS | ||
| 1666 | ar9170_unregister_leds(ar); | ||
| 1667 | #endif /* CONFIG_AR9170_LEDS */ | ||
| 1668 | |||
| 1669 | ieee80211_unregister_hw(ar->hw); | ||
| 1670 | mutex_destroy(&ar->mutex); | ||
| 1671 | } | ||
diff --git a/drivers/net/wireless/ar9170/phy.c b/drivers/net/wireless/ar9170/phy.c new file mode 100644 index 000000000000..6ce20754b8e7 --- /dev/null +++ b/drivers/net/wireless/ar9170/phy.c | |||
| @@ -0,0 +1,1240 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * PHY and RF code | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; see the file COPYING. If not, see | ||
| 20 | * http://www.gnu.org/licenses/. | ||
| 21 | * | ||
| 22 | * This file incorporates work covered by the following copyright and | ||
| 23 | * permission notice: | ||
| 24 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 25 | * | ||
| 26 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 27 | * purpose with or without fee is hereby granted, provided that the above | ||
| 28 | * copyright notice and this permission notice appear in all copies. | ||
| 29 | * | ||
| 30 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 31 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 32 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 33 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 34 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 35 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 36 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 37 | */ | ||
| 38 | |||
| 39 | #include <linux/bitrev.h> | ||
| 40 | #include "ar9170.h" | ||
| 41 | #include "cmd.h" | ||
| 42 | |||
| 43 | static int ar9170_init_power_cal(struct ar9170 *ar) | ||
| 44 | { | ||
| 45 | ar9170_regwrite_begin(ar); | ||
| 46 | |||
| 47 | ar9170_regwrite(0x1bc000 + 0x993c, 0x7f); | ||
| 48 | ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f); | ||
| 49 | ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f); | ||
| 50 | ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f); | ||
| 51 | ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f); | ||
| 52 | ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f); | ||
| 53 | ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f); | ||
| 54 | ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f); | ||
| 55 | ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f); | ||
| 56 | ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f); | ||
| 57 | |||
| 58 | ar9170_regwrite_finish(); | ||
| 59 | return ar9170_regwrite_result(); | ||
| 60 | } | ||
| 61 | |||
| 62 | struct ar9170_phy_init { | ||
| 63 | u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static struct ar9170_phy_init ar5416_phy_init[] = { | ||
| 67 | { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
| 68 | { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, }, | ||
| 69 | { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 70 | { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, }, | ||
| 71 | { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, }, | ||
| 72 | { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, }, | ||
| 73 | { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, }, | ||
| 74 | { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 75 | { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, }, | ||
| 76 | { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, | ||
| 77 | { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, }, | ||
| 78 | { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, | ||
| 79 | { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 80 | { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, }, | ||
| 81 | { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
| 82 | { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, }, | ||
| 83 | { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, }, | ||
| 84 | { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, }, | ||
| 85 | { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, }, | ||
| 86 | { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, }, | ||
| 87 | { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, }, | ||
| 88 | { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, }, | ||
| 89 | { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, }, | ||
| 90 | { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, }, | ||
| 91 | { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, }, | ||
| 92 | { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, }, | ||
| 93 | { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, }, | ||
| 94 | { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 95 | { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 96 | { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 97 | { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 98 | { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, }, | ||
| 99 | { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, }, | ||
| 100 | { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, }, | ||
| 101 | { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, }, | ||
| 102 | { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, }, | ||
| 103 | { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
| 104 | { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, | ||
| 105 | { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 106 | { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 107 | { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, }, | ||
| 108 | { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, }, | ||
| 109 | { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, }, | ||
| 110 | { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, }, | ||
| 111 | { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, }, | ||
| 112 | { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, }, | ||
| 113 | { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
| 114 | { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, }, | ||
| 115 | { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, }, | ||
| 116 | { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 117 | { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
| 118 | { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 119 | { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 120 | { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 121 | { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 122 | { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 123 | { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 124 | { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 125 | { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 126 | { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 127 | { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 128 | { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
| 129 | { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, }, | ||
| 130 | { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, }, | ||
| 131 | { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, }, | ||
| 132 | { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, }, | ||
| 133 | { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, }, | ||
| 134 | { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, }, | ||
| 135 | { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, }, | ||
| 136 | { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, }, | ||
| 137 | { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, }, | ||
| 138 | { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 139 | { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 140 | { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 141 | { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, }, | ||
| 142 | { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, }, | ||
| 143 | { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, }, | ||
| 144 | { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, }, | ||
| 145 | { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 146 | { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, }, | ||
| 147 | { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 148 | { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, }, | ||
| 149 | { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, }, | ||
| 150 | { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, }, | ||
| 151 | { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, }, | ||
| 152 | { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, }, | ||
| 153 | { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, }, | ||
| 154 | { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, }, | ||
| 155 | { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, }, | ||
| 156 | { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, }, | ||
| 157 | { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, | ||
| 158 | { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, }, | ||
| 159 | { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, }, | ||
| 160 | { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, }, | ||
| 161 | { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, }, | ||
| 162 | { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, }, | ||
| 163 | { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, }, | ||
| 164 | { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, }, | ||
| 165 | { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, }, | ||
| 166 | { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, }, | ||
| 167 | { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, }, | ||
| 168 | { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, }, | ||
| 169 | { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, }, | ||
| 170 | { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, }, | ||
| 171 | { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, }, | ||
| 172 | { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, }, | ||
| 173 | { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, }, | ||
| 174 | { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, }, | ||
| 175 | { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, }, | ||
| 176 | { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, }, | ||
| 177 | { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, }, | ||
| 178 | { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, }, | ||
| 179 | { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, }, | ||
| 180 | { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, }, | ||
| 181 | { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, }, | ||
| 182 | { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, }, | ||
| 183 | { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, }, | ||
| 184 | { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, }, | ||
| 185 | { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, }, | ||
| 186 | { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, }, | ||
| 187 | { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 188 | { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 189 | { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 190 | { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 191 | { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 192 | { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 193 | { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 194 | { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 195 | { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 196 | { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 197 | { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 198 | { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 199 | { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 200 | { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 201 | { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 202 | { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 203 | { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 204 | { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 205 | { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 206 | { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 207 | { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 208 | { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 209 | { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 210 | { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, }, | ||
| 211 | { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 212 | { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
| 213 | { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, }, | ||
| 214 | { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, }, | ||
| 215 | { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, }, | ||
| 216 | { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, }, | ||
| 217 | { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, }, | ||
| 218 | { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, }, | ||
| 219 | { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, }, | ||
| 220 | { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, }, | ||
| 221 | { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, }, | ||
| 222 | { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, }, | ||
| 223 | { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, | ||
| 224 | { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, }, | ||
| 225 | { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, }, | ||
| 226 | { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, }, | ||
| 227 | { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, }, | ||
| 228 | { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, }, | ||
| 229 | { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, }, | ||
| 230 | { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, }, | ||
| 231 | { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, | ||
| 232 | { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, }, | ||
| 233 | { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, }, | ||
| 234 | { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, }, | ||
| 235 | { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, }, | ||
| 236 | { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, }, | ||
| 237 | { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, }, | ||
| 238 | { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, }, | ||
| 239 | { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, }, | ||
| 240 | { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, }, | ||
| 241 | { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, }, | ||
| 242 | { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, }, | ||
| 243 | { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, }, | ||
| 244 | { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, }, | ||
| 245 | { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, }, | ||
| 246 | { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, }, | ||
| 247 | { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, }, | ||
| 248 | { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, }, | ||
| 249 | { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, }, | ||
| 250 | { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, }, | ||
| 251 | { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, }, | ||
| 252 | { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 253 | { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 254 | { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 255 | { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 256 | { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 257 | { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 258 | { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 259 | { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 260 | { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 261 | { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 262 | { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 263 | { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 264 | { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 265 | { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 266 | { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 267 | { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 268 | { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 269 | { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 270 | { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 271 | { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 272 | { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, }, | ||
| 273 | { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, }, | ||
| 274 | { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, }, | ||
| 275 | { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 276 | { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 277 | { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 278 | { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 279 | { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 280 | { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 281 | { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 282 | { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 283 | { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 284 | { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 285 | { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 286 | { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 287 | { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 288 | { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 289 | { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 290 | { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 291 | { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 292 | { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 293 | { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, }, | ||
| 294 | { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, }, | ||
| 295 | { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, }, | ||
| 296 | { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
| 297 | { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, }, | ||
| 298 | { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, }, | ||
| 299 | { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, }, | ||
| 300 | { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, }, | ||
| 301 | { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, }, | ||
| 302 | { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, }, | ||
| 303 | { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, }, | ||
| 304 | { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 305 | { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, }, | ||
| 306 | { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 307 | { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 308 | { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, }, | ||
| 309 | { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, }, | ||
| 310 | { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, }, | ||
| 311 | { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, }, | ||
| 312 | { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, }, | ||
| 313 | { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, }, | ||
| 314 | { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 315 | { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, }, | ||
| 316 | { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, }, | ||
| 317 | { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, }, | ||
| 318 | { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, }, | ||
| 319 | { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 320 | { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
| 321 | { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, }, | ||
| 322 | { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
| 323 | { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, }, | ||
| 324 | { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, }, | ||
| 325 | { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, }, | ||
| 326 | { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, }, | ||
| 327 | { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, }, | ||
| 328 | { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, }, | ||
| 329 | { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, }, | ||
| 330 | { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, }, | ||
| 331 | { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, }, | ||
| 332 | { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, }, | ||
| 333 | { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, }, | ||
| 334 | { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, }, | ||
| 335 | { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 336 | { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 337 | { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 338 | { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 339 | { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 340 | { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 341 | { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 342 | { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
| 343 | { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
| 344 | { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, }, | ||
| 345 | { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, }, | ||
| 346 | { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, }, | ||
| 347 | { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, }, | ||
| 348 | { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 349 | { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 350 | { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
| 351 | { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, }, | ||
| 352 | { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, }, | ||
| 353 | { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 354 | { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 355 | { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 356 | { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 357 | { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 358 | { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 359 | { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 360 | { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 361 | { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 362 | { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 363 | { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 364 | { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 365 | { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 366 | { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, }, | ||
| 367 | { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, | ||
| 368 | { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, }, | ||
| 369 | { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, }, | ||
| 370 | { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, | ||
| 371 | { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, | ||
| 372 | { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
| 373 | { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
| 374 | { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
| 375 | { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, }, | ||
| 376 | { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, }, | ||
| 377 | { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, }, | ||
| 378 | { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, }, | ||
| 379 | { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, }, | ||
| 380 | /* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */ | ||
| 381 | { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, }, | ||
| 382 | { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, }, | ||
| 383 | { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, }, | ||
| 384 | { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, }, | ||
| 385 | { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, }, | ||
| 386 | { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, }, | ||
| 387 | { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, }, | ||
| 388 | { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, }, | ||
| 389 | { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, }, | ||
| 390 | { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, }, | ||
| 391 | { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, }, | ||
| 392 | { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, }, | ||
| 393 | { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, }, | ||
| 394 | { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, }, | ||
| 395 | { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, }, | ||
| 396 | { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, } | ||
| 397 | }; | ||
| 398 | |||
| 399 | int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) | ||
| 400 | { | ||
| 401 | int i, err; | ||
| 402 | u32 val; | ||
| 403 | bool is_2ghz = band == IEEE80211_BAND_2GHZ; | ||
| 404 | bool is_40mhz = false; /* XXX: for now */ | ||
| 405 | |||
| 406 | ar9170_regwrite_begin(ar); | ||
| 407 | |||
| 408 | for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) { | ||
| 409 | if (is_40mhz) { | ||
| 410 | if (is_2ghz) | ||
| 411 | val = ar5416_phy_init[i]._2ghz_40; | ||
| 412 | else | ||
| 413 | val = ar5416_phy_init[i]._5ghz_40; | ||
| 414 | } else { | ||
| 415 | if (is_2ghz) | ||
| 416 | val = ar5416_phy_init[i]._2ghz_20; | ||
| 417 | else | ||
| 418 | val = ar5416_phy_init[i]._5ghz_20; | ||
| 419 | } | ||
| 420 | |||
| 421 | ar9170_regwrite(ar5416_phy_init[i].reg, val); | ||
| 422 | } | ||
| 423 | |||
| 424 | ar9170_regwrite_finish(); | ||
| 425 | err = ar9170_regwrite_result(); | ||
| 426 | if (err) | ||
| 427 | return err; | ||
| 428 | |||
| 429 | /* XXX: use EEPROM data here! */ | ||
| 430 | |||
| 431 | err = ar9170_init_power_cal(ar); | ||
| 432 | if (err) | ||
| 433 | return err; | ||
| 434 | |||
| 435 | /* XXX: remove magic! */ | ||
| 436 | if (is_2ghz) | ||
| 437 | err = ar9170_write_reg(ar, 0x1d4014, 0x5163); | ||
| 438 | else | ||
| 439 | err = ar9170_write_reg(ar, 0x1d4014, 0x5143); | ||
| 440 | |||
| 441 | return err; | ||
| 442 | } | ||
| 443 | |||
| 444 | struct ar9170_rf_init { | ||
| 445 | u32 reg, _5ghz, _2ghz; | ||
| 446 | }; | ||
| 447 | |||
| 448 | static struct ar9170_rf_init ar9170_rf_init[] = { | ||
| 449 | /* bank 0 */ | ||
| 450 | { 0x1c58b0, 0x1e5795e5, 0x1e5795e5}, | ||
| 451 | { 0x1c58e0, 0x02008020, 0x02008020}, | ||
| 452 | /* bank 1 */ | ||
| 453 | { 0x1c58b0, 0x02108421, 0x02108421}, | ||
| 454 | { 0x1c58ec, 0x00000008, 0x00000008}, | ||
| 455 | /* bank 2 */ | ||
| 456 | { 0x1c58b0, 0x0e73ff17, 0x0e73ff17}, | ||
| 457 | { 0x1c58e0, 0x00000420, 0x00000420}, | ||
| 458 | /* bank 3 */ | ||
| 459 | { 0x1c58f0, 0x01400018, 0x01c00018}, | ||
| 460 | /* bank 4 */ | ||
| 461 | { 0x1c58b0, 0x000001a1, 0x000001a1}, | ||
| 462 | { 0x1c58e8, 0x00000001, 0x00000001}, | ||
| 463 | /* bank 5 */ | ||
| 464 | { 0x1c58b0, 0x00000013, 0x00000013}, | ||
| 465 | { 0x1c58e4, 0x00000002, 0x00000002}, | ||
| 466 | /* bank 6 */ | ||
| 467 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 468 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 469 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 470 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 471 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 472 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
| 473 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
| 474 | { 0x1c58b0, 0x00002c00, 0x00002c00}, | ||
| 475 | { 0x1c58b0, 0x00004800, 0x00004800}, | ||
| 476 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
| 477 | { 0x1c58b0, 0x00006000, 0x00006000}, | ||
| 478 | { 0x1c58b0, 0x00001000, 0x00001000}, | ||
| 479 | { 0x1c58b0, 0x00004000, 0x00004000}, | ||
| 480 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 481 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 482 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 483 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 484 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 485 | { 0x1c58b0, 0x00087c00, 0x00087c00}, | ||
| 486 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 487 | { 0x1c58b0, 0x00005400, 0x00005400}, | ||
| 488 | { 0x1c58b0, 0x00000c00, 0x00000c00}, | ||
| 489 | { 0x1c58b0, 0x00001800, 0x00001800}, | ||
| 490 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 491 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
| 492 | { 0x1c58b0, 0x00006c00, 0x00006c00}, | ||
| 493 | { 0x1c58b0, 0x00007c00, 0x00007c00}, | ||
| 494 | { 0x1c58b0, 0x00002c00, 0x00002c00}, | ||
| 495 | { 0x1c58b0, 0x00003c00, 0x00003c00}, | ||
| 496 | { 0x1c58b0, 0x00003800, 0x00003800}, | ||
| 497 | { 0x1c58b0, 0x00001c00, 0x00001c00}, | ||
| 498 | { 0x1c58b0, 0x00000800, 0x00000800}, | ||
| 499 | { 0x1c58b0, 0x00000408, 0x00000408}, | ||
| 500 | { 0x1c58b0, 0x00004c15, 0x00004c15}, | ||
| 501 | { 0x1c58b0, 0x00004188, 0x00004188}, | ||
| 502 | { 0x1c58b0, 0x0000201e, 0x0000201e}, | ||
| 503 | { 0x1c58b0, 0x00010408, 0x00010408}, | ||
| 504 | { 0x1c58b0, 0x00000801, 0x00000801}, | ||
| 505 | { 0x1c58b0, 0x00000c08, 0x00000c08}, | ||
| 506 | { 0x1c58b0, 0x0000181e, 0x0000181e}, | ||
| 507 | { 0x1c58b0, 0x00001016, 0x00001016}, | ||
| 508 | { 0x1c58b0, 0x00002800, 0x00002800}, | ||
| 509 | { 0x1c58b0, 0x00004010, 0x00004010}, | ||
| 510 | { 0x1c58b0, 0x0000081c, 0x0000081c}, | ||
| 511 | { 0x1c58b0, 0x00000115, 0x00000115}, | ||
| 512 | { 0x1c58b0, 0x00000015, 0x00000015}, | ||
| 513 | { 0x1c58b0, 0x00000066, 0x00000066}, | ||
| 514 | { 0x1c58b0, 0x0000001c, 0x0000001c}, | ||
| 515 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 516 | { 0x1c58b0, 0x00000004, 0x00000004}, | ||
| 517 | { 0x1c58b0, 0x00000015, 0x00000015}, | ||
| 518 | { 0x1c58b0, 0x0000001f, 0x0000001f}, | ||
| 519 | { 0x1c58e0, 0x00000000, 0x00000400}, | ||
| 520 | /* bank 7 */ | ||
| 521 | { 0x1c58b0, 0x000000a0, 0x000000a0}, | ||
| 522 | { 0x1c58b0, 0x00000000, 0x00000000}, | ||
| 523 | { 0x1c58b0, 0x00000040, 0x00000040}, | ||
| 524 | { 0x1c58f0, 0x0000001c, 0x0000001c}, | ||
| 525 | }; | ||
| 526 | |||
| 527 | static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz) | ||
| 528 | { | ||
| 529 | int err, i; | ||
| 530 | |||
| 531 | ar9170_regwrite_begin(ar); | ||
| 532 | |||
| 533 | for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++) | ||
| 534 | ar9170_regwrite(ar9170_rf_init[i].reg, | ||
| 535 | band5ghz ? ar9170_rf_init[i]._5ghz | ||
| 536 | : ar9170_rf_init[i]._2ghz); | ||
| 537 | |||
| 538 | ar9170_regwrite_finish(); | ||
| 539 | err = ar9170_regwrite_result(); | ||
| 540 | if (err) | ||
| 541 | printk(KERN_ERR "%s: rf init failed\n", | ||
| 542 | wiphy_name(ar->hw->wiphy)); | ||
| 543 | return err; | ||
| 544 | } | ||
| 545 | |||
| 546 | static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, | ||
| 547 | u32 freq, enum ar9170_bw bw) | ||
| 548 | { | ||
| 549 | int err; | ||
| 550 | u32 d0, d1, td0, td1, fd0, fd1; | ||
| 551 | u8 chansel; | ||
| 552 | u8 refsel0 = 1, refsel1 = 0; | ||
| 553 | u8 lf_synth = 0; | ||
| 554 | |||
| 555 | switch (bw) { | ||
| 556 | case AR9170_BW_40_ABOVE: | ||
| 557 | freq += 10; | ||
| 558 | break; | ||
| 559 | case AR9170_BW_40_BELOW: | ||
| 560 | freq -= 10; | ||
| 561 | break; | ||
| 562 | case AR9170_BW_20: | ||
| 563 | break; | ||
| 564 | case __AR9170_NUM_BW: | ||
| 565 | BUG(); | ||
| 566 | } | ||
| 567 | |||
| 568 | if (band5ghz) { | ||
| 569 | if (freq % 10) { | ||
| 570 | chansel = (freq - 4800) / 5; | ||
| 571 | } else { | ||
| 572 | chansel = ((freq - 4800) / 10) * 2; | ||
| 573 | refsel0 = 0; | ||
| 574 | refsel1 = 1; | ||
| 575 | } | ||
| 576 | chansel = byte_rev_table[chansel]; | ||
| 577 | } else { | ||
| 578 | if (freq == 2484) { | ||
| 579 | chansel = 10 + (freq - 2274) / 5; | ||
| 580 | lf_synth = 1; | ||
| 581 | } else | ||
| 582 | chansel = 16 + (freq - 2272) / 5; | ||
| 583 | chansel *= 4; | ||
| 584 | chansel = byte_rev_table[chansel]; | ||
| 585 | } | ||
| 586 | |||
| 587 | d1 = chansel; | ||
| 588 | d0 = 0x21 | | ||
| 589 | refsel0 << 3 | | ||
| 590 | refsel1 << 2 | | ||
| 591 | lf_synth << 1; | ||
| 592 | td0 = d0 & 0x1f; | ||
| 593 | td1 = d1 & 0x1f; | ||
| 594 | fd0 = td1 << 5 | td0; | ||
| 595 | |||
| 596 | td0 = (d0 >> 5) & 0x7; | ||
| 597 | td1 = (d1 >> 5) & 0x7; | ||
| 598 | fd1 = td1 << 5 | td0; | ||
| 599 | |||
| 600 | ar9170_regwrite_begin(ar); | ||
| 601 | |||
| 602 | ar9170_regwrite(0x1c58b0, fd0); | ||
| 603 | ar9170_regwrite(0x1c58e8, fd1); | ||
| 604 | |||
| 605 | ar9170_regwrite_finish(); | ||
| 606 | err = ar9170_regwrite_result(); | ||
| 607 | if (err) | ||
| 608 | return err; | ||
| 609 | |||
| 610 | msleep(10); | ||
| 611 | |||
| 612 | return 0; | ||
| 613 | } | ||
| 614 | |||
| 615 | struct ar9170_phy_freq_params { | ||
| 616 | u8 coeff_exp; | ||
| 617 | u16 coeff_man; | ||
| 618 | u8 coeff_exp_shgi; | ||
| 619 | u16 coeff_man_shgi; | ||
| 620 | }; | ||
| 621 | |||
| 622 | struct ar9170_phy_freq_entry { | ||
| 623 | u16 freq; | ||
| 624 | struct ar9170_phy_freq_params params[__AR9170_NUM_BW]; | ||
| 625 | }; | ||
| 626 | |||
| 627 | /* NB: must be in sync with channel tables in main! */ | ||
| 628 | static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = { | ||
| 629 | /* | ||
| 630 | * freq, | ||
| 631 | * 20MHz, | ||
| 632 | * 40MHz (below), | ||
| 633 | * 40Mhz (above), | ||
| 634 | */ | ||
| 635 | { 2412, { | ||
| 636 | { 3, 21737, 3, 19563, }, | ||
| 637 | { 3, 21827, 3, 19644, }, | ||
| 638 | { 3, 21647, 3, 19482, }, | ||
| 639 | } }, | ||
| 640 | { 2417, { | ||
| 641 | { 3, 21692, 3, 19523, }, | ||
| 642 | { 3, 21782, 3, 19604, }, | ||
| 643 | { 3, 21602, 3, 19442, }, | ||
| 644 | } }, | ||
| 645 | { 2422, { | ||
| 646 | { 3, 21647, 3, 19482, }, | ||
| 647 | { 3, 21737, 3, 19563, }, | ||
| 648 | { 3, 21558, 3, 19402, }, | ||
| 649 | } }, | ||
| 650 | { 2427, { | ||
| 651 | { 3, 21602, 3, 19442, }, | ||
| 652 | { 3, 21692, 3, 19523, }, | ||
| 653 | { 3, 21514, 3, 19362, }, | ||
| 654 | } }, | ||
| 655 | { 2432, { | ||
| 656 | { 3, 21558, 3, 19402, }, | ||
| 657 | { 3, 21647, 3, 19482, }, | ||
| 658 | { 3, 21470, 3, 19323, }, | ||
| 659 | } }, | ||
| 660 | { 2437, { | ||
| 661 | { 3, 21514, 3, 19362, }, | ||
| 662 | { 3, 21602, 3, 19442, }, | ||
| 663 | { 3, 21426, 3, 19283, }, | ||
| 664 | } }, | ||
| 665 | { 2442, { | ||
| 666 | { 3, 21470, 3, 19323, }, | ||
| 667 | { 3, 21558, 3, 19402, }, | ||
| 668 | { 3, 21382, 3, 19244, }, | ||
| 669 | } }, | ||
| 670 | { 2447, { | ||
| 671 | { 3, 21426, 3, 19283, }, | ||
| 672 | { 3, 21514, 3, 19362, }, | ||
| 673 | { 3, 21339, 3, 19205, }, | ||
| 674 | } }, | ||
| 675 | { 2452, { | ||
| 676 | { 3, 21382, 3, 19244, }, | ||
| 677 | { 3, 21470, 3, 19323, }, | ||
| 678 | { 3, 21295, 3, 19166, }, | ||
| 679 | } }, | ||
| 680 | { 2457, { | ||
| 681 | { 3, 21339, 3, 19205, }, | ||
| 682 | { 3, 21426, 3, 19283, }, | ||
| 683 | { 3, 21252, 3, 19127, }, | ||
| 684 | } }, | ||
| 685 | { 2462, { | ||
| 686 | { 3, 21295, 3, 19166, }, | ||
| 687 | { 3, 21382, 3, 19244, }, | ||
| 688 | { 3, 21209, 3, 19088, }, | ||
| 689 | } }, | ||
| 690 | { 2467, { | ||
| 691 | { 3, 21252, 3, 19127, }, | ||
| 692 | { 3, 21339, 3, 19205, }, | ||
| 693 | { 3, 21166, 3, 19050, }, | ||
| 694 | } }, | ||
| 695 | { 2472, { | ||
| 696 | { 3, 21209, 3, 19088, }, | ||
| 697 | { 3, 21295, 3, 19166, }, | ||
| 698 | { 3, 21124, 3, 19011, }, | ||
| 699 | } }, | ||
| 700 | { 2484, { | ||
| 701 | { 3, 21107, 3, 18996, }, | ||
| 702 | { 3, 21192, 3, 19073, }, | ||
| 703 | { 3, 21022, 3, 18920, }, | ||
| 704 | } }, | ||
| 705 | { 4920, { | ||
| 706 | { 4, 21313, 4, 19181, }, | ||
| 707 | { 4, 21356, 4, 19220, }, | ||
| 708 | { 4, 21269, 4, 19142, }, | ||
| 709 | } }, | ||
| 710 | { 4940, { | ||
| 711 | { 4, 21226, 4, 19104, }, | ||
| 712 | { 4, 21269, 4, 19142, }, | ||
| 713 | { 4, 21183, 4, 19065, }, | ||
| 714 | } }, | ||
| 715 | { 4960, { | ||
| 716 | { 4, 21141, 4, 19027, }, | ||
| 717 | { 4, 21183, 4, 19065, }, | ||
| 718 | { 4, 21098, 4, 18988, }, | ||
| 719 | } }, | ||
| 720 | { 4980, { | ||
| 721 | { 4, 21056, 4, 18950, }, | ||
| 722 | { 4, 21098, 4, 18988, }, | ||
| 723 | { 4, 21014, 4, 18912, }, | ||
| 724 | } }, | ||
| 725 | { 5040, { | ||
| 726 | { 4, 20805, 4, 18725, }, | ||
| 727 | { 4, 20846, 4, 18762, }, | ||
| 728 | { 4, 20764, 4, 18687, }, | ||
| 729 | } }, | ||
| 730 | { 5060, { | ||
| 731 | { 4, 20723, 4, 18651, }, | ||
| 732 | { 4, 20764, 4, 18687, }, | ||
| 733 | { 4, 20682, 4, 18614, }, | ||
| 734 | } }, | ||
| 735 | { 5080, { | ||
| 736 | { 4, 20641, 4, 18577, }, | ||
| 737 | { 4, 20682, 4, 18614, }, | ||
| 738 | { 4, 20601, 4, 18541, }, | ||
| 739 | } }, | ||
| 740 | { 5180, { | ||
| 741 | { 4, 20243, 4, 18219, }, | ||
| 742 | { 4, 20282, 4, 18254, }, | ||
| 743 | { 4, 20204, 4, 18183, }, | ||
| 744 | } }, | ||
| 745 | { 5200, { | ||
| 746 | { 4, 20165, 4, 18148, }, | ||
| 747 | { 4, 20204, 4, 18183, }, | ||
| 748 | { 4, 20126, 4, 18114, }, | ||
| 749 | } }, | ||
| 750 | { 5220, { | ||
| 751 | { 4, 20088, 4, 18079, }, | ||
| 752 | { 4, 20126, 4, 18114, }, | ||
| 753 | { 4, 20049, 4, 18044, }, | ||
| 754 | } }, | ||
| 755 | { 5240, { | ||
| 756 | { 4, 20011, 4, 18010, }, | ||
| 757 | { 4, 20049, 4, 18044, }, | ||
| 758 | { 4, 19973, 4, 17976, }, | ||
| 759 | } }, | ||
| 760 | { 5260, { | ||
| 761 | { 4, 19935, 4, 17941, }, | ||
| 762 | { 4, 19973, 4, 17976, }, | ||
| 763 | { 4, 19897, 4, 17907, }, | ||
| 764 | } }, | ||
| 765 | { 5280, { | ||
| 766 | { 4, 19859, 4, 17873, }, | ||
| 767 | { 4, 19897, 4, 17907, }, | ||
| 768 | { 4, 19822, 4, 17840, }, | ||
| 769 | } }, | ||
| 770 | { 5300, { | ||
| 771 | { 4, 19784, 4, 17806, }, | ||
| 772 | { 4, 19822, 4, 17840, }, | ||
| 773 | { 4, 19747, 4, 17772, }, | ||
| 774 | } }, | ||
| 775 | { 5320, { | ||
| 776 | { 4, 19710, 4, 17739, }, | ||
| 777 | { 4, 19747, 4, 17772, }, | ||
| 778 | { 4, 19673, 4, 17706, }, | ||
| 779 | } }, | ||
| 780 | { 5500, { | ||
| 781 | { 4, 19065, 4, 17159, }, | ||
| 782 | { 4, 19100, 4, 17190, }, | ||
| 783 | { 4, 19030, 4, 17127, }, | ||
| 784 | } }, | ||
| 785 | { 5520, { | ||
| 786 | { 4, 18996, 4, 17096, }, | ||
| 787 | { 4, 19030, 4, 17127, }, | ||
| 788 | { 4, 18962, 4, 17065, }, | ||
| 789 | } }, | ||
| 790 | { 5540, { | ||
| 791 | { 4, 18927, 4, 17035, }, | ||
| 792 | { 4, 18962, 4, 17065, }, | ||
| 793 | { 4, 18893, 4, 17004, }, | ||
| 794 | } }, | ||
| 795 | { 5560, { | ||
| 796 | { 4, 18859, 4, 16973, }, | ||
| 797 | { 4, 18893, 4, 17004, }, | ||
| 798 | { 4, 18825, 4, 16943, }, | ||
| 799 | } }, | ||
| 800 | { 5580, { | ||
| 801 | { 4, 18792, 4, 16913, }, | ||
| 802 | { 4, 18825, 4, 16943, }, | ||
| 803 | { 4, 18758, 4, 16882, }, | ||
| 804 | } }, | ||
| 805 | { 5600, { | ||
| 806 | { 4, 18725, 4, 16852, }, | ||
| 807 | { 4, 18758, 4, 16882, }, | ||
| 808 | { 4, 18691, 4, 16822, }, | ||
| 809 | } }, | ||
| 810 | { 5620, { | ||
| 811 | { 4, 18658, 4, 16792, }, | ||
| 812 | { 4, 18691, 4, 16822, }, | ||
| 813 | { 4, 18625, 4, 16762, }, | ||
| 814 | } }, | ||
| 815 | { 5640, { | ||
| 816 | { 4, 18592, 4, 16733, }, | ||
| 817 | { 4, 18625, 4, 16762, }, | ||
| 818 | { 4, 18559, 4, 16703, }, | ||
| 819 | } }, | ||
| 820 | { 5660, { | ||
| 821 | { 4, 18526, 4, 16673, }, | ||
| 822 | { 4, 18559, 4, 16703, }, | ||
| 823 | { 4, 18493, 4, 16644, }, | ||
| 824 | } }, | ||
| 825 | { 5680, { | ||
| 826 | { 4, 18461, 4, 16615, }, | ||
| 827 | { 4, 18493, 4, 16644, }, | ||
| 828 | { 4, 18428, 4, 16586, }, | ||
| 829 | } }, | ||
| 830 | { 5700, { | ||
| 831 | { 4, 18396, 4, 16556, }, | ||
| 832 | { 4, 18428, 4, 16586, }, | ||
| 833 | { 4, 18364, 4, 16527, }, | ||
| 834 | } }, | ||
| 835 | { 5745, { | ||
| 836 | { 4, 18252, 4, 16427, }, | ||
| 837 | { 4, 18284, 4, 16455, }, | ||
| 838 | { 4, 18220, 4, 16398, }, | ||
| 839 | } }, | ||
| 840 | { 5765, { | ||
| 841 | { 4, 18189, 5, 32740, }, | ||
| 842 | { 4, 18220, 4, 16398, }, | ||
| 843 | { 4, 18157, 5, 32683, }, | ||
| 844 | } }, | ||
| 845 | { 5785, { | ||
| 846 | { 4, 18126, 5, 32626, }, | ||
| 847 | { 4, 18157, 5, 32683, }, | ||
| 848 | { 4, 18094, 5, 32570, }, | ||
| 849 | } }, | ||
| 850 | { 5805, { | ||
| 851 | { 4, 18063, 5, 32514, }, | ||
| 852 | { 4, 18094, 5, 32570, }, | ||
| 853 | { 4, 18032, 5, 32458, }, | ||
| 854 | } }, | ||
| 855 | { 5825, { | ||
| 856 | { 4, 18001, 5, 32402, }, | ||
| 857 | { 4, 18032, 5, 32458, }, | ||
| 858 | { 4, 17970, 5, 32347, }, | ||
| 859 | } }, | ||
| 860 | { 5170, { | ||
| 861 | { 4, 20282, 4, 18254, }, | ||
| 862 | { 4, 20321, 4, 18289, }, | ||
| 863 | { 4, 20243, 4, 18219, }, | ||
| 864 | } }, | ||
| 865 | { 5190, { | ||
| 866 | { 4, 20204, 4, 18183, }, | ||
| 867 | { 4, 20243, 4, 18219, }, | ||
| 868 | { 4, 20165, 4, 18148, }, | ||
| 869 | } }, | ||
| 870 | { 5210, { | ||
| 871 | { 4, 20126, 4, 18114, }, | ||
| 872 | { 4, 20165, 4, 18148, }, | ||
| 873 | { 4, 20088, 4, 18079, }, | ||
| 874 | } }, | ||
| 875 | { 5230, { | ||
| 876 | { 4, 20049, 4, 18044, }, | ||
| 877 | { 4, 20088, 4, 18079, }, | ||
| 878 | { 4, 20011, 4, 18010, }, | ||
| 879 | } }, | ||
| 880 | }; | ||
| 881 | |||
| 882 | static const struct ar9170_phy_freq_params * | ||
| 883 | ar9170_get_hw_dyn_params(struct ieee80211_channel *channel, | ||
| 884 | enum ar9170_bw bw) | ||
| 885 | { | ||
| 886 | unsigned int chanidx = 0; | ||
| 887 | u16 freq = 2412; | ||
| 888 | |||
| 889 | if (channel) { | ||
| 890 | chanidx = channel->hw_value; | ||
| 891 | freq = channel->center_freq; | ||
| 892 | } | ||
| 893 | |||
| 894 | BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params)); | ||
| 895 | |||
| 896 | BUILD_BUG_ON(__AR9170_NUM_BW != 3); | ||
| 897 | |||
| 898 | WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq); | ||
| 899 | |||
| 900 | return &ar9170_phy_freq_params[chanidx].params[bw]; | ||
| 901 | } | ||
| 902 | |||
| 903 | |||
| 904 | int ar9170_init_rf(struct ar9170 *ar) | ||
| 905 | { | ||
| 906 | const struct ar9170_phy_freq_params *freqpar; | ||
| 907 | __le32 cmd[7]; | ||
| 908 | int err; | ||
| 909 | |||
| 910 | err = ar9170_init_rf_banks_0_7(ar, false); | ||
| 911 | if (err) | ||
| 912 | return err; | ||
| 913 | |||
| 914 | err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20); | ||
| 915 | if (err) | ||
| 916 | return err; | ||
| 917 | |||
| 918 | freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20); | ||
| 919 | |||
| 920 | cmd[0] = cpu_to_le32(2412 * 1000); | ||
| 921 | cmd[1] = cpu_to_le32(0); | ||
| 922 | cmd[2] = cpu_to_le32(1); | ||
| 923 | cmd[3] = cpu_to_le32(freqpar->coeff_exp); | ||
| 924 | cmd[4] = cpu_to_le32(freqpar->coeff_man); | ||
| 925 | cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi); | ||
| 926 | cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi); | ||
| 927 | |||
| 928 | /* RF_INIT echoes the command back to us */ | ||
| 929 | err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT, | ||
| 930 | sizeof(cmd), (u8 *)cmd, | ||
| 931 | sizeof(cmd), (u8 *)cmd); | ||
| 932 | if (err) | ||
| 933 | return err; | ||
| 934 | |||
| 935 | msleep(1000); | ||
| 936 | |||
| 937 | return ar9170_echo_test(ar, 0xaabbccdd); | ||
| 938 | } | ||
| 939 | |||
| 940 | static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f) | ||
| 941 | { | ||
| 942 | int idx = nfreqs - 2; | ||
| 943 | |||
| 944 | while (idx >= 0) { | ||
| 945 | if (f >= freqs[idx]) | ||
| 946 | return idx; | ||
| 947 | idx--; | ||
| 948 | } | ||
| 949 | |||
| 950 | return 0; | ||
| 951 | } | ||
| 952 | |||
| 953 | static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) | ||
| 954 | { | ||
| 955 | /* nothing to interpolate, it's horizontal */ | ||
| 956 | if (y2 == y1) | ||
| 957 | return y1; | ||
| 958 | |||
| 959 | /* check if we hit one of the edges */ | ||
| 960 | if (x == x1) | ||
| 961 | return y1; | ||
| 962 | if (x == x2) | ||
| 963 | return y2; | ||
| 964 | |||
| 965 | /* x1 == x2 is bad, hopefully == x */ | ||
| 966 | if (x2 == x1) | ||
| 967 | return y1; | ||
| 968 | |||
| 969 | return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1)); | ||
| 970 | } | ||
| 971 | |||
| 972 | static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2) | ||
| 973 | { | ||
| 974 | #define SHIFT 8 | ||
| 975 | s32 y; | ||
| 976 | |||
| 977 | y = ar9170_interpolate_s32(x << SHIFT, | ||
| 978 | x1 << SHIFT, y1 << SHIFT, | ||
| 979 | x2 << SHIFT, y2 << SHIFT); | ||
| 980 | |||
| 981 | /* | ||
| 982 | * XXX: unwrap this expression | ||
| 983 | * Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)? | ||
| 984 | * Can we rely on the compiler to optimise away the div? | ||
| 985 | */ | ||
| 986 | return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1)); | ||
| 987 | #undef SHIFT | ||
| 988 | } | ||
| 989 | |||
| 990 | static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw) | ||
| 991 | { | ||
| 992 | struct ar9170_calibration_target_power_legacy *ctpl; | ||
| 993 | struct ar9170_calibration_target_power_ht *ctph; | ||
| 994 | u8 *ctpres; | ||
| 995 | int ntargets; | ||
| 996 | int idx, i, n; | ||
| 997 | u8 ackpower, ackchains, f; | ||
| 998 | u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS]; | ||
| 999 | |||
| 1000 | if (freq < 3000) | ||
| 1001 | f = freq - 2300; | ||
| 1002 | else | ||
| 1003 | f = (freq - 4800)/5; | ||
| 1004 | |||
| 1005 | /* | ||
| 1006 | * cycle through the various modes | ||
| 1007 | * | ||
| 1008 | * legacy modes first: 5G, 2G CCK, 2G OFDM | ||
| 1009 | */ | ||
| 1010 | for (i = 0; i < 3; i++) { | ||
| 1011 | switch (i) { | ||
| 1012 | case 0: /* 5 GHz legacy */ | ||
| 1013 | ctpl = &ar->eeprom.cal_tgt_pwr_5G[0]; | ||
| 1014 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
| 1015 | ctpres = ar->power_5G_leg; | ||
| 1016 | break; | ||
| 1017 | case 1: /* 2.4 GHz CCK */ | ||
| 1018 | ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0]; | ||
| 1019 | ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS; | ||
| 1020 | ctpres = ar->power_2G_cck; | ||
| 1021 | break; | ||
| 1022 | case 2: /* 2.4 GHz OFDM */ | ||
| 1023 | ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0]; | ||
| 1024 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
| 1025 | ctpres = ar->power_2G_ofdm; | ||
| 1026 | break; | ||
| 1027 | default: | ||
| 1028 | BUG(); | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | for (n = 0; n < ntargets; n++) { | ||
| 1032 | if (ctpl[n].freq == 0xff) | ||
| 1033 | break; | ||
| 1034 | pwr_freqs[n] = ctpl[n].freq; | ||
| 1035 | } | ||
| 1036 | ntargets = n; | ||
| 1037 | idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); | ||
| 1038 | for (n = 0; n < 4; n++) | ||
| 1039 | ctpres[n] = ar9170_interpolate_u8( | ||
| 1040 | f, | ||
| 1041 | ctpl[idx + 0].freq, | ||
| 1042 | ctpl[idx + 0].power[n], | ||
| 1043 | ctpl[idx + 1].freq, | ||
| 1044 | ctpl[idx + 1].power[n]); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | /* | ||
| 1048 | * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40 | ||
| 1049 | */ | ||
| 1050 | for (i = 0; i < 4; i++) { | ||
| 1051 | switch (i) { | ||
| 1052 | case 0: /* 5 GHz HT 20 */ | ||
| 1053 | ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0]; | ||
| 1054 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
| 1055 | ctpres = ar->power_5G_ht20; | ||
| 1056 | break; | ||
| 1057 | case 1: /* 5 GHz HT 40 */ | ||
| 1058 | ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0]; | ||
| 1059 | ntargets = AR5416_NUM_5G_TARGET_PWRS; | ||
| 1060 | ctpres = ar->power_5G_ht40; | ||
| 1061 | break; | ||
| 1062 | case 2: /* 2.4 GHz HT 20 */ | ||
| 1063 | ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0]; | ||
| 1064 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
| 1065 | ctpres = ar->power_2G_ht20; | ||
| 1066 | break; | ||
| 1067 | case 3: /* 2.4 GHz HT 40 */ | ||
| 1068 | ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0]; | ||
| 1069 | ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS; | ||
| 1070 | ctpres = ar->power_2G_ht40; | ||
| 1071 | break; | ||
| 1072 | default: | ||
| 1073 | BUG(); | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | for (n = 0; n < ntargets; n++) { | ||
| 1077 | if (ctph[n].freq == 0xff) | ||
| 1078 | break; | ||
| 1079 | pwr_freqs[n] = ctph[n].freq; | ||
| 1080 | } | ||
| 1081 | ntargets = n; | ||
| 1082 | idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f); | ||
| 1083 | for (n = 0; n < 8; n++) | ||
| 1084 | ctpres[n] = ar9170_interpolate_u8( | ||
| 1085 | f, | ||
| 1086 | ctph[idx + 0].freq, | ||
| 1087 | ctph[idx + 0].power[n], | ||
| 1088 | ctph[idx + 1].freq, | ||
| 1089 | ctph[idx + 1].power[n]); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | /* set ACK/CTS TX power */ | ||
| 1093 | ar9170_regwrite_begin(ar); | ||
| 1094 | |||
| 1095 | if (ar->eeprom.tx_mask != 1) | ||
| 1096 | ackchains = AR9170_TX_PHY_TXCHAIN_2; | ||
| 1097 | else | ||
| 1098 | ackchains = AR9170_TX_PHY_TXCHAIN_1; | ||
| 1099 | |||
| 1100 | if (freq < 3000) | ||
| 1101 | ackpower = ar->power_2G_ofdm[0] & 0x3f; | ||
| 1102 | else | ||
| 1103 | ackpower = ar->power_5G_leg[0] & 0x3f; | ||
| 1104 | |||
| 1105 | ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26); | ||
| 1106 | ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 | | ||
| 1107 | ackpower << 21 | ackchains << 27); | ||
| 1108 | |||
| 1109 | ar9170_regwrite_finish(); | ||
| 1110 | return ar9170_regwrite_result(); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | static int ar9170_calc_noise_dbm(u32 raw_noise) | ||
| 1114 | { | ||
| 1115 | if (raw_noise & 0x100) | ||
| 1116 | return ~((raw_noise & 0x0ff) >> 1); | ||
| 1117 | else | ||
| 1118 | return (raw_noise & 0xff) >> 1; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, | ||
| 1122 | enum ar9170_rf_init_mode rfi, enum ar9170_bw bw) | ||
| 1123 | { | ||
| 1124 | const struct ar9170_phy_freq_params *freqpar; | ||
| 1125 | u32 cmd, tmp, offs; | ||
| 1126 | __le32 vals[8]; | ||
| 1127 | int i, err; | ||
| 1128 | bool bandswitch; | ||
| 1129 | |||
| 1130 | /* clear BB heavy clip enable */ | ||
| 1131 | err = ar9170_write_reg(ar, 0x1c59e0, 0x200); | ||
| 1132 | if (err) | ||
| 1133 | return err; | ||
| 1134 | |||
| 1135 | /* may be NULL at first setup */ | ||
| 1136 | if (ar->channel) | ||
| 1137 | bandswitch = ar->channel->band != channel->band; | ||
| 1138 | else | ||
| 1139 | bandswitch = true; | ||
| 1140 | |||
| 1141 | /* HW workaround */ | ||
| 1142 | if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] && | ||
| 1143 | channel->center_freq <= 2417) | ||
| 1144 | bandswitch = true; | ||
| 1145 | |||
| 1146 | err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL); | ||
| 1147 | if (err) | ||
| 1148 | return err; | ||
| 1149 | |||
| 1150 | if (rfi != AR9170_RFI_NONE || bandswitch) { | ||
| 1151 | u32 val = 0x400; | ||
| 1152 | |||
| 1153 | if (rfi == AR9170_RFI_COLD) | ||
| 1154 | val = 0x800; | ||
| 1155 | |||
| 1156 | /* warm/cold reset BB/ADDA */ | ||
| 1157 | err = ar9170_write_reg(ar, 0x1d4004, val); | ||
| 1158 | if (err) | ||
| 1159 | return err; | ||
| 1160 | |||
| 1161 | err = ar9170_write_reg(ar, 0x1d4004, 0x0); | ||
| 1162 | if (err) | ||
| 1163 | return err; | ||
| 1164 | |||
| 1165 | err = ar9170_init_phy(ar, channel->band); | ||
| 1166 | if (err) | ||
| 1167 | return err; | ||
| 1168 | |||
| 1169 | err = ar9170_init_rf_banks_0_7(ar, | ||
| 1170 | channel->band == IEEE80211_BAND_5GHZ); | ||
| 1171 | if (err) | ||
| 1172 | return err; | ||
| 1173 | |||
| 1174 | cmd = AR9170_CMD_RF_INIT; | ||
| 1175 | } else { | ||
| 1176 | cmd = AR9170_CMD_FREQUENCY; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | err = ar9170_init_rf_bank4_pwr(ar, | ||
| 1180 | channel->band == IEEE80211_BAND_5GHZ, | ||
| 1181 | channel->center_freq, bw); | ||
| 1182 | if (err) | ||
| 1183 | return err; | ||
| 1184 | |||
| 1185 | switch (bw) { | ||
| 1186 | case AR9170_BW_20: | ||
| 1187 | tmp = 0x240; | ||
| 1188 | offs = 0; | ||
| 1189 | break; | ||
| 1190 | case AR9170_BW_40_BELOW: | ||
| 1191 | tmp = 0x2c4; | ||
| 1192 | offs = 3; | ||
| 1193 | break; | ||
| 1194 | case AR9170_BW_40_ABOVE: | ||
| 1195 | tmp = 0x2d4; | ||
| 1196 | offs = 1; | ||
| 1197 | break; | ||
| 1198 | default: | ||
| 1199 | BUG(); | ||
| 1200 | return -ENOSYS; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | if (0 /* 2 streams capable */) | ||
| 1204 | tmp |= 0x100; | ||
| 1205 | |||
| 1206 | err = ar9170_write_reg(ar, 0x1c5804, tmp); | ||
| 1207 | if (err) | ||
| 1208 | return err; | ||
| 1209 | |||
| 1210 | err = ar9170_set_power_cal(ar, channel->center_freq, bw); | ||
| 1211 | if (err) | ||
| 1212 | return err; | ||
| 1213 | |||
| 1214 | freqpar = ar9170_get_hw_dyn_params(channel, bw); | ||
| 1215 | |||
| 1216 | vals[0] = cpu_to_le32(channel->center_freq * 1000); | ||
| 1217 | vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1); | ||
| 1218 | vals[2] = cpu_to_le32(offs << 2 | 1); | ||
| 1219 | vals[3] = cpu_to_le32(freqpar->coeff_exp); | ||
| 1220 | vals[4] = cpu_to_le32(freqpar->coeff_man); | ||
| 1221 | vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi); | ||
| 1222 | vals[6] = cpu_to_le32(freqpar->coeff_man_shgi); | ||
| 1223 | vals[7] = cpu_to_le32(1000); | ||
| 1224 | |||
| 1225 | err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals, | ||
| 1226 | sizeof(vals), (u8 *)vals); | ||
| 1227 | if (err) | ||
| 1228 | return err; | ||
| 1229 | |||
| 1230 | for (i = 0; i < 2; i++) { | ||
| 1231 | ar->noise[i] = ar9170_calc_noise_dbm( | ||
| 1232 | (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff); | ||
| 1233 | |||
| 1234 | ar->noise[i + 2] = ar9170_calc_noise_dbm( | ||
| 1235 | (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff); | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | ar->channel = channel; | ||
| 1239 | return 0; | ||
| 1240 | } | ||
diff --git a/drivers/net/wireless/ar9170/usb.c b/drivers/net/wireless/ar9170/usb.c new file mode 100644 index 000000000000..ad296840893e --- /dev/null +++ b/drivers/net/wireless/ar9170/usb.c | |||
| @@ -0,0 +1,748 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 driver | ||
| 3 | * | ||
| 4 | * USB - frontend | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; see the file COPYING. If not, see | ||
| 21 | * http://www.gnu.org/licenses/. | ||
| 22 | * | ||
| 23 | * This file incorporates work covered by the following copyright and | ||
| 24 | * permission notice: | ||
| 25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 26 | * | ||
| 27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 28 | * purpose with or without fee is hereby granted, provided that the above | ||
| 29 | * copyright notice and this permission notice appear in all copies. | ||
| 30 | * | ||
| 31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <linux/module.h> | ||
| 41 | #include <linux/usb.h> | ||
| 42 | #include <linux/firmware.h> | ||
| 43 | #include <linux/etherdevice.h> | ||
| 44 | #include <net/mac80211.h> | ||
| 45 | #include "ar9170.h" | ||
| 46 | #include "cmd.h" | ||
| 47 | #include "hw.h" | ||
| 48 | #include "usb.h" | ||
| 49 | |||
| 50 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 51 | MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); | ||
| 52 | MODULE_LICENSE("GPL"); | ||
| 53 | MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless"); | ||
| 54 | MODULE_FIRMWARE("ar9170-1.fw"); | ||
| 55 | MODULE_FIRMWARE("ar9170-2.fw"); | ||
| 56 | |||
| 57 | static struct usb_device_id ar9170_usb_ids[] = { | ||
| 58 | /* Atheros 9170 */ | ||
| 59 | { USB_DEVICE(0x0cf3, 0x9170) }, | ||
| 60 | /* Atheros TG121N */ | ||
| 61 | { USB_DEVICE(0x0cf3, 0x1001) }, | ||
| 62 | /* D-Link DWA 160A */ | ||
| 63 | { USB_DEVICE(0x07d1, 0x3c10) }, | ||
| 64 | /* Netgear WNDA3100 */ | ||
| 65 | { USB_DEVICE(0x0846, 0x9010) }, | ||
| 66 | /* Netgear WN111 v2 */ | ||
| 67 | { USB_DEVICE(0x0846, 0x9001) }, | ||
| 68 | /* Zydas ZD1221 */ | ||
| 69 | { USB_DEVICE(0x0ace, 0x1221) }, | ||
| 70 | /* Z-Com UB81 BG */ | ||
| 71 | { USB_DEVICE(0x0cde, 0x0023) }, | ||
| 72 | /* Z-Com UB82 ABG */ | ||
| 73 | { USB_DEVICE(0x0cde, 0x0026) }, | ||
| 74 | /* Arcadyan WN7512 */ | ||
| 75 | { USB_DEVICE(0x083a, 0xf522) }, | ||
| 76 | /* Planex GWUS300 */ | ||
| 77 | { USB_DEVICE(0x2019, 0x5304) }, | ||
| 78 | /* IO-Data WNGDNUS2 */ | ||
| 79 | { USB_DEVICE(0x04bb, 0x093f) }, | ||
| 80 | |||
| 81 | /* terminate */ | ||
| 82 | {} | ||
| 83 | }; | ||
| 84 | MODULE_DEVICE_TABLE(usb, ar9170_usb_ids); | ||
| 85 | |||
| 86 | static void ar9170_usb_tx_urb_complete_free(struct urb *urb) | ||
| 87 | { | ||
| 88 | struct sk_buff *skb = urb->context; | ||
| 89 | struct ar9170_usb *aru = (struct ar9170_usb *) | ||
| 90 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
| 91 | |||
| 92 | if (!aru) { | ||
| 93 | dev_kfree_skb_irq(skb); | ||
| 94 | return ; | ||
| 95 | } | ||
| 96 | |||
| 97 | ar9170_handle_tx_status(&aru->common, skb, false, | ||
| 98 | AR9170_TX_STATUS_COMPLETE); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void ar9170_usb_tx_urb_complete(struct urb *urb) | ||
| 102 | { | ||
| 103 | } | ||
| 104 | |||
| 105 | static void ar9170_usb_irq_completed(struct urb *urb) | ||
| 106 | { | ||
| 107 | struct ar9170_usb *aru = urb->context; | ||
| 108 | |||
| 109 | switch (urb->status) { | ||
| 110 | /* everything is fine */ | ||
| 111 | case 0: | ||
| 112 | break; | ||
| 113 | |||
| 114 | /* disconnect */ | ||
| 115 | case -ENOENT: | ||
| 116 | case -ECONNRESET: | ||
| 117 | case -ENODEV: | ||
| 118 | case -ESHUTDOWN: | ||
| 119 | goto free; | ||
| 120 | |||
| 121 | default: | ||
| 122 | goto resubmit; | ||
| 123 | } | ||
| 124 | |||
| 125 | print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET, | ||
| 126 | urb->transfer_buffer, urb->actual_length); | ||
| 127 | |||
| 128 | resubmit: | ||
| 129 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
| 130 | if (usb_submit_urb(urb, GFP_ATOMIC)) { | ||
| 131 | usb_unanchor_urb(urb); | ||
| 132 | goto free; | ||
| 133 | } | ||
| 134 | |||
| 135 | return; | ||
| 136 | |||
| 137 | free: | ||
| 138 | usb_buffer_free(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma); | ||
| 139 | } | ||
| 140 | |||
| 141 | static void ar9170_usb_rx_completed(struct urb *urb) | ||
| 142 | { | ||
| 143 | struct sk_buff *skb = urb->context; | ||
| 144 | struct ar9170_usb *aru = (struct ar9170_usb *) | ||
| 145 | usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); | ||
| 146 | int err; | ||
| 147 | |||
| 148 | if (!aru) | ||
| 149 | goto free; | ||
| 150 | |||
| 151 | switch (urb->status) { | ||
| 152 | /* everything is fine */ | ||
| 153 | case 0: | ||
| 154 | break; | ||
| 155 | |||
| 156 | /* disconnect */ | ||
| 157 | case -ENOENT: | ||
| 158 | case -ECONNRESET: | ||
| 159 | case -ENODEV: | ||
| 160 | case -ESHUTDOWN: | ||
| 161 | goto free; | ||
| 162 | |||
| 163 | default: | ||
| 164 | goto resubmit; | ||
| 165 | } | ||
| 166 | |||
| 167 | skb_put(skb, urb->actual_length); | ||
| 168 | ar9170_rx(&aru->common, skb); | ||
| 169 | |||
| 170 | resubmit: | ||
| 171 | skb_reset_tail_pointer(skb); | ||
| 172 | skb_trim(skb, 0); | ||
| 173 | |||
| 174 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
| 175 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 176 | if (err) { | ||
| 177 | usb_unanchor_urb(urb); | ||
| 178 | dev_kfree_skb_irq(skb); | ||
| 179 | } | ||
| 180 | |||
| 181 | return ; | ||
| 182 | |||
| 183 | free: | ||
| 184 | dev_kfree_skb_irq(skb); | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru, | ||
| 189 | struct urb *urb, gfp_t gfp) | ||
| 190 | { | ||
| 191 | struct sk_buff *skb; | ||
| 192 | |||
| 193 | skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp); | ||
| 194 | if (!skb) | ||
| 195 | return -ENOMEM; | ||
| 196 | |||
| 197 | /* reserve some space for mac80211's radiotap */ | ||
| 198 | skb_reserve(skb, 32); | ||
| 199 | |||
| 200 | usb_fill_bulk_urb(urb, aru->udev, | ||
| 201 | usb_rcvbulkpipe(aru->udev, AR9170_EP_RX), | ||
| 202 | skb->data, min(skb_tailroom(skb), | ||
| 203 | AR9170_MAX_RX_BUFFER_SIZE), | ||
| 204 | ar9170_usb_rx_completed, skb); | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru) | ||
| 210 | { | ||
| 211 | struct urb *urb = NULL; | ||
| 212 | void *ibuf; | ||
| 213 | int err = -ENOMEM; | ||
| 214 | |||
| 215 | /* initialize interrupt endpoint */ | ||
| 216 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 217 | if (!urb) | ||
| 218 | goto out; | ||
| 219 | |||
| 220 | ibuf = usb_buffer_alloc(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma); | ||
| 221 | if (!ibuf) | ||
| 222 | goto out; | ||
| 223 | |||
| 224 | usb_fill_int_urb(urb, aru->udev, | ||
| 225 | usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf, | ||
| 226 | 64, ar9170_usb_irq_completed, aru, 1); | ||
| 227 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
| 228 | |||
| 229 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
| 230 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
| 231 | if (err) { | ||
| 232 | usb_unanchor_urb(urb); | ||
| 233 | usb_buffer_free(aru->udev, 64, urb->transfer_buffer, | ||
| 234 | urb->transfer_dma); | ||
| 235 | } | ||
| 236 | |||
| 237 | out: | ||
| 238 | usb_free_urb(urb); | ||
| 239 | return err; | ||
| 240 | } | ||
| 241 | |||
| 242 | static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru) | ||
| 243 | { | ||
| 244 | struct urb *urb; | ||
| 245 | int i; | ||
| 246 | int err = -EINVAL; | ||
| 247 | |||
| 248 | for (i = 0; i < AR9170_NUM_RX_URBS; i++) { | ||
| 249 | err = -ENOMEM; | ||
| 250 | urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 251 | if (!urb) | ||
| 252 | goto err_out; | ||
| 253 | |||
| 254 | err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL); | ||
| 255 | if (err) { | ||
| 256 | usb_free_urb(urb); | ||
| 257 | goto err_out; | ||
| 258 | } | ||
| 259 | |||
| 260 | usb_anchor_urb(urb, &aru->rx_submitted); | ||
| 261 | err = usb_submit_urb(urb, GFP_KERNEL); | ||
| 262 | if (err) { | ||
| 263 | usb_unanchor_urb(urb); | ||
| 264 | dev_kfree_skb_any((void *) urb->transfer_buffer); | ||
| 265 | usb_free_urb(urb); | ||
| 266 | goto err_out; | ||
| 267 | } | ||
| 268 | usb_free_urb(urb); | ||
| 269 | } | ||
| 270 | |||
| 271 | /* the device now waiting for a firmware. */ | ||
| 272 | aru->common.state = AR9170_IDLE; | ||
| 273 | return 0; | ||
| 274 | |||
| 275 | err_out: | ||
| 276 | |||
| 277 | usb_kill_anchored_urbs(&aru->rx_submitted); | ||
| 278 | return err; | ||
| 279 | } | ||
| 280 | |||
| 281 | static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru) | ||
| 282 | { | ||
| 283 | int ret; | ||
| 284 | |||
| 285 | aru->common.state = AR9170_UNKNOWN_STATE; | ||
| 286 | |||
| 287 | usb_unlink_anchored_urbs(&aru->tx_submitted); | ||
| 288 | |||
| 289 | /* give the LED OFF command and the deauth frame a chance to air. */ | ||
| 290 | ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, | ||
| 291 | msecs_to_jiffies(100)); | ||
| 292 | if (ret == 0) | ||
| 293 | dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); | ||
| 294 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
| 295 | |||
| 296 | usb_poison_anchored_urbs(&aru->rx_submitted); | ||
| 297 | } | ||
| 298 | |||
| 299 | static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd, | ||
| 300 | unsigned int plen, void *payload, | ||
| 301 | unsigned int outlen, void *out) | ||
| 302 | { | ||
| 303 | struct ar9170_usb *aru = (void *) ar; | ||
| 304 | struct urb *urb = NULL; | ||
| 305 | unsigned long flags; | ||
| 306 | int err = -ENOMEM; | ||
| 307 | |||
| 308 | if (unlikely(!IS_ACCEPTING_CMD(ar))) | ||
| 309 | return -EPERM; | ||
| 310 | |||
| 311 | if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4)) | ||
| 312 | return -EINVAL; | ||
| 313 | |||
| 314 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 315 | if (unlikely(!urb)) | ||
| 316 | goto err_free; | ||
| 317 | |||
| 318 | ar->cmdbuf[0] = cpu_to_le32(plen); | ||
| 319 | ar->cmdbuf[0] |= cpu_to_le32(cmd << 8); | ||
| 320 | /* writing multiple regs fills this buffer already */ | ||
| 321 | if (plen && payload != (u8 *)(&ar->cmdbuf[1])) | ||
| 322 | memcpy(&ar->cmdbuf[1], payload, plen); | ||
| 323 | |||
| 324 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
| 325 | aru->readbuf = (u8 *)out; | ||
| 326 | aru->readlen = outlen; | ||
| 327 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
| 328 | |||
| 329 | usb_fill_int_urb(urb, aru->udev, | ||
| 330 | usb_sndbulkpipe(aru->udev, AR9170_EP_CMD), | ||
| 331 | aru->common.cmdbuf, plen + 4, | ||
| 332 | ar9170_usb_tx_urb_complete, NULL, 1); | ||
| 333 | |||
| 334 | usb_anchor_urb(urb, &aru->tx_submitted); | ||
| 335 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 336 | if (err) { | ||
| 337 | usb_unanchor_urb(urb); | ||
| 338 | usb_free_urb(urb); | ||
| 339 | goto err_unbuf; | ||
| 340 | } | ||
| 341 | usb_free_urb(urb); | ||
| 342 | |||
| 343 | err = wait_for_completion_timeout(&aru->cmd_wait, HZ); | ||
| 344 | if (err == 0) { | ||
| 345 | err = -ETIMEDOUT; | ||
| 346 | goto err_unbuf; | ||
| 347 | } | ||
| 348 | |||
| 349 | if (outlen >= 0 && aru->readlen != outlen) { | ||
| 350 | err = -EMSGSIZE; | ||
| 351 | goto err_unbuf; | ||
| 352 | } | ||
| 353 | |||
| 354 | return 0; | ||
| 355 | |||
| 356 | err_unbuf: | ||
| 357 | /* Maybe the device was removed in the second we were waiting? */ | ||
| 358 | if (IS_STARTED(ar)) { | ||
| 359 | dev_err(&aru->udev->dev, "no command feedback " | ||
| 360 | "received (%d).\n", err); | ||
| 361 | |||
| 362 | /* provide some maybe useful debug information */ | ||
| 363 | print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE, | ||
| 364 | aru->common.cmdbuf, plen + 4); | ||
| 365 | dump_stack(); | ||
| 366 | } | ||
| 367 | |||
| 368 | /* invalidate to avoid completing the next prematurely */ | ||
| 369 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
| 370 | aru->readbuf = NULL; | ||
| 371 | aru->readlen = 0; | ||
| 372 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
| 373 | |||
| 374 | err_free: | ||
| 375 | |||
| 376 | return err; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb, | ||
| 380 | bool txstatus_needed, unsigned int extra_len) | ||
| 381 | { | ||
| 382 | struct ar9170_usb *aru = (struct ar9170_usb *) ar; | ||
| 383 | struct urb *urb; | ||
| 384 | int err; | ||
| 385 | |||
| 386 | if (unlikely(!IS_STARTED(ar))) { | ||
| 387 | /* Seriously, what were you drink... err... thinking!? */ | ||
| 388 | return -EPERM; | ||
| 389 | } | ||
| 390 | |||
| 391 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 392 | if (unlikely(!urb)) | ||
| 393 | return -ENOMEM; | ||
| 394 | |||
| 395 | usb_fill_bulk_urb(urb, aru->udev, | ||
| 396 | usb_sndbulkpipe(aru->udev, AR9170_EP_TX), | ||
| 397 | skb->data, skb->len + extra_len, (txstatus_needed ? | ||
| 398 | ar9170_usb_tx_urb_complete : | ||
| 399 | ar9170_usb_tx_urb_complete_free), skb); | ||
| 400 | urb->transfer_flags |= URB_ZERO_PACKET; | ||
| 401 | |||
| 402 | usb_anchor_urb(urb, &aru->tx_submitted); | ||
| 403 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 404 | if (unlikely(err)) | ||
| 405 | usb_unanchor_urb(urb); | ||
| 406 | |||
| 407 | usb_free_urb(urb); | ||
| 408 | return err; | ||
| 409 | } | ||
| 410 | |||
| 411 | static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer) | ||
| 412 | { | ||
| 413 | struct ar9170_usb *aru = (void *) ar; | ||
| 414 | unsigned long flags; | ||
| 415 | u32 in, out; | ||
| 416 | |||
| 417 | if (!buffer) | ||
| 418 | return ; | ||
| 419 | |||
| 420 | in = le32_to_cpup((__le32 *)buffer); | ||
| 421 | out = le32_to_cpu(ar->cmdbuf[0]); | ||
| 422 | |||
| 423 | /* mask off length byte */ | ||
| 424 | out &= ~0xFF; | ||
| 425 | |||
| 426 | if (aru->readlen >= 0) { | ||
| 427 | /* add expected length */ | ||
| 428 | out |= aru->readlen; | ||
| 429 | } else { | ||
| 430 | /* add obtained length */ | ||
| 431 | out |= in & 0xFF; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* | ||
| 435 | * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response | ||
| 436 | * length and we cannot predict the correct length in advance. | ||
| 437 | * So we only check if we provided enough space for the data. | ||
| 438 | */ | ||
| 439 | if (unlikely(out < in)) { | ||
| 440 | dev_warn(&aru->udev->dev, "received invalid command response " | ||
| 441 | "got %d bytes, instead of %d bytes " | ||
| 442 | "and the resp length is %d bytes\n", | ||
| 443 | in, out, len); | ||
| 444 | print_hex_dump_bytes("ar9170 invalid resp: ", | ||
| 445 | DUMP_PREFIX_OFFSET, buffer, len); | ||
| 446 | /* | ||
| 447 | * Do not complete, then the command times out, | ||
| 448 | * and we get a stack trace from there. | ||
| 449 | */ | ||
| 450 | return ; | ||
| 451 | } | ||
| 452 | |||
| 453 | spin_lock_irqsave(&aru->common.cmdlock, flags); | ||
| 454 | if (aru->readbuf && len > 0) { | ||
| 455 | memcpy(aru->readbuf, buffer + 4, len - 4); | ||
| 456 | aru->readbuf = NULL; | ||
| 457 | } | ||
| 458 | complete(&aru->cmd_wait); | ||
| 459 | spin_unlock_irqrestore(&aru->common.cmdlock, flags); | ||
| 460 | } | ||
| 461 | |||
| 462 | static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data, | ||
| 463 | size_t len, u32 addr, bool complete) | ||
| 464 | { | ||
| 465 | int transfer, err; | ||
| 466 | u8 *buf = kmalloc(4096, GFP_KERNEL); | ||
| 467 | |||
| 468 | if (!buf) | ||
| 469 | return -ENOMEM; | ||
| 470 | |||
| 471 | while (len) { | ||
| 472 | transfer = min_t(int, len, 4096); | ||
| 473 | memcpy(buf, data, transfer); | ||
| 474 | |||
| 475 | err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), | ||
| 476 | 0x30 /* FW DL */, 0x40 | USB_DIR_OUT, | ||
| 477 | addr >> 8, 0, buf, transfer, 1000); | ||
| 478 | |||
| 479 | if (err < 0) { | ||
| 480 | kfree(buf); | ||
| 481 | return err; | ||
| 482 | } | ||
| 483 | |||
| 484 | len -= transfer; | ||
| 485 | data += transfer; | ||
| 486 | addr += transfer; | ||
| 487 | } | ||
| 488 | kfree(buf); | ||
| 489 | |||
| 490 | if (complete) { | ||
| 491 | err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0), | ||
| 492 | 0x31 /* FW DL COMPLETE */, | ||
| 493 | 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000); | ||
| 494 | } | ||
| 495 | |||
| 496 | return 0; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int ar9170_usb_request_firmware(struct ar9170_usb *aru) | ||
| 500 | { | ||
| 501 | int err = 0; | ||
| 502 | |||
| 503 | err = request_firmware(&aru->init_values, "ar9170-1.fw", | ||
| 504 | &aru->udev->dev); | ||
| 505 | if (err) { | ||
| 506 | dev_err(&aru->udev->dev, "file with init values not found.\n"); | ||
| 507 | return err; | ||
| 508 | } | ||
| 509 | |||
| 510 | err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev); | ||
| 511 | if (err) { | ||
| 512 | release_firmware(aru->init_values); | ||
| 513 | dev_err(&aru->udev->dev, "firmware file not found.\n"); | ||
| 514 | return err; | ||
| 515 | } | ||
| 516 | |||
| 517 | return err; | ||
| 518 | } | ||
| 519 | |||
| 520 | static int ar9170_usb_reset(struct ar9170_usb *aru) | ||
| 521 | { | ||
| 522 | int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING); | ||
| 523 | |||
| 524 | if (lock) { | ||
| 525 | ret = usb_lock_device_for_reset(aru->udev, aru->intf); | ||
| 526 | if (ret < 0) { | ||
| 527 | dev_err(&aru->udev->dev, "unable to lock device " | ||
| 528 | "for reset (%d).\n", ret); | ||
| 529 | return ret; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | ret = usb_reset_device(aru->udev); | ||
| 534 | if (lock) | ||
| 535 | usb_unlock_device(aru->udev); | ||
| 536 | |||
| 537 | /* let it rest - for a second - */ | ||
| 538 | msleep(1000); | ||
| 539 | |||
| 540 | return ret; | ||
| 541 | } | ||
| 542 | |||
| 543 | static int ar9170_usb_upload_firmware(struct ar9170_usb *aru) | ||
| 544 | { | ||
| 545 | int err; | ||
| 546 | |||
| 547 | /* First, upload initial values to device RAM */ | ||
| 548 | err = ar9170_usb_upload(aru, aru->init_values->data, | ||
| 549 | aru->init_values->size, 0x102800, false); | ||
| 550 | if (err) { | ||
| 551 | dev_err(&aru->udev->dev, "firmware part 1 " | ||
| 552 | "upload failed (%d).\n", err); | ||
| 553 | return err; | ||
| 554 | } | ||
| 555 | |||
| 556 | /* Then, upload the firmware itself and start it */ | ||
| 557 | return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size, | ||
| 558 | 0x200000, true); | ||
| 559 | } | ||
| 560 | |||
| 561 | static int ar9170_usb_init_transport(struct ar9170_usb *aru) | ||
| 562 | { | ||
| 563 | struct ar9170 *ar = (void *) &aru->common; | ||
| 564 | int err; | ||
| 565 | |||
| 566 | ar9170_regwrite_begin(ar); | ||
| 567 | |||
| 568 | /* Set USB Rx stream mode MAX packet number to 2 */ | ||
| 569 | ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4); | ||
| 570 | |||
| 571 | /* Set USB Rx stream mode timeout to 10us */ | ||
| 572 | ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80); | ||
| 573 | |||
| 574 | ar9170_regwrite_finish(); | ||
| 575 | |||
| 576 | err = ar9170_regwrite_result(); | ||
| 577 | if (err) | ||
| 578 | dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err); | ||
| 579 | |||
| 580 | return err; | ||
| 581 | } | ||
| 582 | |||
| 583 | static void ar9170_usb_stop(struct ar9170 *ar) | ||
| 584 | { | ||
| 585 | struct ar9170_usb *aru = (void *) ar; | ||
| 586 | int ret; | ||
| 587 | |||
| 588 | if (IS_ACCEPTING_CMD(ar)) | ||
| 589 | aru->common.state = AR9170_STOPPED; | ||
| 590 | |||
| 591 | /* lets wait a while until the tx - queues are dried out */ | ||
| 592 | ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted, | ||
| 593 | msecs_to_jiffies(1000)); | ||
| 594 | if (ret == 0) | ||
| 595 | dev_err(&aru->udev->dev, "kill pending tx urbs.\n"); | ||
| 596 | |||
| 597 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
| 598 | |||
| 599 | /* | ||
| 600 | * Note: | ||
| 601 | * So far we freed all tx urbs, but we won't dare to touch any rx urbs. | ||
| 602 | * Else we would end up with a unresponsive device... | ||
| 603 | */ | ||
| 604 | } | ||
| 605 | |||
| 606 | static int ar9170_usb_open(struct ar9170 *ar) | ||
| 607 | { | ||
| 608 | struct ar9170_usb *aru = (void *) ar; | ||
| 609 | int err; | ||
| 610 | |||
| 611 | usb_unpoison_anchored_urbs(&aru->tx_submitted); | ||
| 612 | err = ar9170_usb_init_transport(aru); | ||
| 613 | if (err) { | ||
| 614 | usb_poison_anchored_urbs(&aru->tx_submitted); | ||
| 615 | return err; | ||
| 616 | } | ||
| 617 | |||
| 618 | aru->common.state = AR9170_IDLE; | ||
| 619 | return 0; | ||
| 620 | } | ||
| 621 | |||
| 622 | static int ar9170_usb_probe(struct usb_interface *intf, | ||
| 623 | const struct usb_device_id *id) | ||
| 624 | { | ||
| 625 | struct ar9170_usb *aru; | ||
| 626 | struct ar9170 *ar; | ||
| 627 | struct usb_device *udev; | ||
| 628 | int err; | ||
| 629 | |||
| 630 | aru = ar9170_alloc(sizeof(*aru)); | ||
| 631 | if (IS_ERR(aru)) { | ||
| 632 | err = PTR_ERR(aru); | ||
| 633 | goto out; | ||
| 634 | } | ||
| 635 | |||
| 636 | udev = interface_to_usbdev(intf); | ||
| 637 | usb_get_dev(udev); | ||
| 638 | aru->udev = udev; | ||
| 639 | aru->intf = intf; | ||
| 640 | ar = &aru->common; | ||
| 641 | |||
| 642 | usb_set_intfdata(intf, aru); | ||
| 643 | SET_IEEE80211_DEV(ar->hw, &udev->dev); | ||
| 644 | |||
| 645 | init_usb_anchor(&aru->rx_submitted); | ||
| 646 | init_usb_anchor(&aru->tx_submitted); | ||
| 647 | init_completion(&aru->cmd_wait); | ||
| 648 | |||
| 649 | aru->common.stop = ar9170_usb_stop; | ||
| 650 | aru->common.open = ar9170_usb_open; | ||
| 651 | aru->common.tx = ar9170_usb_tx; | ||
| 652 | aru->common.exec_cmd = ar9170_usb_exec_cmd; | ||
| 653 | aru->common.callback_cmd = ar9170_usb_callback_cmd; | ||
| 654 | |||
| 655 | err = ar9170_usb_reset(aru); | ||
| 656 | if (err) | ||
| 657 | goto err_unlock; | ||
| 658 | |||
| 659 | err = ar9170_usb_request_firmware(aru); | ||
| 660 | if (err) | ||
| 661 | goto err_unlock; | ||
| 662 | |||
| 663 | err = ar9170_usb_alloc_rx_irq_urb(aru); | ||
| 664 | if (err) | ||
| 665 | goto err_freefw; | ||
| 666 | |||
| 667 | err = ar9170_usb_alloc_rx_bulk_urbs(aru); | ||
| 668 | if (err) | ||
| 669 | goto err_unrx; | ||
| 670 | |||
| 671 | err = ar9170_usb_upload_firmware(aru); | ||
| 672 | if (err) { | ||
| 673 | err = ar9170_echo_test(&aru->common, 0x60d43110); | ||
| 674 | if (err) { | ||
| 675 | /* force user invention, by disabling the device */ | ||
| 676 | err = usb_driver_set_configuration(aru->udev, -1); | ||
| 677 | dev_err(&aru->udev->dev, "device is in a bad state. " | ||
| 678 | "please reconnect it!\n"); | ||
| 679 | goto err_unrx; | ||
| 680 | } | ||
| 681 | } | ||
| 682 | |||
| 683 | err = ar9170_usb_open(ar); | ||
| 684 | if (err) | ||
| 685 | goto err_unrx; | ||
| 686 | |||
| 687 | err = ar9170_register(ar, &udev->dev); | ||
| 688 | |||
| 689 | ar9170_usb_stop(ar); | ||
| 690 | if (err) | ||
| 691 | goto err_unrx; | ||
| 692 | |||
| 693 | return 0; | ||
| 694 | |||
| 695 | err_unrx: | ||
| 696 | ar9170_usb_cancel_urbs(aru); | ||
| 697 | |||
| 698 | err_freefw: | ||
| 699 | release_firmware(aru->init_values); | ||
| 700 | release_firmware(aru->firmware); | ||
| 701 | |||
| 702 | err_unlock: | ||
| 703 | usb_set_intfdata(intf, NULL); | ||
| 704 | usb_put_dev(udev); | ||
| 705 | ieee80211_free_hw(ar->hw); | ||
| 706 | out: | ||
| 707 | return err; | ||
| 708 | } | ||
| 709 | |||
| 710 | static void ar9170_usb_disconnect(struct usb_interface *intf) | ||
| 711 | { | ||
| 712 | struct ar9170_usb *aru = usb_get_intfdata(intf); | ||
| 713 | |||
| 714 | if (!aru) | ||
| 715 | return; | ||
| 716 | |||
| 717 | aru->common.state = AR9170_IDLE; | ||
| 718 | ar9170_unregister(&aru->common); | ||
| 719 | ar9170_usb_cancel_urbs(aru); | ||
| 720 | |||
| 721 | release_firmware(aru->init_values); | ||
| 722 | release_firmware(aru->firmware); | ||
| 723 | |||
| 724 | usb_put_dev(aru->udev); | ||
| 725 | usb_set_intfdata(intf, NULL); | ||
| 726 | ieee80211_free_hw(aru->common.hw); | ||
| 727 | } | ||
| 728 | |||
| 729 | static struct usb_driver ar9170_driver = { | ||
| 730 | .name = "ar9170usb", | ||
| 731 | .probe = ar9170_usb_probe, | ||
| 732 | .disconnect = ar9170_usb_disconnect, | ||
| 733 | .id_table = ar9170_usb_ids, | ||
| 734 | .soft_unbind = 1, | ||
| 735 | }; | ||
| 736 | |||
| 737 | static int __init ar9170_init(void) | ||
| 738 | { | ||
| 739 | return usb_register(&ar9170_driver); | ||
| 740 | } | ||
| 741 | |||
| 742 | static void __exit ar9170_exit(void) | ||
| 743 | { | ||
| 744 | usb_deregister(&ar9170_driver); | ||
| 745 | } | ||
| 746 | |||
| 747 | module_init(ar9170_init); | ||
| 748 | module_exit(ar9170_exit); | ||
diff --git a/drivers/net/wireless/ar9170/usb.h b/drivers/net/wireless/ar9170/usb.h new file mode 100644 index 000000000000..f5852924cd64 --- /dev/null +++ b/drivers/net/wireless/ar9170/usb.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * Atheros AR9170 USB driver | ||
| 3 | * | ||
| 4 | * Driver specific definitions | ||
| 5 | * | ||
| 6 | * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> | ||
| 7 | * Copyright 2009, Christian Lamparter <chunkeey@web.de> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; see the file COPYING. If not, see | ||
| 21 | * http://www.gnu.org/licenses/. | ||
| 22 | * | ||
| 23 | * This file incorporates work covered by the following copyright and | ||
| 24 | * permission notice: | ||
| 25 | * Copyright (c) 2007-2008 Atheros Communications, Inc. | ||
| 26 | * | ||
| 27 | * Permission to use, copy, modify, and/or distribute this software for any | ||
| 28 | * purpose with or without fee is hereby granted, provided that the above | ||
| 29 | * copyright notice and this permission notice appear in all copies. | ||
| 30 | * | ||
| 31 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 32 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 33 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 34 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 35 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 36 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 37 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 38 | */ | ||
| 39 | #ifndef __USB_H | ||
| 40 | #define __USB_H | ||
| 41 | |||
| 42 | #include <linux/usb.h> | ||
| 43 | #include <linux/completion.h> | ||
| 44 | #include <linux/spinlock.h> | ||
| 45 | #include <linux/leds.h> | ||
| 46 | #include <net/wireless.h> | ||
| 47 | #include <net/mac80211.h> | ||
| 48 | #include <linux/firmware.h> | ||
| 49 | #include "eeprom.h" | ||
| 50 | #include "hw.h" | ||
| 51 | #include "ar9170.h" | ||
| 52 | |||
| 53 | #define AR9170_NUM_RX_URBS 16 | ||
| 54 | |||
| 55 | struct firmware; | ||
| 56 | |||
| 57 | struct ar9170_usb { | ||
| 58 | struct ar9170 common; | ||
| 59 | struct usb_device *udev; | ||
| 60 | struct usb_interface *intf; | ||
| 61 | |||
| 62 | struct usb_anchor rx_submitted; | ||
| 63 | struct usb_anchor tx_submitted; | ||
| 64 | |||
| 65 | spinlock_t cmdlock; | ||
| 66 | struct completion cmd_wait; | ||
| 67 | int readlen; | ||
| 68 | u8 *readbuf; | ||
| 69 | |||
| 70 | const struct firmware *init_values; | ||
| 71 | const struct firmware *firmware; | ||
| 72 | }; | ||
| 73 | |||
| 74 | #endif /* __USB_H */ | ||
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 0dc2c7321c8b..0b616e72fe05 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h | |||
| @@ -204,9 +204,9 @@ | |||
| 204 | #define AR5K_TUNE_CWMAX_11B 1023 | 204 | #define AR5K_TUNE_CWMAX_11B 1023 |
| 205 | #define AR5K_TUNE_CWMAX_XR 7 | 205 | #define AR5K_TUNE_CWMAX_XR 7 |
| 206 | #define AR5K_TUNE_NOISE_FLOOR -72 | 206 | #define AR5K_TUNE_NOISE_FLOOR -72 |
| 207 | #define AR5K_TUNE_MAX_TXPOWER 60 | 207 | #define AR5K_TUNE_MAX_TXPOWER 63 |
| 208 | #define AR5K_TUNE_DEFAULT_TXPOWER 30 | 208 | #define AR5K_TUNE_DEFAULT_TXPOWER 25 |
| 209 | #define AR5K_TUNE_TPC_TXPOWER true | 209 | #define AR5K_TUNE_TPC_TXPOWER false |
| 210 | #define AR5K_TUNE_ANT_DIVERSITY true | 210 | #define AR5K_TUNE_ANT_DIVERSITY true |
| 211 | #define AR5K_TUNE_HWTXTRIES 4 | 211 | #define AR5K_TUNE_HWTXTRIES 4 |
| 212 | 212 | ||
| @@ -551,11 +551,11 @@ enum ath5k_pkt_type { | |||
| 551 | */ | 551 | */ |
| 552 | #define AR5K_TXPOWER_OFDM(_r, _v) ( \ | 552 | #define AR5K_TXPOWER_OFDM(_r, _v) ( \ |
| 553 | ((0 & 1) << ((_v) + 6)) | \ | 553 | ((0 & 1) << ((_v) + 6)) | \ |
| 554 | (((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v)) \ | 554 | (((ah->ah_txpower.txp_rates_power_table[(_r)]) & 0x3f) << (_v)) \ |
| 555 | ) | 555 | ) |
| 556 | 556 | ||
| 557 | #define AR5K_TXPOWER_CCK(_r, _v) ( \ | 557 | #define AR5K_TXPOWER_CCK(_r, _v) ( \ |
| 558 | (ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v) \ | 558 | (ah->ah_txpower.txp_rates_power_table[(_r)] & 0x3f) << (_v) \ |
| 559 | ) | 559 | ) |
| 560 | 560 | ||
| 561 | /* | 561 | /* |
| @@ -1085,13 +1085,25 @@ struct ath5k_hw { | |||
| 1085 | struct ath5k_gain ah_gain; | 1085 | struct ath5k_gain ah_gain; |
| 1086 | u8 ah_offset[AR5K_MAX_RF_BANKS]; | 1086 | u8 ah_offset[AR5K_MAX_RF_BANKS]; |
| 1087 | 1087 | ||
| 1088 | |||
| 1088 | struct { | 1089 | struct { |
| 1089 | u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; | 1090 | /* Temporary tables used for interpolation */ |
| 1090 | u16 txp_rates[AR5K_MAX_RATES]; | 1091 | u8 tmpL[AR5K_EEPROM_N_PD_GAINS] |
| 1091 | s16 txp_min; | 1092 | [AR5K_EEPROM_POWER_TABLE_SIZE]; |
| 1092 | s16 txp_max; | 1093 | u8 tmpR[AR5K_EEPROM_N_PD_GAINS] |
| 1094 | [AR5K_EEPROM_POWER_TABLE_SIZE]; | ||
| 1095 | u8 txp_pd_table[AR5K_EEPROM_POWER_TABLE_SIZE * 2]; | ||
| 1096 | u16 txp_rates_power_table[AR5K_MAX_RATES]; | ||
| 1097 | u8 txp_min_idx; | ||
| 1093 | bool txp_tpc; | 1098 | bool txp_tpc; |
| 1099 | /* Values in 0.25dB units */ | ||
| 1100 | s16 txp_min_pwr; | ||
| 1101 | s16 txp_max_pwr; | ||
| 1102 | s16 txp_offset; | ||
| 1094 | s16 txp_ofdm; | 1103 | s16 txp_ofdm; |
| 1104 | /* Values in dB units */ | ||
| 1105 | s16 txp_cck_ofdm_pwr_delta; | ||
| 1106 | s16 txp_cck_ofdm_gainf_delta; | ||
| 1095 | } ah_txpower; | 1107 | } ah_txpower; |
| 1096 | 1108 | ||
| 1097 | struct { | 1109 | struct { |
| @@ -1161,6 +1173,7 @@ extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_l | |||
| 1161 | 1173 | ||
| 1162 | /* EEPROM access functions */ | 1174 | /* EEPROM access functions */ |
| 1163 | extern int ath5k_eeprom_init(struct ath5k_hw *ah); | 1175 | extern int ath5k_eeprom_init(struct ath5k_hw *ah); |
| 1176 | extern void ath5k_eeprom_detach(struct ath5k_hw *ah); | ||
| 1164 | extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); | 1177 | extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); |
| 1165 | extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); | 1178 | extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah); |
| 1166 | 1179 | ||
| @@ -1256,8 +1269,8 @@ extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); | |||
| 1256 | extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); | 1269 | extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); |
| 1257 | extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); | 1270 | extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); |
| 1258 | /* TX power setup */ | 1271 | /* TX power setup */ |
| 1259 | extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower); | 1272 | extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower); |
| 1260 | extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power); | 1273 | extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 ee_mode, u8 txpower); |
| 1261 | 1274 | ||
| 1262 | /* | 1275 | /* |
| 1263 | * Functions used internaly | 1276 | * Functions used internaly |
diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 656cb9dc833b..70d376c63aac 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c | |||
| @@ -341,6 +341,8 @@ void ath5k_hw_detach(struct ath5k_hw *ah) | |||
| 341 | if (ah->ah_rf_banks != NULL) | 341 | if (ah->ah_rf_banks != NULL) |
| 342 | kfree(ah->ah_rf_banks); | 342 | kfree(ah->ah_rf_banks); |
| 343 | 343 | ||
| 344 | ath5k_eeprom_detach(ah); | ||
| 345 | |||
| 344 | /* assume interrupts are down */ | 346 | /* assume interrupts are down */ |
| 345 | kfree(ah); | 347 | kfree(ah); |
| 346 | } | 348 | } |
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index cad3ccf61b00..5d57d774e466 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
| @@ -685,13 +685,6 @@ ath5k_pci_resume(struct pci_dev *pdev) | |||
| 685 | if (err) | 685 | if (err) |
| 686 | return err; | 686 | return err; |
| 687 | 687 | ||
| 688 | /* | ||
| 689 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
| 690 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
| 691 | * PCI Tx retries from interfering with C3 CPU state | ||
| 692 | */ | ||
| 693 | pci_write_config_byte(pdev, 0x41, 0); | ||
| 694 | |||
| 695 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); | 688 | err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc); |
| 696 | if (err) { | 689 | if (err) { |
| 697 | ATH5K_ERR(sc, "request_irq failed\n"); | 690 | ATH5K_ERR(sc, "request_irq failed\n"); |
| @@ -1095,9 +1088,18 @@ ath5k_mode_setup(struct ath5k_softc *sc) | |||
| 1095 | static inline int | 1088 | static inline int |
| 1096 | ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) | 1089 | ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix) |
| 1097 | { | 1090 | { |
| 1098 | WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, | 1091 | int rix; |
| 1099 | "hw_rix out of bounds: %x\n", hw_rix); | 1092 | |
| 1100 | return sc->rate_idx[sc->curband->band][hw_rix]; | 1093 | /* return base rate on errors */ |
| 1094 | if (WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES, | ||
| 1095 | "hw_rix out of bounds: %x\n", hw_rix)) | ||
| 1096 | return 0; | ||
| 1097 | |||
| 1098 | rix = sc->rate_idx[sc->curband->band][hw_rix]; | ||
| 1099 | if (WARN(rix < 0, "invalid hw_rix: %x\n", hw_rix)) | ||
| 1100 | rix = 0; | ||
| 1101 | |||
| 1102 | return rix; | ||
| 1101 | } | 1103 | } |
| 1102 | 1104 | ||
| 1103 | /***************\ | 1105 | /***************\ |
| @@ -1216,6 +1218,9 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
| 1216 | 1218 | ||
| 1217 | pktlen = skb->len; | 1219 | pktlen = skb->len; |
| 1218 | 1220 | ||
| 1221 | /* FIXME: If we are in g mode and rate is a CCK rate | ||
| 1222 | * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta | ||
| 1223 | * from tx power (value is in dB units already) */ | ||
| 1219 | if (info->control.hw_key) { | 1224 | if (info->control.hw_key) { |
| 1220 | keyidx = info->control.hw_key->hw_key_idx; | 1225 | keyidx = info->control.hw_key->hw_key_idx; |
| 1221 | pktlen += info->control.hw_key->icv_len; | 1226 | pktlen += info->control.hw_key->icv_len; |
| @@ -2044,6 +2049,9 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
| 2044 | antenna = sc->bsent & 4 ? 2 : 1; | 2049 | antenna = sc->bsent & 4 ? 2 : 1; |
| 2045 | } | 2050 | } |
| 2046 | 2051 | ||
| 2052 | /* FIXME: If we are in g mode and rate is a CCK rate | ||
| 2053 | * subtract ah->ah_txpower.txp_cck_ofdm_pwr_delta | ||
| 2054 | * from tx power (value is in dB units already) */ | ||
| 2047 | ds->ds_data = bf->skbaddr; | 2055 | ds->ds_data = bf->skbaddr; |
| 2048 | ret = ah->ah_setup_tx_desc(ah, ds, skb->len, | 2056 | ret = ah->ah_setup_tx_desc(ah, ds, skb->len, |
| 2049 | ieee80211_get_hdrlen_from_skb(skb), | 2057 | ieee80211_get_hdrlen_from_skb(skb), |
| @@ -2305,7 +2313,7 @@ ath5k_init(struct ath5k_softc *sc) | |||
| 2305 | sc->curband = &sc->sbands[sc->curchan->band]; | 2313 | sc->curband = &sc->sbands[sc->curchan->band]; |
| 2306 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | | 2314 | sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | |
| 2307 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | | 2315 | AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | |
| 2308 | AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; | 2316 | AR5K_INT_FATAL | AR5K_INT_GLOBAL; |
| 2309 | ret = ath5k_reset(sc, false, false); | 2317 | ret = ath5k_reset(sc, false, false); |
| 2310 | if (ret) | 2318 | if (ret) |
| 2311 | goto done; | 2319 | goto done; |
| @@ -2554,7 +2562,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 2554 | if (skb_headroom(skb) < padsize) { | 2562 | if (skb_headroom(skb) < padsize) { |
| 2555 | ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" | 2563 | ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" |
| 2556 | " headroom to pad %d\n", hdrlen, padsize); | 2564 | " headroom to pad %d\n", hdrlen, padsize); |
| 2557 | return NETDEV_TX_BUSY; | 2565 | goto drop_packet; |
| 2558 | } | 2566 | } |
| 2559 | skb_push(skb, padsize); | 2567 | skb_push(skb, padsize); |
| 2560 | memmove(skb->data, skb->data+padsize, hdrlen); | 2568 | memmove(skb->data, skb->data+padsize, hdrlen); |
| @@ -2565,7 +2573,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 2565 | ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); | 2573 | ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); |
| 2566 | spin_unlock_irqrestore(&sc->txbuflock, flags); | 2574 | spin_unlock_irqrestore(&sc->txbuflock, flags); |
| 2567 | ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); | 2575 | ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); |
| 2568 | return NETDEV_TX_BUSY; | 2576 | goto drop_packet; |
| 2569 | } | 2577 | } |
| 2570 | bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); | 2578 | bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); |
| 2571 | list_del(&bf->list); | 2579 | list_del(&bf->list); |
| @@ -2582,10 +2590,12 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
| 2582 | list_add_tail(&bf->list, &sc->txbuf); | 2590 | list_add_tail(&bf->list, &sc->txbuf); |
| 2583 | sc->txbuf_len++; | 2591 | sc->txbuf_len++; |
| 2584 | spin_unlock_irqrestore(&sc->txbuflock, flags); | 2592 | spin_unlock_irqrestore(&sc->txbuflock, flags); |
| 2585 | dev_kfree_skb_any(skb); | 2593 | goto drop_packet; |
| 2586 | return NETDEV_TX_OK; | ||
| 2587 | } | 2594 | } |
| 2595 | return NETDEV_TX_OK; | ||
| 2588 | 2596 | ||
| 2597 | drop_packet: | ||
| 2598 | dev_kfree_skb_any(skb); | ||
| 2589 | return NETDEV_TX_OK; | 2599 | return NETDEV_TX_OK; |
| 2590 | } | 2600 | } |
| 2591 | 2601 | ||
| @@ -2608,12 +2618,6 @@ ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel) | |||
| 2608 | goto err; | 2618 | goto err; |
| 2609 | } | 2619 | } |
| 2610 | 2620 | ||
| 2611 | /* | ||
| 2612 | * This is needed only to setup initial state | ||
| 2613 | * but it's best done after a reset. | ||
| 2614 | */ | ||
| 2615 | ath5k_hw_set_txpower_limit(sc->ah, 0); | ||
| 2616 | |||
| 2617 | ret = ath5k_rx_start(sc); | 2621 | ret = ath5k_rx_start(sc); |
| 2618 | if (ret) { | 2622 | if (ret) { |
| 2619 | ATH5K_ERR(sc, "can't start recv logic\n"); | 2623 | ATH5K_ERR(sc, "can't start recv logic\n"); |
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index 20e0d14b41ec..822956114cd7 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h | |||
| @@ -112,7 +112,7 @@ struct ath5k_softc { | |||
| 112 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; | 112 | struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; |
| 113 | struct ieee80211_channel channels[ATH_CHAN_MAX]; | 113 | struct ieee80211_channel channels[ATH_CHAN_MAX]; |
| 114 | struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; | 114 | struct ieee80211_rate rates[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; |
| 115 | u8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; | 115 | s8 rate_idx[IEEE80211_NUM_BANDS][AR5K_MAX_RATES]; |
| 116 | enum nl80211_iftype opmode; | 116 | enum nl80211_iftype opmode; |
| 117 | struct ath5k_hw *ah; /* Atheros HW */ | 117 | struct ath5k_hw *ah; /* Atheros HW */ |
| 118 | 118 | ||
diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index b40a9287a39a..dc30a2b70a6b 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c | |||
| @@ -194,6 +194,10 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, | |||
| 194 | return -EINVAL; | 194 | return -EINVAL; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | tx_power += ah->ah_txpower.txp_offset; | ||
| 198 | if (tx_power > AR5K_TUNE_MAX_TXPOWER) | ||
| 199 | tx_power = AR5K_TUNE_MAX_TXPOWER; | ||
| 200 | |||
| 197 | /* Clear descriptor */ | 201 | /* Clear descriptor */ |
| 198 | memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); | 202 | memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); |
| 199 | 203 | ||
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index ac45ca47ca87..c0fb3b09ba45 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> | 2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> |
| 3 | * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> | 3 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> |
| 4 | * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> | 4 | * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> |
| 5 | * | 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any | 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -98,11 +98,6 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah) | |||
| 98 | int ret; | 98 | int ret; |
| 99 | u16 val; | 99 | u16 val; |
| 100 | 100 | ||
| 101 | /* Initial TX thermal adjustment values */ | ||
| 102 | ee->ee_tx_clip = 4; | ||
| 103 | ee->ee_pwd_84 = ee->ee_pwd_90 = 1; | ||
| 104 | ee->ee_gain_select = 1; | ||
| 105 | |||
| 106 | /* | 101 | /* |
| 107 | * Read values from EEPROM and store them in the capability structure | 102 | * Read values from EEPROM and store them in the capability structure |
| 108 | */ | 103 | */ |
| @@ -241,22 +236,22 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, | |||
| 241 | ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); | 236 | ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); |
| 242 | switch(mode) { | 237 | switch(mode) { |
| 243 | case AR5K_EEPROM_MODE_11A: | 238 | case AR5K_EEPROM_MODE_11A: |
| 244 | ee->ee_ob[mode][3] = (val >> 5) & 0x7; | 239 | ee->ee_ob[mode][3] = (val >> 5) & 0x7; |
| 245 | ee->ee_db[mode][3] = (val >> 2) & 0x7; | 240 | ee->ee_db[mode][3] = (val >> 2) & 0x7; |
| 246 | ee->ee_ob[mode][2] = (val << 1) & 0x7; | 241 | ee->ee_ob[mode][2] = (val << 1) & 0x7; |
| 247 | 242 | ||
| 248 | AR5K_EEPROM_READ(o++, val); | 243 | AR5K_EEPROM_READ(o++, val); |
| 249 | ee->ee_ob[mode][2] |= (val >> 15) & 0x1; | 244 | ee->ee_ob[mode][2] |= (val >> 15) & 0x1; |
| 250 | ee->ee_db[mode][2] = (val >> 12) & 0x7; | 245 | ee->ee_db[mode][2] = (val >> 12) & 0x7; |
| 251 | ee->ee_ob[mode][1] = (val >> 9) & 0x7; | 246 | ee->ee_ob[mode][1] = (val >> 9) & 0x7; |
| 252 | ee->ee_db[mode][1] = (val >> 6) & 0x7; | 247 | ee->ee_db[mode][1] = (val >> 6) & 0x7; |
| 253 | ee->ee_ob[mode][0] = (val >> 3) & 0x7; | 248 | ee->ee_ob[mode][0] = (val >> 3) & 0x7; |
| 254 | ee->ee_db[mode][0] = val & 0x7; | 249 | ee->ee_db[mode][0] = val & 0x7; |
| 255 | break; | 250 | break; |
| 256 | case AR5K_EEPROM_MODE_11G: | 251 | case AR5K_EEPROM_MODE_11G: |
| 257 | case AR5K_EEPROM_MODE_11B: | 252 | case AR5K_EEPROM_MODE_11B: |
| 258 | ee->ee_ob[mode][1] = (val >> 4) & 0x7; | 253 | ee->ee_ob[mode][1] = (val >> 4) & 0x7; |
| 259 | ee->ee_db[mode][1] = val & 0x7; | 254 | ee->ee_db[mode][1] = val & 0x7; |
| 260 | break; | 255 | break; |
| 261 | } | 256 | } |
| 262 | 257 | ||
| @@ -504,35 +499,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah) | |||
| 504 | return 0; | 499 | return 0; |
| 505 | } | 500 | } |
| 506 | 501 | ||
| 507 | /* Used to match PCDAC steps with power values on RF5111 chips | ||
| 508 | * (eeprom versions < 4). For RF5111 we have 10 pre-defined PCDAC | ||
| 509 | * steps that match with the power values we read from eeprom. On | ||
| 510 | * older eeprom versions (< 3.2) these steps are equaly spaced at | ||
| 511 | * 10% of the pcdac curve -until the curve reaches it's maximum- | ||
| 512 | * (10 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) | ||
| 513 | * these 10 steps are spaced in a different way. This function returns | ||
| 514 | * the pcdac steps based on eeprom version and curve min/max so that we | ||
| 515 | * can have pcdac/pwr points. | ||
| 516 | */ | ||
| 517 | static inline void | ||
| 518 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | ||
| 519 | { | ||
| 520 | static const u16 intercepts3[] = | ||
| 521 | { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; | ||
| 522 | static const u16 intercepts3_2[] = | ||
| 523 | { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; | ||
| 524 | const u16 *ip; | ||
| 525 | int i; | ||
| 526 | |||
| 527 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) | ||
| 528 | ip = intercepts3_2; | ||
| 529 | else | ||
| 530 | ip = intercepts3; | ||
| 531 | |||
| 532 | for (i = 0; i < ARRAY_SIZE(intercepts3); i++) | ||
| 533 | *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; | ||
| 534 | } | ||
| 535 | |||
| 536 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff | 502 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff |
| 537 | * frequency mask) */ | 503 | * frequency mask) */ |
| 538 | static inline int | 504 | static inline int |
| @@ -546,26 +512,25 @@ ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, | |||
| 546 | int ret; | 512 | int ret; |
| 547 | u16 val; | 513 | u16 val; |
| 548 | 514 | ||
| 515 | ee->ee_n_piers[mode] = 0; | ||
| 549 | while(i < max) { | 516 | while(i < max) { |
| 550 | AR5K_EEPROM_READ(o++, val); | 517 | AR5K_EEPROM_READ(o++, val); |
| 551 | 518 | ||
| 552 | freq1 = (val >> 8) & 0xff; | 519 | freq1 = val & 0xff; |
| 553 | freq2 = val & 0xff; | 520 | if (!freq1) |
| 554 | 521 | break; | |
| 555 | if (freq1) { | ||
| 556 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
| 557 | freq1, mode); | ||
| 558 | ee->ee_n_piers[mode]++; | ||
| 559 | } | ||
| 560 | 522 | ||
| 561 | if (freq2) { | 523 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, |
| 562 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | 524 | freq1, mode); |
| 563 | freq2, mode); | 525 | ee->ee_n_piers[mode]++; |
| 564 | ee->ee_n_piers[mode]++; | ||
| 565 | } | ||
| 566 | 526 | ||
| 567 | if (!freq1 || !freq2) | 527 | freq2 = (val >> 8) & 0xff; |
| 528 | if (!freq2) | ||
| 568 | break; | 529 | break; |
| 530 | |||
| 531 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
| 532 | freq2, mode); | ||
| 533 | ee->ee_n_piers[mode]++; | ||
| 569 | } | 534 | } |
| 570 | 535 | ||
| 571 | /* return new offset */ | 536 | /* return new offset */ |
| @@ -652,13 +617,122 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) | |||
| 652 | return 0; | 617 | return 0; |
| 653 | } | 618 | } |
| 654 | 619 | ||
| 655 | /* Read power calibration for RF5111 chips | 620 | /* |
| 621 | * Read power calibration for RF5111 chips | ||
| 622 | * | ||
| 656 | * For RF5111 we have an XPD -eXternal Power Detector- curve | 623 | * For RF5111 we have an XPD -eXternal Power Detector- curve |
| 657 | * for each calibrated channel. Each curve has PCDAC steps on | 624 | * for each calibrated channel. Each curve has 0,5dB Power steps |
| 658 | * x axis and power on y axis and looks like a logarithmic | 625 | * on x axis and PCDAC steps (offsets) on y axis and looks like an |
| 659 | * function. To recreate the curve and pass the power values | 626 | * exponential function. To recreate the curve we read 11 points |
| 660 | * on the pcdac table, we read 10 points here and interpolate later. | 627 | * here and interpolate later. |
| 661 | */ | 628 | */ |
| 629 | |||
| 630 | /* Used to match PCDAC steps with power values on RF5111 chips | ||
| 631 | * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC | ||
| 632 | * steps that match with the power values we read from eeprom. On | ||
| 633 | * older eeprom versions (< 3.2) these steps are equaly spaced at | ||
| 634 | * 10% of the pcdac curve -until the curve reaches it's maximum- | ||
| 635 | * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) | ||
| 636 | * these 11 steps are spaced in a different way. This function returns | ||
| 637 | * the pcdac steps based on eeprom version and curve min/max so that we | ||
| 638 | * can have pcdac/pwr points. | ||
| 639 | */ | ||
| 640 | static inline void | ||
| 641 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | ||
| 642 | { | ||
| 643 | const static u16 intercepts3[] = | ||
| 644 | { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; | ||
| 645 | const static u16 intercepts3_2[] = | ||
| 646 | { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; | ||
| 647 | const u16 *ip; | ||
| 648 | int i; | ||
| 649 | |||
| 650 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) | ||
| 651 | ip = intercepts3_2; | ||
| 652 | else | ||
| 653 | ip = intercepts3; | ||
| 654 | |||
| 655 | for (i = 0; i < ARRAY_SIZE(intercepts3); i++) | ||
| 656 | vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; | ||
| 657 | } | ||
| 658 | |||
| 659 | /* Convert RF5111 specific data to generic raw data | ||
| 660 | * used by interpolation code */ | ||
| 661 | static int | ||
| 662 | ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, | ||
| 663 | struct ath5k_chan_pcal_info *chinfo) | ||
| 664 | { | ||
| 665 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 666 | struct ath5k_chan_pcal_info_rf5111 *pcinfo; | ||
| 667 | struct ath5k_pdgain_info *pd; | ||
| 668 | u8 pier, point, idx; | ||
| 669 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
| 670 | |||
| 671 | /* Fill raw data for each calibration pier */ | ||
| 672 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
| 673 | |||
| 674 | pcinfo = &chinfo[pier].rf5111_info; | ||
| 675 | |||
| 676 | /* Allocate pd_curves for this cal pier */ | ||
| 677 | chinfo[pier].pd_curves = | ||
| 678 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
| 679 | sizeof(struct ath5k_pdgain_info), | ||
| 680 | GFP_KERNEL); | ||
| 681 | |||
| 682 | if (!chinfo[pier].pd_curves) | ||
| 683 | return -ENOMEM; | ||
| 684 | |||
| 685 | /* Only one curve for RF5111 | ||
| 686 | * find out which one and place | ||
| 687 | * in in pd_curves. | ||
| 688 | * Note: ee_x_gain is reversed here */ | ||
| 689 | for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { | ||
| 690 | |||
| 691 | if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) { | ||
| 692 | pdgain_idx[0] = idx; | ||
| 693 | break; | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | ee->ee_pd_gains[mode] = 1; | ||
| 698 | |||
| 699 | pd = &chinfo[pier].pd_curves[idx]; | ||
| 700 | |||
| 701 | pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111; | ||
| 702 | |||
| 703 | /* Allocate pd points for this curve */ | ||
| 704 | pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
| 705 | sizeof(u8), GFP_KERNEL); | ||
| 706 | if (!pd->pd_step) | ||
| 707 | return -ENOMEM; | ||
| 708 | |||
| 709 | pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
| 710 | sizeof(s16), GFP_KERNEL); | ||
| 711 | if (!pd->pd_pwr) | ||
| 712 | return -ENOMEM; | ||
| 713 | |||
| 714 | /* Fill raw dataset | ||
| 715 | * (convert power to 0.25dB units | ||
| 716 | * for RF5112 combatibility) */ | ||
| 717 | for (point = 0; point < pd->pd_points; point++) { | ||
| 718 | |||
| 719 | /* Absolute values */ | ||
| 720 | pd->pd_pwr[point] = 2 * pcinfo->pwr[point]; | ||
| 721 | |||
| 722 | /* Already sorted */ | ||
| 723 | pd->pd_step[point] = pcinfo->pcdac[point]; | ||
| 724 | } | ||
| 725 | |||
| 726 | /* Set min/max pwr */ | ||
| 727 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
| 728 | chinfo[pier].max_pwr = pd->pd_pwr[10]; | ||
| 729 | |||
| 730 | } | ||
| 731 | |||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* Parse EEPROM data */ | ||
| 662 | static int | 736 | static int |
| 663 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | 737 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) |
| 664 | { | 738 | { |
| @@ -747,30 +821,165 @@ ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | |||
| 747 | cdata->pcdac_max, cdata->pcdac); | 821 | cdata->pcdac_max, cdata->pcdac); |
| 748 | } | 822 | } |
| 749 | 823 | ||
| 750 | return 0; | 824 | return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal); |
| 751 | } | 825 | } |
| 752 | 826 | ||
| 753 | /* Read power calibration for RF5112 chips | 827 | |
| 828 | /* | ||
| 829 | * Read power calibration for RF5112 chips | ||
| 830 | * | ||
| 754 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves | 831 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves |
| 755 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only | 832 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only |
| 756 | * use the higher (3) and the lower (0) curves. Each curve has PCDAC | 833 | * use the higher (3) and the lower (0) curves. Each curve has 0.5dB |
| 757 | * steps on x axis and power on y axis and looks like a linear | 834 | * power steps on x axis and PCDAC steps on y axis and looks like a |
| 758 | * function. To recreate the curve and pass the power values | 835 | * linear function. To recreate the curve and pass the power values |
| 759 | * on the pcdac table, we read 4 points for xpd 0 and 3 points | 836 | * on hw, we read 4 points for xpd 0 (lower gain -> max power) |
| 760 | * for xpd 3 here and interpolate later. | 837 | * and 3 points for xpd 3 (higher gain -> lower power) here and |
| 838 | * interpolate later. | ||
| 761 | * | 839 | * |
| 762 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. | 840 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. |
| 763 | */ | 841 | */ |
| 842 | |||
| 843 | /* Convert RF5112 specific data to generic raw data | ||
| 844 | * used by interpolation code */ | ||
| 845 | static int | ||
| 846 | ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, | ||
| 847 | struct ath5k_chan_pcal_info *chinfo) | ||
| 848 | { | ||
| 849 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 850 | struct ath5k_chan_pcal_info_rf5112 *pcinfo; | ||
| 851 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
| 852 | unsigned int pier, pdg, point; | ||
| 853 | |||
| 854 | /* Fill raw data for each calibration pier */ | ||
| 855 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
| 856 | |||
| 857 | pcinfo = &chinfo[pier].rf5112_info; | ||
| 858 | |||
| 859 | /* Allocate pd_curves for this cal pier */ | ||
| 860 | chinfo[pier].pd_curves = | ||
| 861 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
| 862 | sizeof(struct ath5k_pdgain_info), | ||
| 863 | GFP_KERNEL); | ||
| 864 | |||
| 865 | if (!chinfo[pier].pd_curves) | ||
| 866 | return -ENOMEM; | ||
| 867 | |||
| 868 | /* Fill pd_curves */ | ||
| 869 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
| 870 | |||
| 871 | u8 idx = pdgain_idx[pdg]; | ||
| 872 | struct ath5k_pdgain_info *pd = | ||
| 873 | &chinfo[pier].pd_curves[idx]; | ||
| 874 | |||
| 875 | /* Lowest gain curve (max power) */ | ||
| 876 | if (pdg == 0) { | ||
| 877 | /* One more point for better accuracy */ | ||
| 878 | pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS; | ||
| 879 | |||
| 880 | /* Allocate pd points for this curve */ | ||
| 881 | pd->pd_step = kcalloc(pd->pd_points, | ||
| 882 | sizeof(u8), GFP_KERNEL); | ||
| 883 | |||
| 884 | if (!pd->pd_step) | ||
| 885 | return -ENOMEM; | ||
| 886 | |||
| 887 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
| 888 | sizeof(s16), GFP_KERNEL); | ||
| 889 | |||
| 890 | if (!pd->pd_pwr) | ||
| 891 | return -ENOMEM; | ||
| 892 | |||
| 893 | |||
| 894 | /* Fill raw dataset | ||
| 895 | * (all power levels are in 0.25dB units) */ | ||
| 896 | pd->pd_step[0] = pcinfo->pcdac_x0[0]; | ||
| 897 | pd->pd_pwr[0] = pcinfo->pwr_x0[0]; | ||
| 898 | |||
| 899 | for (point = 1; point < pd->pd_points; | ||
| 900 | point++) { | ||
| 901 | /* Absolute values */ | ||
| 902 | pd->pd_pwr[point] = | ||
| 903 | pcinfo->pwr_x0[point]; | ||
| 904 | |||
| 905 | /* Deltas */ | ||
| 906 | pd->pd_step[point] = | ||
| 907 | pd->pd_step[point - 1] + | ||
| 908 | pcinfo->pcdac_x0[point]; | ||
| 909 | } | ||
| 910 | |||
| 911 | /* Set min power for this frequency */ | ||
| 912 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
| 913 | |||
| 914 | /* Highest gain curve (min power) */ | ||
| 915 | } else if (pdg == 1) { | ||
| 916 | |||
| 917 | pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS; | ||
| 918 | |||
| 919 | /* Allocate pd points for this curve */ | ||
| 920 | pd->pd_step = kcalloc(pd->pd_points, | ||
| 921 | sizeof(u8), GFP_KERNEL); | ||
| 922 | |||
| 923 | if (!pd->pd_step) | ||
| 924 | return -ENOMEM; | ||
| 925 | |||
| 926 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
| 927 | sizeof(s16), GFP_KERNEL); | ||
| 928 | |||
| 929 | if (!pd->pd_pwr) | ||
| 930 | return -ENOMEM; | ||
| 931 | |||
| 932 | /* Fill raw dataset | ||
| 933 | * (all power levels are in 0.25dB units) */ | ||
| 934 | for (point = 0; point < pd->pd_points; | ||
| 935 | point++) { | ||
| 936 | /* Absolute values */ | ||
| 937 | pd->pd_pwr[point] = | ||
| 938 | pcinfo->pwr_x3[point]; | ||
| 939 | |||
| 940 | /* Fixed points */ | ||
| 941 | pd->pd_step[point] = | ||
| 942 | pcinfo->pcdac_x3[point]; | ||
| 943 | } | ||
| 944 | |||
| 945 | /* Since we have a higher gain curve | ||
| 946 | * override min power */ | ||
| 947 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
| 948 | } | ||
| 949 | } | ||
| 950 | } | ||
| 951 | |||
| 952 | return 0; | ||
| 953 | } | ||
| 954 | |||
| 955 | /* Parse EEPROM data */ | ||
| 764 | static int | 956 | static int |
| 765 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | 957 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) |
| 766 | { | 958 | { |
| 767 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 959 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 768 | struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; | 960 | struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; |
| 769 | struct ath5k_chan_pcal_info *gen_chan_info; | 961 | struct ath5k_chan_pcal_info *gen_chan_info; |
| 962 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
| 770 | u32 offset; | 963 | u32 offset; |
| 771 | unsigned int i, c; | 964 | u8 i, c; |
| 772 | u16 val; | 965 | u16 val; |
| 773 | int ret; | 966 | int ret; |
| 967 | u8 pd_gains = 0; | ||
| 968 | |||
| 969 | /* Count how many curves we have and | ||
| 970 | * identify them (which one of the 4 | ||
| 971 | * available curves we have on each count). | ||
| 972 | * Curves are stored from lower (x0) to | ||
| 973 | * higher (x3) gain */ | ||
| 974 | for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) { | ||
| 975 | /* ee_x_gain[mode] is x gain mask */ | ||
| 976 | if ((ee->ee_x_gain[mode] >> i) & 0x1) | ||
| 977 | pdgain_idx[pd_gains++] = i; | ||
| 978 | } | ||
| 979 | ee->ee_pd_gains[mode] = pd_gains; | ||
| 980 | |||
| 981 | if (pd_gains == 0 || pd_gains > 2) | ||
| 982 | return -EINVAL; | ||
| 774 | 983 | ||
| 775 | switch (mode) { | 984 | switch (mode) { |
| 776 | case AR5K_EEPROM_MODE_11A: | 985 | case AR5K_EEPROM_MODE_11A: |
| @@ -808,13 +1017,13 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
| 808 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | 1017 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { |
| 809 | chan_pcal_info = &gen_chan_info[i].rf5112_info; | 1018 | chan_pcal_info = &gen_chan_info[i].rf5112_info; |
| 810 | 1019 | ||
| 811 | /* Power values in dBm * 4 | 1020 | /* Power values in quarter dB |
| 812 | * for the lower xpd gain curve | 1021 | * for the lower xpd gain curve |
| 813 | * (0 dBm -> higher output power) */ | 1022 | * (0 dBm -> higher output power) */ |
| 814 | for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { | 1023 | for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { |
| 815 | AR5K_EEPROM_READ(offset++, val); | 1024 | AR5K_EEPROM_READ(offset++, val); |
| 816 | chan_pcal_info->pwr_x0[c] = (val & 0xff); | 1025 | chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff); |
| 817 | chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff); | 1026 | chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff); |
| 818 | } | 1027 | } |
| 819 | 1028 | ||
| 820 | /* PCDAC steps | 1029 | /* PCDAC steps |
| @@ -825,12 +1034,12 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
| 825 | chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); | 1034 | chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); |
| 826 | chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); | 1035 | chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); |
| 827 | 1036 | ||
| 828 | /* Power values in dBm * 4 | 1037 | /* Power values in quarter dB |
| 829 | * for the higher xpd gain curve | 1038 | * for the higher xpd gain curve |
| 830 | * (18 dBm -> lower output power) */ | 1039 | * (18 dBm -> lower output power) */ |
| 831 | AR5K_EEPROM_READ(offset++, val); | 1040 | AR5K_EEPROM_READ(offset++, val); |
| 832 | chan_pcal_info->pwr_x3[0] = (val & 0xff); | 1041 | chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff); |
| 833 | chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff); | 1042 | chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff); |
| 834 | 1043 | ||
| 835 | AR5K_EEPROM_READ(offset++, val); | 1044 | AR5K_EEPROM_READ(offset++, val); |
| 836 | chan_pcal_info->pwr_x3[2] = (val & 0xff); | 1045 | chan_pcal_info->pwr_x3[2] = (val & 0xff); |
| @@ -843,24 +1052,36 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | |||
| 843 | chan_pcal_info->pcdac_x3[2] = 63; | 1052 | chan_pcal_info->pcdac_x3[2] = 63; |
| 844 | 1053 | ||
| 845 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { | 1054 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { |
| 846 | chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff); | 1055 | chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f); |
| 847 | 1056 | ||
| 848 | /* Last xpd0 power level is also channel maximum */ | 1057 | /* Last xpd0 power level is also channel maximum */ |
| 849 | gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; | 1058 | gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; |
| 850 | } else { | 1059 | } else { |
| 851 | chan_pcal_info->pcdac_x0[0] = 1; | 1060 | chan_pcal_info->pcdac_x0[0] = 1; |
| 852 | gen_chan_info[i].max_pwr = ((val >> 8) & 0xff); | 1061 | gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff); |
| 853 | } | 1062 | } |
| 854 | 1063 | ||
| 855 | /* Recreate pcdac_x0 table for this channel using pcdac steps */ | ||
| 856 | chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0]; | ||
| 857 | chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1]; | ||
| 858 | chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2]; | ||
| 859 | } | 1064 | } |
| 860 | 1065 | ||
| 861 | return 0; | 1066 | return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info); |
| 862 | } | 1067 | } |
| 863 | 1068 | ||
| 1069 | |||
| 1070 | /* | ||
| 1071 | * Read power calibration for RF2413 chips | ||
| 1072 | * | ||
| 1073 | * For RF2413 we have a Power to PDDAC table (Power Detector) | ||
| 1074 | * instead of a PCDAC and 4 pd gain curves for each calibrated channel. | ||
| 1075 | * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y | ||
| 1076 | * axis and looks like an exponential function like the RF5111 curve. | ||
| 1077 | * | ||
| 1078 | * To recreate the curves we read here the points and interpolate | ||
| 1079 | * later. Note that in most cases only 2 (higher and lower) curves are | ||
| 1080 | * used (like RF5112) but vendors have the oportunity to include all | ||
| 1081 | * 4 curves on eeprom. The final curve (higher power) has an extra | ||
| 1082 | * point for better accuracy like RF5112. | ||
| 1083 | */ | ||
| 1084 | |||
| 864 | /* For RF2413 power calibration data doesn't start on a fixed location and | 1085 | /* For RF2413 power calibration data doesn't start on a fixed location and |
| 865 | * if a mode is not supported, it's section is missing -not zeroed-. | 1086 | * if a mode is not supported, it's section is missing -not zeroed-. |
| 866 | * So we need to calculate the starting offset for each section by using | 1087 | * So we need to calculate the starting offset for each section by using |
| @@ -890,13 +1111,15 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
| 890 | switch(mode) { | 1111 | switch(mode) { |
| 891 | case AR5K_EEPROM_MODE_11G: | 1112 | case AR5K_EEPROM_MODE_11G: |
| 892 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) | 1113 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) |
| 893 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + | 1114 | offset += ath5k_pdgains_size_2413(ee, |
| 894 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1115 | AR5K_EEPROM_MODE_11B) + |
| 1116 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
| 895 | /* fall through */ | 1117 | /* fall through */ |
| 896 | case AR5K_EEPROM_MODE_11B: | 1118 | case AR5K_EEPROM_MODE_11B: |
| 897 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | 1119 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) |
| 898 | offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + | 1120 | offset += ath5k_pdgains_size_2413(ee, |
| 899 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | 1121 | AR5K_EEPROM_MODE_11A) + |
| 1122 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||
| 900 | /* fall through */ | 1123 | /* fall through */ |
| 901 | case AR5K_EEPROM_MODE_11A: | 1124 | case AR5K_EEPROM_MODE_11A: |
| 902 | break; | 1125 | break; |
| @@ -907,37 +1130,118 @@ ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | |||
| 907 | return offset; | 1130 | return offset; |
| 908 | } | 1131 | } |
| 909 | 1132 | ||
| 910 | /* Read power calibration for RF2413 chips | 1133 | /* Convert RF2413 specific data to generic raw data |
| 911 | * For RF2413 we have a PDDAC table (Power Detector) instead | 1134 | * used by interpolation code */ |
| 912 | * of a PCDAC and 4 pd gain curves for each calibrated channel. | 1135 | static int |
| 913 | * Each curve has PDDAC steps on x axis and power on y axis and | 1136 | ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, |
| 914 | * looks like an exponential function. To recreate the curves | 1137 | struct ath5k_chan_pcal_info *chinfo) |
| 915 | * we read here the points and interpolate later. Note that | 1138 | { |
| 916 | * in most cases only higher and lower curves are used (like | 1139 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 917 | * RF5112) but vendors have the oportunity to include all 4 | 1140 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; |
| 918 | * curves on eeprom. The final curve (higher power) has an extra | 1141 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; |
| 919 | * point for better accuracy like RF5112. | 1142 | unsigned int pier, pdg, point; |
| 920 | */ | 1143 | |
| 1144 | /* Fill raw data for each calibration pier */ | ||
| 1145 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
| 1146 | |||
| 1147 | pcinfo = &chinfo[pier].rf2413_info; | ||
| 1148 | |||
| 1149 | /* Allocate pd_curves for this cal pier */ | ||
| 1150 | chinfo[pier].pd_curves = | ||
| 1151 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
| 1152 | sizeof(struct ath5k_pdgain_info), | ||
| 1153 | GFP_KERNEL); | ||
| 1154 | |||
| 1155 | if (!chinfo[pier].pd_curves) | ||
| 1156 | return -ENOMEM; | ||
| 1157 | |||
| 1158 | /* Fill pd_curves */ | ||
| 1159 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
| 1160 | |||
| 1161 | u8 idx = pdgain_idx[pdg]; | ||
| 1162 | struct ath5k_pdgain_info *pd = | ||
| 1163 | &chinfo[pier].pd_curves[idx]; | ||
| 1164 | |||
| 1165 | /* One more point for the highest power | ||
| 1166 | * curve (lowest gain) */ | ||
| 1167 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
| 1168 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS; | ||
| 1169 | else | ||
| 1170 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1; | ||
| 1171 | |||
| 1172 | /* Allocate pd points for this curve */ | ||
| 1173 | pd->pd_step = kcalloc(pd->pd_points, | ||
| 1174 | sizeof(u8), GFP_KERNEL); | ||
| 1175 | |||
| 1176 | if (!pd->pd_step) | ||
| 1177 | return -ENOMEM; | ||
| 1178 | |||
| 1179 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
| 1180 | sizeof(s16), GFP_KERNEL); | ||
| 1181 | |||
| 1182 | if (!pd->pd_pwr) | ||
| 1183 | return -ENOMEM; | ||
| 1184 | |||
| 1185 | /* Fill raw dataset | ||
| 1186 | * convert all pwr levels to | ||
| 1187 | * quarter dB for RF5112 combatibility */ | ||
| 1188 | pd->pd_step[0] = pcinfo->pddac_i[pdg]; | ||
| 1189 | pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg]; | ||
| 1190 | |||
| 1191 | for (point = 1; point < pd->pd_points; point++) { | ||
| 1192 | |||
| 1193 | pd->pd_pwr[point] = pd->pd_pwr[point - 1] + | ||
| 1194 | 2 * pcinfo->pwr[pdg][point - 1]; | ||
| 1195 | |||
| 1196 | pd->pd_step[point] = pd->pd_step[point - 1] + | ||
| 1197 | pcinfo->pddac[pdg][point - 1]; | ||
| 1198 | |||
| 1199 | } | ||
| 1200 | |||
| 1201 | /* Highest gain curve -> min power */ | ||
| 1202 | if (pdg == 0) | ||
| 1203 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
| 1204 | |||
| 1205 | /* Lowest gain curve -> max power */ | ||
| 1206 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
| 1207 | chinfo[pier].max_pwr = | ||
| 1208 | pd->pd_pwr[pd->pd_points - 1]; | ||
| 1209 | } | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | return 0; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | /* Parse EEPROM data */ | ||
| 921 | static int | 1216 | static int |
| 922 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | 1217 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) |
| 923 | { | 1218 | { |
| 924 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 1219 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 925 | struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; | 1220 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; |
| 926 | struct ath5k_chan_pcal_info *gen_chan_info; | 1221 | struct ath5k_chan_pcal_info *chinfo; |
| 927 | unsigned int i, c; | 1222 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; |
| 928 | u32 offset; | 1223 | u32 offset; |
| 929 | int ret; | 1224 | int idx, i, ret; |
| 930 | u16 val; | 1225 | u16 val; |
| 931 | u8 pd_gains = 0; | 1226 | u8 pd_gains = 0; |
| 932 | 1227 | ||
| 933 | if (ee->ee_x_gain[mode] & 0x1) pd_gains++; | 1228 | /* Count how many curves we have and |
| 934 | if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; | 1229 | * identify them (which one of the 4 |
| 935 | if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; | 1230 | * available curves we have on each count). |
| 936 | if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; | 1231 | * Curves are stored from higher to |
| 1232 | * lower gain so we go backwards */ | ||
| 1233 | for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) { | ||
| 1234 | /* ee_x_gain[mode] is x gain mask */ | ||
| 1235 | if ((ee->ee_x_gain[mode] >> idx) & 0x1) | ||
| 1236 | pdgain_idx[pd_gains++] = idx; | ||
| 1237 | |||
| 1238 | } | ||
| 937 | ee->ee_pd_gains[mode] = pd_gains; | 1239 | ee->ee_pd_gains[mode] = pd_gains; |
| 938 | 1240 | ||
| 1241 | if (pd_gains == 0) | ||
| 1242 | return -EINVAL; | ||
| 1243 | |||
| 939 | offset = ath5k_cal_data_offset_2413(ee, mode); | 1244 | offset = ath5k_cal_data_offset_2413(ee, mode); |
| 940 | ee->ee_n_piers[mode] = 0; | ||
| 941 | switch (mode) { | 1245 | switch (mode) { |
| 942 | case AR5K_EEPROM_MODE_11A: | 1246 | case AR5K_EEPROM_MODE_11A: |
| 943 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | 1247 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) |
| @@ -945,7 +1249,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 945 | 1249 | ||
| 946 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); | 1250 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); |
| 947 | offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; | 1251 | offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; |
| 948 | gen_chan_info = ee->ee_pwr_cal_a; | 1252 | chinfo = ee->ee_pwr_cal_a; |
| 949 | break; | 1253 | break; |
| 950 | case AR5K_EEPROM_MODE_11B: | 1254 | case AR5K_EEPROM_MODE_11B: |
| 951 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | 1255 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) |
| @@ -953,7 +1257,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 953 | 1257 | ||
| 954 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | 1258 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); |
| 955 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1259 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; |
| 956 | gen_chan_info = ee->ee_pwr_cal_b; | 1260 | chinfo = ee->ee_pwr_cal_b; |
| 957 | break; | 1261 | break; |
| 958 | case AR5K_EEPROM_MODE_11G: | 1262 | case AR5K_EEPROM_MODE_11G: |
| 959 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | 1263 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) |
| @@ -961,41 +1265,35 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 961 | 1265 | ||
| 962 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | 1266 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); |
| 963 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | 1267 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; |
| 964 | gen_chan_info = ee->ee_pwr_cal_g; | 1268 | chinfo = ee->ee_pwr_cal_g; |
| 965 | break; | 1269 | break; |
| 966 | default: | 1270 | default: |
| 967 | return -EINVAL; | 1271 | return -EINVAL; |
| 968 | } | 1272 | } |
| 969 | 1273 | ||
| 970 | if (pd_gains == 0) | ||
| 971 | return 0; | ||
| 972 | |||
| 973 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | 1274 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { |
| 974 | chan_pcal_info = &gen_chan_info[i].rf2413_info; | 1275 | pcinfo = &chinfo[i].rf2413_info; |
| 975 | 1276 | ||
| 976 | /* | 1277 | /* |
| 977 | * Read pwr_i, pddac_i and the first | 1278 | * Read pwr_i, pddac_i and the first |
| 978 | * 2 pd points (pwr, pddac) | 1279 | * 2 pd points (pwr, pddac) |
| 979 | */ | 1280 | */ |
| 980 | AR5K_EEPROM_READ(offset++, val); | 1281 | AR5K_EEPROM_READ(offset++, val); |
| 981 | chan_pcal_info->pwr_i[0] = val & 0x1f; | 1282 | pcinfo->pwr_i[0] = val & 0x1f; |
| 982 | chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; | 1283 | pcinfo->pddac_i[0] = (val >> 5) & 0x7f; |
| 983 | chan_pcal_info->pwr[0][0] = | 1284 | pcinfo->pwr[0][0] = (val >> 12) & 0xf; |
| 984 | (val >> 12) & 0xf; | ||
| 985 | 1285 | ||
| 986 | AR5K_EEPROM_READ(offset++, val); | 1286 | AR5K_EEPROM_READ(offset++, val); |
| 987 | chan_pcal_info->pddac[0][0] = val & 0x3f; | 1287 | pcinfo->pddac[0][0] = val & 0x3f; |
| 988 | chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; | 1288 | pcinfo->pwr[0][1] = (val >> 6) & 0xf; |
| 989 | chan_pcal_info->pddac[0][1] = | 1289 | pcinfo->pddac[0][1] = (val >> 10) & 0x3f; |
| 990 | (val >> 10) & 0x3f; | ||
| 991 | 1290 | ||
| 992 | AR5K_EEPROM_READ(offset++, val); | 1291 | AR5K_EEPROM_READ(offset++, val); |
| 993 | chan_pcal_info->pwr[0][2] = val & 0xf; | 1292 | pcinfo->pwr[0][2] = val & 0xf; |
| 994 | chan_pcal_info->pddac[0][2] = | 1293 | pcinfo->pddac[0][2] = (val >> 4) & 0x3f; |
| 995 | (val >> 4) & 0x3f; | ||
| 996 | 1294 | ||
| 997 | chan_pcal_info->pwr[0][3] = 0; | 1295 | pcinfo->pwr[0][3] = 0; |
| 998 | chan_pcal_info->pddac[0][3] = 0; | 1296 | pcinfo->pddac[0][3] = 0; |
| 999 | 1297 | ||
| 1000 | if (pd_gains > 1) { | 1298 | if (pd_gains > 1) { |
| 1001 | /* | 1299 | /* |
| @@ -1003,44 +1301,36 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 1003 | * so it only has 2 pd points. | 1301 | * so it only has 2 pd points. |
| 1004 | * Continue wih pd gain 1. | 1302 | * Continue wih pd gain 1. |
| 1005 | */ | 1303 | */ |
| 1006 | chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; | 1304 | pcinfo->pwr_i[1] = (val >> 10) & 0x1f; |
| 1007 | 1305 | ||
| 1008 | chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; | 1306 | pcinfo->pddac_i[1] = (val >> 15) & 0x1; |
| 1009 | AR5K_EEPROM_READ(offset++, val); | 1307 | AR5K_EEPROM_READ(offset++, val); |
| 1010 | chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; | 1308 | pcinfo->pddac_i[1] |= (val & 0x3F) << 1; |
| 1011 | 1309 | ||
| 1012 | chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; | 1310 | pcinfo->pwr[1][0] = (val >> 6) & 0xf; |
| 1013 | chan_pcal_info->pddac[1][0] = | 1311 | pcinfo->pddac[1][0] = (val >> 10) & 0x3f; |
| 1014 | (val >> 10) & 0x3f; | ||
| 1015 | 1312 | ||
| 1016 | AR5K_EEPROM_READ(offset++, val); | 1313 | AR5K_EEPROM_READ(offset++, val); |
| 1017 | chan_pcal_info->pwr[1][1] = val & 0xf; | 1314 | pcinfo->pwr[1][1] = val & 0xf; |
| 1018 | chan_pcal_info->pddac[1][1] = | 1315 | pcinfo->pddac[1][1] = (val >> 4) & 0x3f; |
| 1019 | (val >> 4) & 0x3f; | 1316 | pcinfo->pwr[1][2] = (val >> 10) & 0xf; |
| 1020 | chan_pcal_info->pwr[1][2] = | 1317 | |
| 1021 | (val >> 10) & 0xf; | 1318 | pcinfo->pddac[1][2] = (val >> 14) & 0x3; |
| 1022 | |||
| 1023 | chan_pcal_info->pddac[1][2] = | ||
| 1024 | (val >> 14) & 0x3; | ||
| 1025 | AR5K_EEPROM_READ(offset++, val); | 1319 | AR5K_EEPROM_READ(offset++, val); |
| 1026 | chan_pcal_info->pddac[1][2] |= | 1320 | pcinfo->pddac[1][2] |= (val & 0xF) << 2; |
| 1027 | (val & 0xF) << 2; | ||
| 1028 | 1321 | ||
| 1029 | chan_pcal_info->pwr[1][3] = 0; | 1322 | pcinfo->pwr[1][3] = 0; |
| 1030 | chan_pcal_info->pddac[1][3] = 0; | 1323 | pcinfo->pddac[1][3] = 0; |
| 1031 | } else if (pd_gains == 1) { | 1324 | } else if (pd_gains == 1) { |
| 1032 | /* | 1325 | /* |
| 1033 | * Pd gain 0 is the last one so | 1326 | * Pd gain 0 is the last one so |
| 1034 | * read the extra point. | 1327 | * read the extra point. |
| 1035 | */ | 1328 | */ |
| 1036 | chan_pcal_info->pwr[0][3] = | 1329 | pcinfo->pwr[0][3] = (val >> 10) & 0xf; |
| 1037 | (val >> 10) & 0xf; | ||
| 1038 | 1330 | ||
| 1039 | chan_pcal_info->pddac[0][3] = | 1331 | pcinfo->pddac[0][3] = (val >> 14) & 0x3; |
| 1040 | (val >> 14) & 0x3; | ||
| 1041 | AR5K_EEPROM_READ(offset++, val); | 1332 | AR5K_EEPROM_READ(offset++, val); |
| 1042 | chan_pcal_info->pddac[0][3] |= | 1333 | pcinfo->pddac[0][3] |= (val & 0xF) << 2; |
| 1043 | (val & 0xF) << 2; | ||
| 1044 | } | 1334 | } |
| 1045 | 1335 | ||
| 1046 | /* | 1336 | /* |
| @@ -1048,105 +1338,65 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 1048 | * as above. | 1338 | * as above. |
| 1049 | */ | 1339 | */ |
| 1050 | if (pd_gains > 2) { | 1340 | if (pd_gains > 2) { |
| 1051 | chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; | 1341 | pcinfo->pwr_i[2] = (val >> 4) & 0x1f; |
| 1052 | chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; | 1342 | pcinfo->pddac_i[2] = (val >> 9) & 0x7f; |
| 1053 | 1343 | ||
| 1054 | AR5K_EEPROM_READ(offset++, val); | 1344 | AR5K_EEPROM_READ(offset++, val); |
| 1055 | chan_pcal_info->pwr[2][0] = | 1345 | pcinfo->pwr[2][0] = (val >> 0) & 0xf; |
| 1056 | (val >> 0) & 0xf; | 1346 | pcinfo->pddac[2][0] = (val >> 4) & 0x3f; |
| 1057 | chan_pcal_info->pddac[2][0] = | 1347 | pcinfo->pwr[2][1] = (val >> 10) & 0xf; |
| 1058 | (val >> 4) & 0x3f; | 1348 | |
| 1059 | chan_pcal_info->pwr[2][1] = | 1349 | pcinfo->pddac[2][1] = (val >> 14) & 0x3; |
| 1060 | (val >> 10) & 0xf; | ||
| 1061 | |||
| 1062 | chan_pcal_info->pddac[2][1] = | ||
| 1063 | (val >> 14) & 0x3; | ||
| 1064 | AR5K_EEPROM_READ(offset++, val); | 1350 | AR5K_EEPROM_READ(offset++, val); |
| 1065 | chan_pcal_info->pddac[2][1] |= | 1351 | pcinfo->pddac[2][1] |= (val & 0xF) << 2; |
| 1066 | (val & 0xF) << 2; | ||
| 1067 | 1352 | ||
| 1068 | chan_pcal_info->pwr[2][2] = | 1353 | pcinfo->pwr[2][2] = (val >> 4) & 0xf; |
| 1069 | (val >> 4) & 0xf; | 1354 | pcinfo->pddac[2][2] = (val >> 8) & 0x3f; |
| 1070 | chan_pcal_info->pddac[2][2] = | ||
| 1071 | (val >> 8) & 0x3f; | ||
| 1072 | 1355 | ||
| 1073 | chan_pcal_info->pwr[2][3] = 0; | 1356 | pcinfo->pwr[2][3] = 0; |
| 1074 | chan_pcal_info->pddac[2][3] = 0; | 1357 | pcinfo->pddac[2][3] = 0; |
| 1075 | } else if (pd_gains == 2) { | 1358 | } else if (pd_gains == 2) { |
| 1076 | chan_pcal_info->pwr[1][3] = | 1359 | pcinfo->pwr[1][3] = (val >> 4) & 0xf; |
| 1077 | (val >> 4) & 0xf; | 1360 | pcinfo->pddac[1][3] = (val >> 8) & 0x3f; |
| 1078 | chan_pcal_info->pddac[1][3] = | ||
| 1079 | (val >> 8) & 0x3f; | ||
| 1080 | } | 1361 | } |
| 1081 | 1362 | ||
| 1082 | if (pd_gains > 3) { | 1363 | if (pd_gains > 3) { |
| 1083 | chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; | 1364 | pcinfo->pwr_i[3] = (val >> 14) & 0x3; |
| 1084 | AR5K_EEPROM_READ(offset++, val); | 1365 | AR5K_EEPROM_READ(offset++, val); |
| 1085 | chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; | 1366 | pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; |
| 1086 | 1367 | ||
| 1087 | chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; | 1368 | pcinfo->pddac_i[3] = (val >> 3) & 0x7f; |
| 1088 | chan_pcal_info->pwr[3][0] = | 1369 | pcinfo->pwr[3][0] = (val >> 10) & 0xf; |
| 1089 | (val >> 10) & 0xf; | 1370 | pcinfo->pddac[3][0] = (val >> 14) & 0x3; |
| 1090 | chan_pcal_info->pddac[3][0] = | ||
| 1091 | (val >> 14) & 0x3; | ||
| 1092 | 1371 | ||
| 1093 | AR5K_EEPROM_READ(offset++, val); | 1372 | AR5K_EEPROM_READ(offset++, val); |
| 1094 | chan_pcal_info->pddac[3][0] |= | 1373 | pcinfo->pddac[3][0] |= (val & 0xF) << 2; |
| 1095 | (val & 0xF) << 2; | 1374 | pcinfo->pwr[3][1] = (val >> 4) & 0xf; |
| 1096 | chan_pcal_info->pwr[3][1] = | 1375 | pcinfo->pddac[3][1] = (val >> 8) & 0x3f; |
| 1097 | (val >> 4) & 0xf; | 1376 | |
| 1098 | chan_pcal_info->pddac[3][1] = | 1377 | pcinfo->pwr[3][2] = (val >> 14) & 0x3; |
| 1099 | (val >> 8) & 0x3f; | ||
| 1100 | |||
| 1101 | chan_pcal_info->pwr[3][2] = | ||
| 1102 | (val >> 14) & 0x3; | ||
| 1103 | AR5K_EEPROM_READ(offset++, val); | 1378 | AR5K_EEPROM_READ(offset++, val); |
| 1104 | chan_pcal_info->pwr[3][2] |= | 1379 | pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; |
| 1105 | ((val >> 0) & 0x3) << 2; | ||
| 1106 | 1380 | ||
| 1107 | chan_pcal_info->pddac[3][2] = | 1381 | pcinfo->pddac[3][2] = (val >> 2) & 0x3f; |
| 1108 | (val >> 2) & 0x3f; | 1382 | pcinfo->pwr[3][3] = (val >> 8) & 0xf; |
| 1109 | chan_pcal_info->pwr[3][3] = | ||
| 1110 | (val >> 8) & 0xf; | ||
| 1111 | 1383 | ||
| 1112 | chan_pcal_info->pddac[3][3] = | 1384 | pcinfo->pddac[3][3] = (val >> 12) & 0xF; |
| 1113 | (val >> 12) & 0xF; | ||
| 1114 | AR5K_EEPROM_READ(offset++, val); | 1385 | AR5K_EEPROM_READ(offset++, val); |
| 1115 | chan_pcal_info->pddac[3][3] |= | 1386 | pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; |
| 1116 | ((val >> 0) & 0x3) << 4; | ||
| 1117 | } else if (pd_gains == 3) { | 1387 | } else if (pd_gains == 3) { |
| 1118 | chan_pcal_info->pwr[2][3] = | 1388 | pcinfo->pwr[2][3] = (val >> 14) & 0x3; |
| 1119 | (val >> 14) & 0x3; | ||
| 1120 | AR5K_EEPROM_READ(offset++, val); | 1389 | AR5K_EEPROM_READ(offset++, val); |
| 1121 | chan_pcal_info->pwr[2][3] |= | 1390 | pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; |
| 1122 | ((val >> 0) & 0x3) << 2; | ||
| 1123 | |||
| 1124 | chan_pcal_info->pddac[2][3] = | ||
| 1125 | (val >> 2) & 0x3f; | ||
| 1126 | } | ||
| 1127 | 1391 | ||
| 1128 | for (c = 0; c < pd_gains; c++) { | 1392 | pcinfo->pddac[2][3] = (val >> 2) & 0x3f; |
| 1129 | /* Recreate pwr table for this channel using pwr steps */ | ||
| 1130 | chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; | ||
| 1131 | chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; | ||
| 1132 | chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; | ||
| 1133 | chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; | ||
| 1134 | if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) | ||
| 1135 | chan_pcal_info->pwr[c][3] = 0; | ||
| 1136 | |||
| 1137 | /* Recreate pddac table for this channel using pddac steps */ | ||
| 1138 | chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; | ||
| 1139 | chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; | ||
| 1140 | chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; | ||
| 1141 | chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; | ||
| 1142 | if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) | ||
| 1143 | chan_pcal_info->pddac[c][3] = 0; | ||
| 1144 | } | 1393 | } |
| 1145 | } | 1394 | } |
| 1146 | 1395 | ||
| 1147 | return 0; | 1396 | return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo); |
| 1148 | } | 1397 | } |
| 1149 | 1398 | ||
| 1399 | |||
| 1150 | /* | 1400 | /* |
| 1151 | * Read per rate target power (this is the maximum tx power | 1401 | * Read per rate target power (this is the maximum tx power |
| 1152 | * supported by the card). This info is used when setting | 1402 | * supported by the card). This info is used when setting |
| @@ -1154,11 +1404,12 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | |||
| 1154 | * | 1404 | * |
| 1155 | * This also works for v5 EEPROMs. | 1405 | * This also works for v5 EEPROMs. |
| 1156 | */ | 1406 | */ |
| 1157 | static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) | 1407 | static int |
| 1408 | ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) | ||
| 1158 | { | 1409 | { |
| 1159 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 1410 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 1160 | struct ath5k_rate_pcal_info *rate_pcal_info; | 1411 | struct ath5k_rate_pcal_info *rate_pcal_info; |
| 1161 | u16 *rate_target_pwr_num; | 1412 | u8 *rate_target_pwr_num; |
| 1162 | u32 offset; | 1413 | u32 offset; |
| 1163 | u16 val; | 1414 | u16 val; |
| 1164 | int ret, i; | 1415 | int ret, i; |
| @@ -1264,7 +1515,9 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | |||
| 1264 | else | 1515 | else |
| 1265 | read_pcal = ath5k_eeprom_read_pcal_info_5111; | 1516 | read_pcal = ath5k_eeprom_read_pcal_info_5111; |
| 1266 | 1517 | ||
| 1267 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { | 1518 | |
| 1519 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; | ||
| 1520 | mode++) { | ||
| 1268 | err = read_pcal(ah, mode); | 1521 | err = read_pcal(ah, mode); |
| 1269 | if (err) | 1522 | if (err) |
| 1270 | return err; | 1523 | return err; |
| @@ -1277,6 +1530,62 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | |||
| 1277 | return 0; | 1530 | return 0; |
| 1278 | } | 1531 | } |
| 1279 | 1532 | ||
| 1533 | static int | ||
| 1534 | ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) | ||
| 1535 | { | ||
| 1536 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 1537 | struct ath5k_chan_pcal_info *chinfo; | ||
| 1538 | u8 pier, pdg; | ||
| 1539 | |||
| 1540 | switch (mode) { | ||
| 1541 | case AR5K_EEPROM_MODE_11A: | ||
| 1542 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
| 1543 | return 0; | ||
| 1544 | chinfo = ee->ee_pwr_cal_a; | ||
| 1545 | break; | ||
| 1546 | case AR5K_EEPROM_MODE_11B: | ||
| 1547 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
| 1548 | return 0; | ||
| 1549 | chinfo = ee->ee_pwr_cal_b; | ||
| 1550 | break; | ||
| 1551 | case AR5K_EEPROM_MODE_11G: | ||
| 1552 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
| 1553 | return 0; | ||
| 1554 | chinfo = ee->ee_pwr_cal_g; | ||
| 1555 | break; | ||
| 1556 | default: | ||
| 1557 | return -EINVAL; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
| 1561 | if (!chinfo[pier].pd_curves) | ||
| 1562 | continue; | ||
| 1563 | |||
| 1564 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
| 1565 | struct ath5k_pdgain_info *pd = | ||
| 1566 | &chinfo[pier].pd_curves[pdg]; | ||
| 1567 | |||
| 1568 | if (pd != NULL) { | ||
| 1569 | kfree(pd->pd_step); | ||
| 1570 | kfree(pd->pd_pwr); | ||
| 1571 | } | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | kfree(chinfo[pier].pd_curves); | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | return 0; | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | void | ||
| 1581 | ath5k_eeprom_detach(struct ath5k_hw *ah) | ||
| 1582 | { | ||
| 1583 | u8 mode; | ||
| 1584 | |||
| 1585 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) | ||
| 1586 | ath5k_eeprom_free_pcal_info(ah, mode); | ||
| 1587 | } | ||
| 1588 | |||
| 1280 | /* Read conformance test limits used for regulatory control */ | 1589 | /* Read conformance test limits used for regulatory control */ |
| 1281 | static int | 1590 | static int |
| 1282 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) | 1591 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) |
| @@ -1457,3 +1766,4 @@ bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) | |||
| 1457 | else | 1766 | else |
| 1458 | return false; | 1767 | return false; |
| 1459 | } | 1768 | } |
| 1769 | |||
diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h index 1deebc0257d4..b0c0606dea0b 100644 --- a/drivers/net/wireless/ath5k/eeprom.h +++ b/drivers/net/wireless/ath5k/eeprom.h | |||
| @@ -173,6 +173,7 @@ | |||
| 173 | #define AR5K_EEPROM_N_5GHZ_CHAN 10 | 173 | #define AR5K_EEPROM_N_5GHZ_CHAN 10 |
| 174 | #define AR5K_EEPROM_N_2GHZ_CHAN 3 | 174 | #define AR5K_EEPROM_N_2GHZ_CHAN 3 |
| 175 | #define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 | 175 | #define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 |
| 176 | #define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4 | ||
| 176 | #define AR5K_EEPROM_MAX_CHAN 10 | 177 | #define AR5K_EEPROM_MAX_CHAN 10 |
| 177 | #define AR5K_EEPROM_N_PWR_POINTS_5111 11 | 178 | #define AR5K_EEPROM_N_PWR_POINTS_5111 11 |
| 178 | #define AR5K_EEPROM_N_PCDAC 11 | 179 | #define AR5K_EEPROM_N_PCDAC 11 |
| @@ -193,7 +194,7 @@ | |||
| 193 | #define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) | 194 | #define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) |
| 194 | #define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) | 195 | #define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) |
| 195 | #define AR5K_EEPROM_MAX_CTLS 32 | 196 | #define AR5K_EEPROM_MAX_CTLS 32 |
| 196 | #define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 | 197 | #define AR5K_EEPROM_N_PD_CURVES 4 |
| 197 | #define AR5K_EEPROM_N_XPD0_POINTS 4 | 198 | #define AR5K_EEPROM_N_XPD0_POINTS 4 |
| 198 | #define AR5K_EEPROM_N_XPD3_POINTS 3 | 199 | #define AR5K_EEPROM_N_XPD3_POINTS 3 |
| 199 | #define AR5K_EEPROM_N_PD_GAINS 4 | 200 | #define AR5K_EEPROM_N_PD_GAINS 4 |
| @@ -232,7 +233,7 @@ enum ath5k_ctl_mode { | |||
| 232 | AR5K_CTL_11B = 1, | 233 | AR5K_CTL_11B = 1, |
| 233 | AR5K_CTL_11G = 2, | 234 | AR5K_CTL_11G = 2, |
| 234 | AR5K_CTL_TURBO = 3, | 235 | AR5K_CTL_TURBO = 3, |
| 235 | AR5K_CTL_108G = 4, | 236 | AR5K_CTL_TURBOG = 4, |
| 236 | AR5K_CTL_2GHT20 = 5, | 237 | AR5K_CTL_2GHT20 = 5, |
| 237 | AR5K_CTL_5GHT20 = 6, | 238 | AR5K_CTL_5GHT20 = 6, |
| 238 | AR5K_CTL_2GHT40 = 7, | 239 | AR5K_CTL_2GHT40 = 7, |
| @@ -240,65 +241,114 @@ enum ath5k_ctl_mode { | |||
| 240 | AR5K_CTL_MODE_M = 15, | 241 | AR5K_CTL_MODE_M = 15, |
| 241 | }; | 242 | }; |
| 242 | 243 | ||
| 244 | /* Default CTL ids for the 3 main reg domains. | ||
| 245 | * Atheros only uses these by default but vendors | ||
| 246 | * can have up to 32 different CTLs for different | ||
| 247 | * scenarios. Note that theese values are ORed with | ||
| 248 | * the mode id (above) so we can have up to 24 CTL | ||
| 249 | * datasets out of these 3 main regdomains. That leaves | ||
| 250 | * 8 ids that can be used by vendors and since 0x20 is | ||
| 251 | * missing from HAL sources i guess this is the set of | ||
| 252 | * custom CTLs vendors can use. */ | ||
| 253 | #define AR5K_CTL_FCC 0x10 | ||
| 254 | #define AR5K_CTL_CUSTOM 0x20 | ||
| 255 | #define AR5K_CTL_ETSI 0x30 | ||
| 256 | #define AR5K_CTL_MKK 0x40 | ||
| 257 | |||
| 258 | /* Indicates a CTL with only mode set and | ||
| 259 | * no reg domain mapping, such CTLs are used | ||
| 260 | * for world roaming domains or simply when | ||
| 261 | * a reg domain is not set */ | ||
| 262 | #define AR5K_CTL_NO_REGDOMAIN 0xf0 | ||
| 263 | |||
| 264 | /* Indicates an empty (invalid) CTL */ | ||
| 265 | #define AR5K_CTL_NO_CTL 0xff | ||
| 266 | |||
| 243 | /* Per channel calibration data, used for power table setup */ | 267 | /* Per channel calibration data, used for power table setup */ |
| 244 | struct ath5k_chan_pcal_info_rf5111 { | 268 | struct ath5k_chan_pcal_info_rf5111 { |
| 245 | /* Power levels in half dbm units | 269 | /* Power levels in half dbm units |
| 246 | * for one power curve. */ | 270 | * for one power curve. */ |
| 247 | u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; | 271 | u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; |
| 248 | /* PCDAC table steps | 272 | /* PCDAC table steps |
| 249 | * for the above values */ | 273 | * for the above values */ |
| 250 | u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; | 274 | u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; |
| 251 | /* Starting PCDAC step */ | 275 | /* Starting PCDAC step */ |
| 252 | u8 pcdac_min; | 276 | u8 pcdac_min; |
| 253 | /* Final PCDAC step */ | 277 | /* Final PCDAC step */ |
| 254 | u8 pcdac_max; | 278 | u8 pcdac_max; |
| 255 | }; | 279 | }; |
| 256 | 280 | ||
| 257 | struct ath5k_chan_pcal_info_rf5112 { | 281 | struct ath5k_chan_pcal_info_rf5112 { |
| 258 | /* Power levels in quarter dBm units | 282 | /* Power levels in quarter dBm units |
| 259 | * for lower (0) and higher (3) | 283 | * for lower (0) and higher (3) |
| 260 | * level curves */ | 284 | * level curves in 0.25dB units */ |
| 261 | s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; | 285 | s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; |
| 262 | s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; | 286 | s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; |
| 263 | /* PCDAC table steps | 287 | /* PCDAC table steps |
| 264 | * for the above values */ | 288 | * for the above values */ |
| 265 | u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; | 289 | u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; |
| 266 | u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; | 290 | u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; |
| 267 | }; | 291 | }; |
| 268 | 292 | ||
| 269 | struct ath5k_chan_pcal_info_rf2413 { | 293 | struct ath5k_chan_pcal_info_rf2413 { |
| 270 | /* Starting pwr/pddac values */ | 294 | /* Starting pwr/pddac values */ |
| 271 | s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; | 295 | s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; |
| 272 | u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; | 296 | u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; |
| 273 | /* (pwr,pddac) points */ | 297 | /* (pwr,pddac) points |
| 274 | s8 pwr[AR5K_EEPROM_N_PD_GAINS] | 298 | * power levels in 0.5dB units */ |
| 275 | [AR5K_EEPROM_N_PD_POINTS]; | 299 | s8 pwr[AR5K_EEPROM_N_PD_GAINS] |
| 276 | u8 pddac[AR5K_EEPROM_N_PD_GAINS] | 300 | [AR5K_EEPROM_N_PD_POINTS]; |
| 277 | [AR5K_EEPROM_N_PD_POINTS]; | 301 | u8 pddac[AR5K_EEPROM_N_PD_GAINS] |
| 302 | [AR5K_EEPROM_N_PD_POINTS]; | ||
| 303 | }; | ||
| 304 | |||
| 305 | enum ath5k_powertable_type { | ||
| 306 | AR5K_PWRTABLE_PWR_TO_PCDAC = 0, | ||
| 307 | AR5K_PWRTABLE_LINEAR_PCDAC = 1, | ||
| 308 | AR5K_PWRTABLE_PWR_TO_PDADC = 2, | ||
| 309 | }; | ||
| 310 | |||
| 311 | struct ath5k_pdgain_info { | ||
| 312 | u8 pd_points; | ||
| 313 | u8 *pd_step; | ||
| 314 | /* Power values are in | ||
| 315 | * 0.25dB units */ | ||
| 316 | s16 *pd_pwr; | ||
| 278 | }; | 317 | }; |
| 279 | 318 | ||
| 280 | struct ath5k_chan_pcal_info { | 319 | struct ath5k_chan_pcal_info { |
| 281 | /* Frequency */ | 320 | /* Frequency */ |
| 282 | u16 freq; | 321 | u16 freq; |
| 283 | /* Max available power */ | 322 | /* Tx power boundaries */ |
| 284 | s8 max_pwr; | 323 | s16 max_pwr; |
| 324 | s16 min_pwr; | ||
| 285 | union { | 325 | union { |
| 286 | struct ath5k_chan_pcal_info_rf5111 rf5111_info; | 326 | struct ath5k_chan_pcal_info_rf5111 rf5111_info; |
| 287 | struct ath5k_chan_pcal_info_rf5112 rf5112_info; | 327 | struct ath5k_chan_pcal_info_rf5112 rf5112_info; |
| 288 | struct ath5k_chan_pcal_info_rf2413 rf2413_info; | 328 | struct ath5k_chan_pcal_info_rf2413 rf2413_info; |
| 289 | }; | 329 | }; |
| 330 | /* Raw values used by phy code | ||
| 331 | * Curves are stored in order from lower | ||
| 332 | * gain to higher gain (max txpower -> min txpower) */ | ||
| 333 | struct ath5k_pdgain_info *pd_curves; | ||
| 290 | }; | 334 | }; |
| 291 | 335 | ||
| 292 | /* Per rate calibration data for each mode, used for power table setup */ | 336 | /* Per rate calibration data for each mode, |
| 337 | * used for rate power table setup. | ||
| 338 | * Note: Values in 0.5dB units */ | ||
| 293 | struct ath5k_rate_pcal_info { | 339 | struct ath5k_rate_pcal_info { |
| 294 | u16 freq; /* Frequency */ | 340 | u16 freq; /* Frequency */ |
| 295 | /* Power level for 6-24Mbit/s rates */ | 341 | /* Power level for 6-24Mbit/s rates or |
| 342 | * 1Mb rate */ | ||
| 296 | u16 target_power_6to24; | 343 | u16 target_power_6to24; |
| 297 | /* Power level for 36Mbit rate */ | 344 | /* Power level for 36Mbit rate or |
| 345 | * 2Mb rate */ | ||
| 298 | u16 target_power_36; | 346 | u16 target_power_36; |
| 299 | /* Power level for 48Mbit rate */ | 347 | /* Power level for 48Mbit rate or |
| 348 | * 5.5Mbit rate */ | ||
| 300 | u16 target_power_48; | 349 | u16 target_power_48; |
| 301 | /* Power level for 54Mbit rate */ | 350 | /* Power level for 54Mbit rate or |
| 351 | * 11Mbit rate */ | ||
| 302 | u16 target_power_54; | 352 | u16 target_power_54; |
| 303 | }; | 353 | }; |
| 304 | 354 | ||
| @@ -330,12 +380,6 @@ struct ath5k_eeprom_info { | |||
| 330 | u16 ee_cck_ofdm_power_delta; | 380 | u16 ee_cck_ofdm_power_delta; |
| 331 | u16 ee_scaled_cck_delta; | 381 | u16 ee_scaled_cck_delta; |
| 332 | 382 | ||
| 333 | /* Used for tx thermal adjustment (eeprom_init, rfregs) */ | ||
| 334 | u16 ee_tx_clip; | ||
| 335 | u16 ee_pwd_84; | ||
| 336 | u16 ee_pwd_90; | ||
| 337 | u16 ee_gain_select; | ||
| 338 | |||
| 339 | /* RF Calibration settings (reset, rfregs) */ | 383 | /* RF Calibration settings (reset, rfregs) */ |
| 340 | u16 ee_i_cal[AR5K_EEPROM_N_MODES]; | 384 | u16 ee_i_cal[AR5K_EEPROM_N_MODES]; |
| 341 | u16 ee_q_cal[AR5K_EEPROM_N_MODES]; | 385 | u16 ee_q_cal[AR5K_EEPROM_N_MODES]; |
| @@ -363,23 +407,25 @@ struct ath5k_eeprom_info { | |||
| 363 | /* Power calibration data */ | 407 | /* Power calibration data */ |
| 364 | u16 ee_false_detect[AR5K_EEPROM_N_MODES]; | 408 | u16 ee_false_detect[AR5K_EEPROM_N_MODES]; |
| 365 | 409 | ||
| 366 | /* Number of pd gain curves per mode (RF2413) */ | 410 | /* Number of pd gain curves per mode */ |
| 367 | u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; | 411 | u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; |
| 412 | /* Back mapping pdcurve number -> pdcurve index in pd->pd_curves */ | ||
| 413 | u8 ee_pdc_to_idx[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PD_GAINS]; | ||
| 368 | 414 | ||
| 369 | u8 ee_n_piers[AR5K_EEPROM_N_MODES]; | 415 | u8 ee_n_piers[AR5K_EEPROM_N_MODES]; |
| 370 | struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; | 416 | struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; |
| 371 | struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN]; | 417 | struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; |
| 372 | struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN]; | 418 | struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; |
| 373 | 419 | ||
| 374 | /* Per rate target power levels */ | 420 | /* Per rate target power levels */ |
| 375 | u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; | 421 | u8 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; |
| 376 | struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; | 422 | struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; |
| 377 | struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN]; | 423 | struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; |
| 378 | struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN]; | 424 | struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN_MAX]; |
| 379 | 425 | ||
| 380 | /* Conformance test limits (Unused) */ | 426 | /* Conformance test limits (Unused) */ |
| 381 | u16 ee_ctls; | 427 | u8 ee_ctls; |
| 382 | u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; | 428 | u8 ee_ctl[AR5K_EEPROM_MAX_CTLS]; |
| 383 | struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS]; | 429 | struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS]; |
| 384 | 430 | ||
| 385 | /* Noise Floor Calibration settings */ | 431 | /* Noise Floor Calibration settings */ |
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index 44886434187b..61fb621ed20d 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c | |||
| @@ -1510,8 +1510,8 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) | |||
| 1510 | rf2425_ini_mode_end, mode); | 1510 | rf2425_ini_mode_end, mode); |
| 1511 | 1511 | ||
| 1512 | ath5k_hw_ini_registers(ah, | 1512 | ath5k_hw_ini_registers(ah, |
| 1513 | ARRAY_SIZE(rf2413_ini_common_end), | 1513 | ARRAY_SIZE(rf2425_ini_common_end), |
| 1514 | rf2413_ini_common_end, change_channel); | 1514 | rf2425_ini_common_end, change_channel); |
| 1515 | 1515 | ||
| 1516 | ath5k_hw_ini_registers(ah, | 1516 | ath5k_hw_ini_registers(ah, |
| 1517 | ARRAY_SIZE(rf5112_ini_bbgain), | 1517 | ARRAY_SIZE(rf5112_ini_bbgain), |
diff --git a/drivers/net/wireless/ath5k/led.c b/drivers/net/wireless/ath5k/led.c index 0686e12738b3..19555fb79c9b 100644 --- a/drivers/net/wireless/ath5k/led.c +++ b/drivers/net/wireless/ath5k/led.c | |||
| @@ -65,6 +65,8 @@ static const struct pci_device_id ath5k_led_devices[] = { | |||
| 65 | { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) }, | 65 | { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) }, |
| 66 | /* E-machines E510 (tuliom@gmail.com) */ | 66 | /* E-machines E510 (tuliom@gmail.com) */ |
| 67 | { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, | 67 | { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) }, |
| 68 | /* Acer Extensa 5620z (nekoreeve@gmail.com) */ | ||
| 69 | { ATH_SDEVICE(PCI_VENDOR_ID_QMI, 0x0105), ATH_LED(3, 0) }, | ||
| 68 | { } | 70 | { } |
| 69 | }; | 71 | }; |
| 70 | 72 | ||
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 81f5bebc48b1..9e2faae5ae94 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> | 4 | * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> |
| 5 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> | 5 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> |
| 6 | * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> | 6 | * Copyright (c) 2007-2008 Jiri Slaby <jirislaby@gmail.com> |
| 7 | * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> | ||
| 7 | * | 8 | * |
| 8 | * Permission to use, copy, modify, and distribute this software for any | 9 | * Permission to use, copy, modify, and distribute this software for any |
| 9 | * purpose with or without fee is hereby granted, provided that the above | 10 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -183,7 +184,9 @@ static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) | |||
| 183 | if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) | 184 | if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) |
| 184 | return; | 185 | return; |
| 185 | 186 | ||
| 186 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, | 187 | /* Send the packet with 2dB below max power as |
| 188 | * patent doc suggest */ | ||
| 189 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4, | ||
| 187 | AR5K_PHY_PAPD_PROBE_TXPOWER) | | 190 | AR5K_PHY_PAPD_PROBE_TXPOWER) | |
| 188 | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); | 191 | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); |
| 189 | 192 | ||
| @@ -1433,93 +1436,1120 @@ unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) | |||
| 1433 | return false; /*XXX: What do we return for 5210 ?*/ | 1436 | return false; /*XXX: What do we return for 5210 ?*/ |
| 1434 | } | 1437 | } |
| 1435 | 1438 | ||
| 1439 | |||
| 1440 | /****************\ | ||
| 1441 | * TX power setup * | ||
| 1442 | \****************/ | ||
| 1443 | |||
| 1444 | /* | ||
| 1445 | * Helper functions | ||
| 1446 | */ | ||
| 1447 | |||
| 1448 | /* | ||
| 1449 | * Do linear interpolation between two given (x, y) points | ||
| 1450 | */ | ||
| 1451 | static s16 | ||
| 1452 | ath5k_get_interpolated_value(s16 target, s16 x_left, s16 x_right, | ||
| 1453 | s16 y_left, s16 y_right) | ||
| 1454 | { | ||
| 1455 | s16 ratio, result; | ||
| 1456 | |||
| 1457 | /* Avoid divide by zero and skip interpolation | ||
| 1458 | * if we have the same point */ | ||
| 1459 | if ((x_left == x_right) || (y_left == y_right)) | ||
| 1460 | return y_left; | ||
| 1461 | |||
| 1462 | /* | ||
| 1463 | * Since we use ints and not fps, we need to scale up in | ||
| 1464 | * order to get a sane ratio value (or else we 'll eg. get | ||
| 1465 | * always 1 instead of 1.25, 1.75 etc). We scale up by 100 | ||
| 1466 | * to have some accuracy both for 0.5 and 0.25 steps. | ||
| 1467 | */ | ||
| 1468 | ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left)); | ||
| 1469 | |||
| 1470 | /* Now scale down to be in range */ | ||
| 1471 | result = y_left + (ratio * (target - x_left) / 100); | ||
| 1472 | |||
| 1473 | return result; | ||
| 1474 | } | ||
| 1475 | |||
| 1476 | /* | ||
| 1477 | * Find vertical boundary (min pwr) for the linear PCDAC curve. | ||
| 1478 | * | ||
| 1479 | * Since we have the top of the curve and we draw the line below | ||
| 1480 | * until we reach 1 (1 pcdac step) we need to know which point | ||
| 1481 | * (x value) that is so that we don't go below y axis and have negative | ||
| 1482 | * pcdac values when creating the curve, or fill the table with zeroes. | ||
| 1483 | */ | ||
| 1484 | static s16 | ||
| 1485 | ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, | ||
| 1486 | const s16 *pwrL, const s16 *pwrR) | ||
| 1487 | { | ||
| 1488 | s8 tmp; | ||
| 1489 | s16 min_pwrL, min_pwrR; | ||
| 1490 | s16 pwr_i = pwrL[0]; | ||
| 1491 | |||
| 1492 | do { | ||
| 1493 | pwr_i--; | ||
| 1494 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, | ||
| 1495 | pwrL[0], pwrL[1], | ||
| 1496 | stepL[0], stepL[1]); | ||
| 1497 | |||
| 1498 | } while (tmp > 1); | ||
| 1499 | |||
| 1500 | min_pwrL = pwr_i; | ||
| 1501 | |||
| 1502 | pwr_i = pwrR[0]; | ||
| 1503 | do { | ||
| 1504 | pwr_i--; | ||
| 1505 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, | ||
| 1506 | pwrR[0], pwrR[1], | ||
| 1507 | stepR[0], stepR[1]); | ||
| 1508 | |||
| 1509 | } while (tmp > 1); | ||
| 1510 | |||
| 1511 | min_pwrR = pwr_i; | ||
| 1512 | |||
| 1513 | /* Keep the right boundary so that it works for both curves */ | ||
| 1514 | return max(min_pwrL, min_pwrR); | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | /* | ||
| 1518 | * Interpolate (pwr,vpd) points to create a Power to PDADC or a | ||
| 1519 | * Power to PCDAC curve. | ||
| 1520 | * | ||
| 1521 | * Each curve has power on x axis (in 0.5dB units) and PCDAC/PDADC | ||
| 1522 | * steps (offsets) on y axis. Power can go up to 31.5dB and max | ||
| 1523 | * PCDAC/PDADC step for each curve is 64 but we can write more than | ||
| 1524 | * one curves on hw so we can go up to 128 (which is the max step we | ||
| 1525 | * can write on the final table). | ||
| 1526 | * | ||
| 1527 | * We write y values (PCDAC/PDADC steps) on hw. | ||
| 1528 | */ | ||
| 1529 | static void | ||
| 1530 | ath5k_create_power_curve(s16 pmin, s16 pmax, | ||
| 1531 | const s16 *pwr, const u8 *vpd, | ||
| 1532 | u8 num_points, | ||
| 1533 | u8 *vpd_table, u8 type) | ||
| 1534 | { | ||
| 1535 | u8 idx[2] = { 0, 1 }; | ||
| 1536 | s16 pwr_i = 2*pmin; | ||
| 1537 | int i; | ||
| 1538 | |||
| 1539 | if (num_points < 2) | ||
| 1540 | return; | ||
| 1541 | |||
| 1542 | /* We want the whole line, so adjust boundaries | ||
| 1543 | * to cover the entire power range. Note that | ||
| 1544 | * power values are already 0.25dB so no need | ||
| 1545 | * to multiply pwr_i by 2 */ | ||
| 1546 | if (type == AR5K_PWRTABLE_LINEAR_PCDAC) { | ||
| 1547 | pwr_i = pmin; | ||
| 1548 | pmin = 0; | ||
| 1549 | pmax = 63; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | /* Find surrounding turning points (TPs) | ||
| 1553 | * and interpolate between them */ | ||
| 1554 | for (i = 0; (i <= (u16) (pmax - pmin)) && | ||
| 1555 | (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { | ||
| 1556 | |||
| 1557 | /* We passed the right TP, move to the next set of TPs | ||
| 1558 | * if we pass the last TP, extrapolate above using the last | ||
| 1559 | * two TPs for ratio */ | ||
| 1560 | if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) { | ||
| 1561 | idx[0]++; | ||
| 1562 | idx[1]++; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i, | ||
| 1566 | pwr[idx[0]], pwr[idx[1]], | ||
| 1567 | vpd[idx[0]], vpd[idx[1]]); | ||
| 1568 | |||
| 1569 | /* Increase by 0.5dB | ||
| 1570 | * (0.25 dB units) */ | ||
| 1571 | pwr_i += 2; | ||
| 1572 | } | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | /* | ||
| 1576 | * Get the surrounding per-channel power calibration piers | ||
| 1577 | * for a given frequency so that we can interpolate between | ||
| 1578 | * them and come up with an apropriate dataset for our current | ||
| 1579 | * channel. | ||
| 1580 | */ | ||
| 1581 | static void | ||
| 1582 | ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, | ||
| 1583 | struct ieee80211_channel *channel, | ||
| 1584 | struct ath5k_chan_pcal_info **pcinfo_l, | ||
| 1585 | struct ath5k_chan_pcal_info **pcinfo_r) | ||
| 1586 | { | ||
| 1587 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 1588 | struct ath5k_chan_pcal_info *pcinfo; | ||
| 1589 | u8 idx_l, idx_r; | ||
| 1590 | u8 mode, max, i; | ||
| 1591 | u32 target = channel->center_freq; | ||
| 1592 | |||
| 1593 | idx_l = 0; | ||
| 1594 | idx_r = 0; | ||
| 1595 | |||
| 1596 | if (!(channel->hw_value & CHANNEL_OFDM)) { | ||
| 1597 | pcinfo = ee->ee_pwr_cal_b; | ||
| 1598 | mode = AR5K_EEPROM_MODE_11B; | ||
| 1599 | } else if (channel->hw_value & CHANNEL_2GHZ) { | ||
| 1600 | pcinfo = ee->ee_pwr_cal_g; | ||
| 1601 | mode = AR5K_EEPROM_MODE_11G; | ||
| 1602 | } else { | ||
| 1603 | pcinfo = ee->ee_pwr_cal_a; | ||
| 1604 | mode = AR5K_EEPROM_MODE_11A; | ||
| 1605 | } | ||
| 1606 | max = ee->ee_n_piers[mode] - 1; | ||
| 1607 | |||
| 1608 | /* Frequency is below our calibrated | ||
| 1609 | * range. Use the lowest power curve | ||
| 1610 | * we have */ | ||
| 1611 | if (target < pcinfo[0].freq) { | ||
| 1612 | idx_l = idx_r = 0; | ||
| 1613 | goto done; | ||
| 1614 | } | ||
| 1615 | |||
| 1616 | /* Frequency is above our calibrated | ||
| 1617 | * range. Use the highest power curve | ||
| 1618 | * we have */ | ||
| 1619 | if (target > pcinfo[max].freq) { | ||
| 1620 | idx_l = idx_r = max; | ||
| 1621 | goto done; | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | /* Frequency is inside our calibrated | ||
| 1625 | * channel range. Pick the surrounding | ||
| 1626 | * calibration piers so that we can | ||
| 1627 | * interpolate */ | ||
| 1628 | for (i = 0; i <= max; i++) { | ||
| 1629 | |||
| 1630 | /* Frequency matches one of our calibration | ||
| 1631 | * piers, no need to interpolate, just use | ||
| 1632 | * that calibration pier */ | ||
| 1633 | if (pcinfo[i].freq == target) { | ||
| 1634 | idx_l = idx_r = i; | ||
| 1635 | goto done; | ||
| 1636 | } | ||
| 1637 | |||
| 1638 | /* We found a calibration pier that's above | ||
| 1639 | * frequency, use this pier and the previous | ||
| 1640 | * one to interpolate */ | ||
| 1641 | if (target < pcinfo[i].freq) { | ||
| 1642 | idx_r = i; | ||
| 1643 | idx_l = idx_r - 1; | ||
| 1644 | goto done; | ||
| 1645 | } | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | done: | ||
| 1649 | *pcinfo_l = &pcinfo[idx_l]; | ||
| 1650 | *pcinfo_r = &pcinfo[idx_r]; | ||
| 1651 | |||
| 1652 | return; | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | /* | ||
| 1656 | * Get the surrounding per-rate power calibration data | ||
| 1657 | * for a given frequency and interpolate between power | ||
| 1658 | * values to set max target power supported by hw for | ||
| 1659 | * each rate. | ||
| 1660 | */ | ||
| 1661 | static void | ||
| 1662 | ath5k_get_rate_pcal_data(struct ath5k_hw *ah, | ||
| 1663 | struct ieee80211_channel *channel, | ||
| 1664 | struct ath5k_rate_pcal_info *rates) | ||
| 1665 | { | ||
| 1666 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 1667 | struct ath5k_rate_pcal_info *rpinfo; | ||
| 1668 | u8 idx_l, idx_r; | ||
| 1669 | u8 mode, max, i; | ||
| 1670 | u32 target = channel->center_freq; | ||
| 1671 | |||
| 1672 | idx_l = 0; | ||
| 1673 | idx_r = 0; | ||
| 1674 | |||
| 1675 | if (!(channel->hw_value & CHANNEL_OFDM)) { | ||
| 1676 | rpinfo = ee->ee_rate_tpwr_b; | ||
| 1677 | mode = AR5K_EEPROM_MODE_11B; | ||
| 1678 | } else if (channel->hw_value & CHANNEL_2GHZ) { | ||
| 1679 | rpinfo = ee->ee_rate_tpwr_g; | ||
| 1680 | mode = AR5K_EEPROM_MODE_11G; | ||
| 1681 | } else { | ||
| 1682 | rpinfo = ee->ee_rate_tpwr_a; | ||
| 1683 | mode = AR5K_EEPROM_MODE_11A; | ||
| 1684 | } | ||
| 1685 | max = ee->ee_rate_target_pwr_num[mode] - 1; | ||
| 1686 | |||
| 1687 | /* Get the surrounding calibration | ||
| 1688 | * piers - same as above */ | ||
| 1689 | if (target < rpinfo[0].freq) { | ||
| 1690 | idx_l = idx_r = 0; | ||
| 1691 | goto done; | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | if (target > rpinfo[max].freq) { | ||
| 1695 | idx_l = idx_r = max; | ||
| 1696 | goto done; | ||
| 1697 | } | ||
| 1698 | |||
| 1699 | for (i = 0; i <= max; i++) { | ||
| 1700 | |||
| 1701 | if (rpinfo[i].freq == target) { | ||
| 1702 | idx_l = idx_r = i; | ||
| 1703 | goto done; | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | if (target < rpinfo[i].freq) { | ||
| 1707 | idx_r = i; | ||
| 1708 | idx_l = idx_r - 1; | ||
| 1709 | goto done; | ||
| 1710 | } | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | done: | ||
| 1714 | /* Now interpolate power value, based on the frequency */ | ||
| 1715 | rates->freq = target; | ||
| 1716 | |||
| 1717 | rates->target_power_6to24 = | ||
| 1718 | ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, | ||
| 1719 | rpinfo[idx_r].freq, | ||
| 1720 | rpinfo[idx_l].target_power_6to24, | ||
| 1721 | rpinfo[idx_r].target_power_6to24); | ||
| 1722 | |||
| 1723 | rates->target_power_36 = | ||
| 1724 | ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, | ||
| 1725 | rpinfo[idx_r].freq, | ||
| 1726 | rpinfo[idx_l].target_power_36, | ||
| 1727 | rpinfo[idx_r].target_power_36); | ||
| 1728 | |||
| 1729 | rates->target_power_48 = | ||
| 1730 | ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, | ||
| 1731 | rpinfo[idx_r].freq, | ||
| 1732 | rpinfo[idx_l].target_power_48, | ||
| 1733 | rpinfo[idx_r].target_power_48); | ||
| 1734 | |||
| 1735 | rates->target_power_54 = | ||
| 1736 | ath5k_get_interpolated_value(target, rpinfo[idx_l].freq, | ||
| 1737 | rpinfo[idx_r].freq, | ||
| 1738 | rpinfo[idx_l].target_power_54, | ||
| 1739 | rpinfo[idx_r].target_power_54); | ||
| 1740 | } | ||
| 1741 | |||
| 1742 | /* | ||
| 1743 | * Get the max edge power for this channel if | ||
| 1744 | * we have such data from EEPROM's Conformance Test | ||
| 1745 | * Limits (CTL), and limit max power if needed. | ||
| 1746 | * | ||
| 1747 | * FIXME: Only works for world regulatory domains | ||
| 1748 | */ | ||
| 1749 | static void | ||
| 1750 | ath5k_get_max_ctl_power(struct ath5k_hw *ah, | ||
| 1751 | struct ieee80211_channel *channel) | ||
| 1752 | { | ||
| 1753 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 1754 | struct ath5k_edge_power *rep = ee->ee_ctl_pwr; | ||
| 1755 | u8 *ctl_val = ee->ee_ctl; | ||
| 1756 | s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4; | ||
| 1757 | s16 edge_pwr = 0; | ||
| 1758 | u8 rep_idx; | ||
| 1759 | u8 i, ctl_mode; | ||
| 1760 | u8 ctl_idx = 0xFF; | ||
| 1761 | u32 target = channel->center_freq; | ||
| 1762 | |||
| 1763 | /* Find out a CTL for our mode that's not mapped | ||
| 1764 | * on a specific reg domain. | ||
| 1765 | * | ||
| 1766 | * TODO: Map our current reg domain to one of the 3 available | ||
| 1767 | * reg domain ids so that we can support more CTLs. */ | ||
| 1768 | switch (channel->hw_value & CHANNEL_MODES) { | ||
| 1769 | case CHANNEL_A: | ||
| 1770 | ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN; | ||
| 1771 | break; | ||
| 1772 | case CHANNEL_G: | ||
| 1773 | ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN; | ||
| 1774 | break; | ||
| 1775 | case CHANNEL_B: | ||
| 1776 | ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN; | ||
| 1777 | break; | ||
| 1778 | case CHANNEL_T: | ||
| 1779 | ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN; | ||
| 1780 | break; | ||
| 1781 | case CHANNEL_TG: | ||
| 1782 | ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN; | ||
| 1783 | break; | ||
| 1784 | case CHANNEL_XR: | ||
| 1785 | /* Fall through */ | ||
| 1786 | default: | ||
| 1787 | return; | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | for (i = 0; i < ee->ee_ctls; i++) { | ||
| 1791 | if (ctl_val[i] == ctl_mode) { | ||
| 1792 | ctl_idx = i; | ||
| 1793 | break; | ||
| 1794 | } | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | /* If we have a CTL dataset available grab it and find the | ||
| 1798 | * edge power for our frequency */ | ||
| 1799 | if (ctl_idx == 0xFF) | ||
| 1800 | return; | ||
| 1801 | |||
| 1802 | /* Edge powers are sorted by frequency from lower | ||
| 1803 | * to higher. Each CTL corresponds to 8 edge power | ||
| 1804 | * measurements. */ | ||
| 1805 | rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES; | ||
| 1806 | |||
| 1807 | /* Don't do boundaries check because we | ||
| 1808 | * might have more that one bands defined | ||
| 1809 | * for this mode */ | ||
| 1810 | |||
| 1811 | /* Get the edge power that's closer to our | ||
| 1812 | * frequency */ | ||
| 1813 | for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) { | ||
| 1814 | rep_idx += i; | ||
| 1815 | if (target <= rep[rep_idx].freq) | ||
| 1816 | edge_pwr = (s16) rep[rep_idx].edge; | ||
| 1817 | } | ||
| 1818 | |||
| 1819 | if (edge_pwr) | ||
| 1820 | ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr); | ||
| 1821 | } | ||
| 1822 | |||
| 1823 | |||
| 1824 | /* | ||
| 1825 | * Power to PCDAC table functions | ||
| 1826 | */ | ||
| 1827 | |||
| 1436 | /* | 1828 | /* |
| 1437 | * TX power setup | 1829 | * Fill Power to PCDAC table on RF5111 |
| 1830 | * | ||
| 1831 | * No further processing is needed for RF5111, the only thing we have to | ||
| 1832 | * do is fill the values below and above calibration range since eeprom data | ||
| 1833 | * may not cover the entire PCDAC table. | ||
| 1438 | */ | 1834 | */ |
| 1835 | static void | ||
| 1836 | ath5k_fill_pwr_to_pcdac_table(struct ath5k_hw *ah, s16* table_min, | ||
| 1837 | s16 *table_max) | ||
| 1838 | { | ||
| 1839 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; | ||
| 1840 | u8 *pcdac_tmp = ah->ah_txpower.tmpL[0]; | ||
| 1841 | u8 pcdac_0, pcdac_n, pcdac_i, pwr_idx, i; | ||
| 1842 | s16 min_pwr, max_pwr; | ||
| 1843 | |||
| 1844 | /* Get table boundaries */ | ||
| 1845 | min_pwr = table_min[0]; | ||
| 1846 | pcdac_0 = pcdac_tmp[0]; | ||
| 1847 | |||
| 1848 | max_pwr = table_max[0]; | ||
| 1849 | pcdac_n = pcdac_tmp[table_max[0] - table_min[0]]; | ||
| 1850 | |||
| 1851 | /* Extrapolate below minimum using pcdac_0 */ | ||
| 1852 | pcdac_i = 0; | ||
| 1853 | for (i = 0; i < min_pwr; i++) | ||
| 1854 | pcdac_out[pcdac_i++] = pcdac_0; | ||
| 1855 | |||
| 1856 | /* Copy values from pcdac_tmp */ | ||
| 1857 | pwr_idx = min_pwr; | ||
| 1858 | for (i = 0 ; pwr_idx <= max_pwr && | ||
| 1859 | pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) { | ||
| 1860 | pcdac_out[pcdac_i++] = pcdac_tmp[i]; | ||
| 1861 | pwr_idx++; | ||
| 1862 | } | ||
| 1863 | |||
| 1864 | /* Extrapolate above maximum */ | ||
| 1865 | while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE) | ||
| 1866 | pcdac_out[pcdac_i++] = pcdac_n; | ||
| 1867 | |||
| 1868 | } | ||
| 1439 | 1869 | ||
| 1440 | /* | 1870 | /* |
| 1441 | * Initialize the tx power table (not fully implemented) | 1871 | * Combine available XPD Curves and fill Linear Power to PCDAC table |
| 1872 | * on RF5112 | ||
| 1873 | * | ||
| 1874 | * RFX112 can have up to 2 curves (one for low txpower range and one for | ||
| 1875 | * higher txpower range). We need to put them both on pcdac_out and place | ||
| 1876 | * them in the correct location. In case we only have one curve available | ||
| 1877 | * just fit it on pcdac_out (it's supposed to cover the entire range of | ||
| 1878 | * available pwr levels since it's always the higher power curve). Extrapolate | ||
| 1879 | * below and above final table if needed. | ||
| 1442 | */ | 1880 | */ |
| 1443 | static void ath5k_txpower_table(struct ath5k_hw *ah, | 1881 | static void |
| 1444 | struct ieee80211_channel *channel, s16 max_power) | 1882 | ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min, |
| 1883 | s16 *table_max, u8 pdcurves) | ||
| 1445 | { | 1884 | { |
| 1446 | unsigned int i, min, max, n; | 1885 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; |
| 1447 | u16 txpower, *rates; | 1886 | u8 *pcdac_low_pwr; |
| 1448 | 1887 | u8 *pcdac_high_pwr; | |
| 1449 | rates = ah->ah_txpower.txp_rates; | 1888 | u8 *pcdac_tmp; |
| 1450 | 1889 | u8 pwr; | |
| 1451 | txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2; | 1890 | s16 max_pwr_idx; |
| 1452 | if (max_power > txpower) | 1891 | s16 min_pwr_idx; |
| 1453 | txpower = max_power > AR5K_TUNE_MAX_TXPOWER ? | 1892 | s16 mid_pwr_idx = 0; |
| 1454 | AR5K_TUNE_MAX_TXPOWER : max_power; | 1893 | /* Edge flag turs on the 7nth bit on the PCDAC |
| 1455 | 1894 | * to delcare the higher power curve (force values | |
| 1456 | for (i = 0; i < AR5K_MAX_RATES; i++) | 1895 | * to be greater than 64). If we only have one curve |
| 1457 | rates[i] = txpower; | 1896 | * we don't need to set this, if we have 2 curves and |
| 1458 | 1897 | * fill the table backwards this can also be used to | |
| 1459 | /* XXX setup target powers by rate */ | 1898 | * switch from higher power curve to lower power curve */ |
| 1460 | 1899 | u8 edge_flag; | |
| 1461 | ah->ah_txpower.txp_min = rates[7]; | 1900 | int i; |
| 1462 | ah->ah_txpower.txp_max = rates[0]; | 1901 | |
| 1463 | ah->ah_txpower.txp_ofdm = rates[0]; | 1902 | /* When we have only one curve available |
| 1464 | 1903 | * that's the higher power curve. If we have | |
| 1465 | /* Calculate the power table */ | 1904 | * two curves the first is the high power curve |
| 1466 | n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac); | 1905 | * and the next is the low power curve. */ |
| 1467 | min = AR5K_EEPROM_PCDAC_START; | 1906 | if (pdcurves > 1) { |
| 1468 | max = AR5K_EEPROM_PCDAC_STOP; | 1907 | pcdac_low_pwr = ah->ah_txpower.tmpL[1]; |
| 1469 | for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP) | 1908 | pcdac_high_pwr = ah->ah_txpower.tmpL[0]; |
| 1470 | ah->ah_txpower.txp_pcdac[i] = | 1909 | mid_pwr_idx = table_max[1] - table_min[1] - 1; |
| 1471 | #ifdef notyet | 1910 | max_pwr_idx = (table_max[0] - table_min[0]) / 2; |
| 1472 | min + ((i * (max - min)) / n); | 1911 | |
| 1473 | #else | 1912 | /* If table size goes beyond 31.5dB, keep the |
| 1474 | min; | 1913 | * upper 31.5dB range when setting tx power. |
| 1914 | * Note: 126 = 31.5 dB in quarter dB steps */ | ||
| 1915 | if (table_max[0] - table_min[1] > 126) | ||
| 1916 | min_pwr_idx = table_max[0] - 126; | ||
| 1917 | else | ||
| 1918 | min_pwr_idx = table_min[1]; | ||
| 1919 | |||
| 1920 | /* Since we fill table backwards | ||
| 1921 | * start from high power curve */ | ||
| 1922 | pcdac_tmp = pcdac_high_pwr; | ||
| 1923 | |||
| 1924 | edge_flag = 0x40; | ||
| 1925 | #if 0 | ||
| 1926 | /* If both min and max power limits are in lower | ||
| 1927 | * power curve's range, only use the low power curve. | ||
| 1928 | * TODO: min/max levels are related to target | ||
| 1929 | * power values requested from driver/user | ||
| 1930 | * XXX: Is this really needed ? */ | ||
| 1931 | if (min_pwr < table_max[1] && | ||
| 1932 | max_pwr < table_max[1]) { | ||
| 1933 | edge_flag = 0; | ||
| 1934 | pcdac_tmp = pcdac_low_pwr; | ||
| 1935 | max_pwr_idx = (table_max[1] - table_min[1])/2; | ||
| 1936 | } | ||
| 1475 | #endif | 1937 | #endif |
| 1938 | } else { | ||
| 1939 | pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */ | ||
| 1940 | pcdac_high_pwr = ah->ah_txpower.tmpL[0]; | ||
| 1941 | min_pwr_idx = table_min[0]; | ||
| 1942 | max_pwr_idx = (table_max[0] - table_min[0]) / 2; | ||
| 1943 | pcdac_tmp = pcdac_high_pwr; | ||
| 1944 | edge_flag = 0; | ||
| 1945 | } | ||
| 1946 | |||
| 1947 | /* This is used when setting tx power*/ | ||
| 1948 | ah->ah_txpower.txp_min_idx = min_pwr_idx/2; | ||
| 1949 | |||
| 1950 | /* Fill Power to PCDAC table backwards */ | ||
| 1951 | pwr = max_pwr_idx; | ||
| 1952 | for (i = 63; i >= 0; i--) { | ||
| 1953 | /* Entering lower power range, reset | ||
| 1954 | * edge flag and set pcdac_tmp to lower | ||
| 1955 | * power curve.*/ | ||
| 1956 | if (edge_flag == 0x40 && | ||
| 1957 | (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) { | ||
| 1958 | edge_flag = 0x00; | ||
| 1959 | pcdac_tmp = pcdac_low_pwr; | ||
| 1960 | pwr = mid_pwr_idx/2; | ||
| 1961 | } | ||
| 1962 | |||
| 1963 | /* Don't go below 1, extrapolate below if we have | ||
| 1964 | * already swithced to the lower power curve -or | ||
| 1965 | * we only have one curve and edge_flag is zero | ||
| 1966 | * anyway */ | ||
| 1967 | if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) { | ||
| 1968 | while (i >= 0) { | ||
| 1969 | pcdac_out[i] = pcdac_out[i + 1]; | ||
| 1970 | i--; | ||
| 1971 | } | ||
| 1972 | break; | ||
| 1973 | } | ||
| 1974 | |||
| 1975 | pcdac_out[i] = pcdac_tmp[pwr] | edge_flag; | ||
| 1976 | |||
| 1977 | /* Extrapolate above if pcdac is greater than | ||
| 1978 | * 126 -this can happen because we OR pcdac_out | ||
| 1979 | * value with edge_flag on high power curve */ | ||
| 1980 | if (pcdac_out[i] > 126) | ||
| 1981 | pcdac_out[i] = 126; | ||
| 1982 | |||
| 1983 | /* Decrease by a 0.5dB step */ | ||
| 1984 | pwr--; | ||
| 1985 | } | ||
| 1476 | } | 1986 | } |
| 1477 | 1987 | ||
| 1988 | /* Write PCDAC values on hw */ | ||
| 1989 | static void | ||
| 1990 | ath5k_setup_pcdac_table(struct ath5k_hw *ah) | ||
| 1991 | { | ||
| 1992 | u8 *pcdac_out = ah->ah_txpower.txp_pd_table; | ||
| 1993 | int i; | ||
| 1994 | |||
| 1995 | /* | ||
| 1996 | * Write TX power values | ||
| 1997 | */ | ||
| 1998 | for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { | ||
| 1999 | ath5k_hw_reg_write(ah, | ||
| 2000 | (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) | | ||
| 2001 | (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16), | ||
| 2002 | AR5K_PHY_PCDAC_TXPOWER(i)); | ||
| 2003 | } | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | |||
| 1478 | /* | 2007 | /* |
| 1479 | * Set transmition power | 2008 | * Power to PDADC table functions |
| 1480 | */ | 2009 | */ |
| 1481 | int /*O.K. - txpower_table is unimplemented so this doesn't work*/ | 2010 | |
| 1482 | ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, | 2011 | /* |
| 1483 | unsigned int txpower) | 2012 | * Set the gain boundaries and create final Power to PDADC table |
| 2013 | * | ||
| 2014 | * We can have up to 4 pd curves, we need to do a simmilar process | ||
| 2015 | * as we do for RF5112. This time we don't have an edge_flag but we | ||
| 2016 | * set the gain boundaries on a separate register. | ||
| 2017 | */ | ||
| 2018 | static void | ||
| 2019 | ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, | ||
| 2020 | s16 *pwr_min, s16 *pwr_max, u8 pdcurves) | ||
| 1484 | { | 2021 | { |
| 1485 | bool tpc = ah->ah_txpower.txp_tpc; | 2022 | u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS]; |
| 1486 | unsigned int i; | 2023 | u8 *pdadc_out = ah->ah_txpower.txp_pd_table; |
| 2024 | u8 *pdadc_tmp; | ||
| 2025 | s16 pdadc_0; | ||
| 2026 | u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size; | ||
| 2027 | u8 pd_gain_overlap; | ||
| 2028 | |||
| 2029 | /* Note: Register value is initialized on initvals | ||
| 2030 | * there is no feedback from hw. | ||
| 2031 | * XXX: What about pd_gain_overlap from EEPROM ? */ | ||
| 2032 | pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) & | ||
| 2033 | AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP; | ||
| 2034 | |||
| 2035 | /* Create final PDADC table */ | ||
| 2036 | for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) { | ||
| 2037 | pdadc_tmp = ah->ah_txpower.tmpL[pdg]; | ||
| 2038 | |||
| 2039 | if (pdg == pdcurves - 1) | ||
| 2040 | /* 2 dB boundary stretch for last | ||
| 2041 | * (higher power) curve */ | ||
| 2042 | gain_boundaries[pdg] = pwr_max[pdg] + 4; | ||
| 2043 | else | ||
| 2044 | /* Set gain boundary in the middle | ||
| 2045 | * between this curve and the next one */ | ||
| 2046 | gain_boundaries[pdg] = | ||
| 2047 | (pwr_max[pdg] + pwr_min[pdg + 1]) / 2; | ||
| 2048 | |||
| 2049 | /* Sanity check in case our 2 db stretch got out of | ||
| 2050 | * range. */ | ||
| 2051 | if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER) | ||
| 2052 | gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER; | ||
| 2053 | |||
| 2054 | /* For the first curve (lower power) | ||
| 2055 | * start from 0 dB */ | ||
| 2056 | if (pdg == 0) | ||
| 2057 | pdadc_0 = 0; | ||
| 2058 | else | ||
| 2059 | /* For the other curves use the gain overlap */ | ||
| 2060 | pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) - | ||
| 2061 | pd_gain_overlap; | ||
| 1487 | 2062 | ||
| 1488 | ATH5K_TRACE(ah->ah_sc); | 2063 | /* Force each power step to be at least 0.5 dB */ |
| 1489 | if (txpower > AR5K_TUNE_MAX_TXPOWER) { | 2064 | if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) |
| 1490 | ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); | 2065 | pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; |
| 1491 | return -EINVAL; | 2066 | else |
| 2067 | pwr_step = 1; | ||
| 2068 | |||
| 2069 | /* If pdadc_0 is negative, we need to extrapolate | ||
| 2070 | * below this pdgain by a number of pwr_steps */ | ||
| 2071 | while ((pdadc_0 < 0) && (pdadc_i < 128)) { | ||
| 2072 | s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step; | ||
| 2073 | pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp; | ||
| 2074 | pdadc_0++; | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | /* Set last pwr level, using gain boundaries */ | ||
| 2078 | pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg]; | ||
| 2079 | /* Limit it to be inside pwr range */ | ||
| 2080 | table_size = pwr_max[pdg] - pwr_min[pdg]; | ||
| 2081 | max_idx = (pdadc_n < table_size) ? pdadc_n : table_size; | ||
| 2082 | |||
| 2083 | /* Fill pdadc_out table */ | ||
| 2084 | while (pdadc_0 < max_idx) | ||
| 2085 | pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++]; | ||
| 2086 | |||
| 2087 | /* Need to extrapolate above this pdgain? */ | ||
| 2088 | if (pdadc_n <= max_idx) | ||
| 2089 | continue; | ||
| 2090 | |||
| 2091 | /* Force each power step to be at least 0.5 dB */ | ||
| 2092 | if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) | ||
| 2093 | pwr_step = pdadc_tmp[table_size - 1] - | ||
| 2094 | pdadc_tmp[table_size - 2]; | ||
| 2095 | else | ||
| 2096 | pwr_step = 1; | ||
| 2097 | |||
| 2098 | /* Extrapolate above */ | ||
| 2099 | while ((pdadc_0 < (s16) pdadc_n) && | ||
| 2100 | (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) { | ||
| 2101 | s16 tmp = pdadc_tmp[table_size - 1] + | ||
| 2102 | (pdadc_0 - max_idx) * pwr_step; | ||
| 2103 | pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp; | ||
| 2104 | pdadc_0++; | ||
| 2105 | } | ||
| 1492 | } | 2106 | } |
| 1493 | 2107 | ||
| 2108 | while (pdg < AR5K_EEPROM_N_PD_GAINS) { | ||
| 2109 | gain_boundaries[pdg] = gain_boundaries[pdg - 1]; | ||
| 2110 | pdg++; | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) { | ||
| 2114 | pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1]; | ||
| 2115 | pdadc_i++; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | /* Set gain boundaries */ | ||
| 2119 | ath5k_hw_reg_write(ah, | ||
| 2120 | AR5K_REG_SM(pd_gain_overlap, | ||
| 2121 | AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) | | ||
| 2122 | AR5K_REG_SM(gain_boundaries[0], | ||
| 2123 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) | | ||
| 2124 | AR5K_REG_SM(gain_boundaries[1], | ||
| 2125 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) | | ||
| 2126 | AR5K_REG_SM(gain_boundaries[2], | ||
| 2127 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) | | ||
| 2128 | AR5K_REG_SM(gain_boundaries[3], | ||
| 2129 | AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4), | ||
| 2130 | AR5K_PHY_TPC_RG5); | ||
| 2131 | |||
| 2132 | /* Used for setting rate power table */ | ||
| 2133 | ah->ah_txpower.txp_min_idx = pwr_min[0]; | ||
| 2134 | |||
| 2135 | } | ||
| 2136 | |||
| 2137 | /* Write PDADC values on hw */ | ||
| 2138 | static void | ||
| 2139 | ath5k_setup_pwr_to_pdadc_table(struct ath5k_hw *ah, | ||
| 2140 | u8 pdcurves, u8 *pdg_to_idx) | ||
| 2141 | { | ||
| 2142 | u8 *pdadc_out = ah->ah_txpower.txp_pd_table; | ||
| 2143 | u32 reg; | ||
| 2144 | u8 i; | ||
| 2145 | |||
| 2146 | /* Select the right pdgain curves */ | ||
| 2147 | |||
| 2148 | /* Clear current settings */ | ||
| 2149 | reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1); | ||
| 2150 | reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 | | ||
| 2151 | AR5K_PHY_TPC_RG1_PDGAIN_2 | | ||
| 2152 | AR5K_PHY_TPC_RG1_PDGAIN_3 | | ||
| 2153 | AR5K_PHY_TPC_RG1_NUM_PD_GAIN); | ||
| 2154 | |||
| 1494 | /* | 2155 | /* |
| 1495 | * RF2413 for some reason can't | 2156 | * Use pd_gains curve from eeprom |
| 1496 | * transmit anything if we call | ||
| 1497 | * this funtion, so we skip it | ||
| 1498 | * until we fix txpower. | ||
| 1499 | * | 2157 | * |
| 1500 | * XXX: Assume same for RF2425 | 2158 | * This overrides the default setting from initvals |
| 1501 | * to be safe. | 2159 | * in case some vendors (e.g. Zcomax) don't use the default |
| 2160 | * curves. If we don't honor their settings we 'll get a | ||
| 2161 | * 5dB (1 * gain overlap ?) drop. | ||
| 1502 | */ | 2162 | */ |
| 1503 | if ((ah->ah_radio == AR5K_RF2413) || (ah->ah_radio == AR5K_RF2425)) | 2163 | reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN); |
| 1504 | return 0; | ||
| 1505 | 2164 | ||
| 1506 | /* Reset TX power values */ | 2165 | switch (pdcurves) { |
| 1507 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); | 2166 | case 3: |
| 1508 | ah->ah_txpower.txp_tpc = tpc; | 2167 | reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3); |
| 1509 | 2168 | /* Fall through */ | |
| 1510 | /* Initialize TX power table */ | 2169 | case 2: |
| 1511 | ath5k_txpower_table(ah, channel, txpower); | 2170 | reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2); |
| 2171 | /* Fall through */ | ||
| 2172 | case 1: | ||
| 2173 | reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1); | ||
| 2174 | break; | ||
| 2175 | } | ||
| 2176 | ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1); | ||
| 1512 | 2177 | ||
| 1513 | /* | 2178 | /* |
| 1514 | * Write TX power values | 2179 | * Write TX power values |
| 1515 | */ | 2180 | */ |
| 1516 | for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { | 2181 | for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { |
| 1517 | ath5k_hw_reg_write(ah, | 2182 | ath5k_hw_reg_write(ah, |
| 1518 | ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) | | 2183 | ((pdadc_out[4*i + 0] & 0xff) << 0) | |
| 1519 | (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | 0xff) & 0xffff), | 2184 | ((pdadc_out[4*i + 1] & 0xff) << 8) | |
| 1520 | AR5K_PHY_PCDAC_TXPOWER(i)); | 2185 | ((pdadc_out[4*i + 2] & 0xff) << 16) | |
| 2186 | ((pdadc_out[4*i + 3] & 0xff) << 24), | ||
| 2187 | AR5K_PHY_PDADC_TXPOWER(i)); | ||
| 2188 | } | ||
| 2189 | } | ||
| 2190 | |||
| 2191 | |||
| 2192 | /* | ||
| 2193 | * Common code for PCDAC/PDADC tables | ||
| 2194 | */ | ||
| 2195 | |||
| 2196 | /* | ||
| 2197 | * This is the main function that uses all of the above | ||
| 2198 | * to set PCDAC/PDADC table on hw for the current channel. | ||
| 2199 | * This table is used for tx power calibration on the basband, | ||
| 2200 | * without it we get weird tx power levels and in some cases | ||
| 2201 | * distorted spectral mask | ||
| 2202 | */ | ||
| 2203 | static int | ||
| 2204 | ath5k_setup_channel_powertable(struct ath5k_hw *ah, | ||
| 2205 | struct ieee80211_channel *channel, | ||
| 2206 | u8 ee_mode, u8 type) | ||
| 2207 | { | ||
| 2208 | struct ath5k_pdgain_info *pdg_L, *pdg_R; | ||
| 2209 | struct ath5k_chan_pcal_info *pcinfo_L; | ||
| 2210 | struct ath5k_chan_pcal_info *pcinfo_R; | ||
| 2211 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
| 2212 | u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode]; | ||
| 2213 | s16 table_min[AR5K_EEPROM_N_PD_GAINS]; | ||
| 2214 | s16 table_max[AR5K_EEPROM_N_PD_GAINS]; | ||
| 2215 | u8 *tmpL; | ||
| 2216 | u8 *tmpR; | ||
| 2217 | u32 target = channel->center_freq; | ||
| 2218 | int pdg, i; | ||
| 2219 | |||
| 2220 | /* Get surounding freq piers for this channel */ | ||
| 2221 | ath5k_get_chan_pcal_surrounding_piers(ah, channel, | ||
| 2222 | &pcinfo_L, | ||
| 2223 | &pcinfo_R); | ||
| 2224 | |||
| 2225 | /* Loop over pd gain curves on | ||
| 2226 | * surounding freq piers by index */ | ||
| 2227 | for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { | ||
| 2228 | |||
| 2229 | /* Fill curves in reverse order | ||
| 2230 | * from lower power (max gain) | ||
| 2231 | * to higher power. Use curve -> idx | ||
| 2232 | * backmaping we did on eeprom init */ | ||
| 2233 | u8 idx = pdg_curve_to_idx[pdg]; | ||
| 2234 | |||
| 2235 | /* Grab the needed curves by index */ | ||
| 2236 | pdg_L = &pcinfo_L->pd_curves[idx]; | ||
| 2237 | pdg_R = &pcinfo_R->pd_curves[idx]; | ||
| 2238 | |||
| 2239 | /* Initialize the temp tables */ | ||
| 2240 | tmpL = ah->ah_txpower.tmpL[pdg]; | ||
| 2241 | tmpR = ah->ah_txpower.tmpR[pdg]; | ||
| 2242 | |||
| 2243 | /* Set curve's x boundaries and create | ||
| 2244 | * curves so that they cover the same | ||
| 2245 | * range (if we don't do that one table | ||
| 2246 | * will have values on some range and the | ||
| 2247 | * other one won't have any so interpolation | ||
| 2248 | * will fail) */ | ||
| 2249 | table_min[pdg] = min(pdg_L->pd_pwr[0], | ||
| 2250 | pdg_R->pd_pwr[0]) / 2; | ||
| 2251 | |||
| 2252 | table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1], | ||
| 2253 | pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2; | ||
| 2254 | |||
| 2255 | /* Now create the curves on surrounding channels | ||
| 2256 | * and interpolate if needed to get the final | ||
| 2257 | * curve for this gain on this channel */ | ||
| 2258 | switch (type) { | ||
| 2259 | case AR5K_PWRTABLE_LINEAR_PCDAC: | ||
| 2260 | /* Override min/max so that we don't loose | ||
| 2261 | * accuracy (don't divide by 2) */ | ||
| 2262 | table_min[pdg] = min(pdg_L->pd_pwr[0], | ||
| 2263 | pdg_R->pd_pwr[0]); | ||
| 2264 | |||
| 2265 | table_max[pdg] = | ||
| 2266 | max(pdg_L->pd_pwr[pdg_L->pd_points - 1], | ||
| 2267 | pdg_R->pd_pwr[pdg_R->pd_points - 1]); | ||
| 2268 | |||
| 2269 | /* Override minimum so that we don't get | ||
| 2270 | * out of bounds while extrapolating | ||
| 2271 | * below. Don't do this when we have 2 | ||
| 2272 | * curves and we are on the high power curve | ||
| 2273 | * because table_min is ok in this case */ | ||
| 2274 | if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) { | ||
| 2275 | |||
| 2276 | table_min[pdg] = | ||
| 2277 | ath5k_get_linear_pcdac_min(pdg_L->pd_step, | ||
| 2278 | pdg_R->pd_step, | ||
| 2279 | pdg_L->pd_pwr, | ||
| 2280 | pdg_R->pd_pwr); | ||
| 2281 | |||
| 2282 | /* Don't go too low because we will | ||
| 2283 | * miss the upper part of the curve. | ||
| 2284 | * Note: 126 = 31.5dB (max power supported) | ||
| 2285 | * in 0.25dB units */ | ||
| 2286 | if (table_max[pdg] - table_min[pdg] > 126) | ||
| 2287 | table_min[pdg] = table_max[pdg] - 126; | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | /* Fall through */ | ||
| 2291 | case AR5K_PWRTABLE_PWR_TO_PCDAC: | ||
| 2292 | case AR5K_PWRTABLE_PWR_TO_PDADC: | ||
| 2293 | |||
| 2294 | ath5k_create_power_curve(table_min[pdg], | ||
| 2295 | table_max[pdg], | ||
| 2296 | pdg_L->pd_pwr, | ||
| 2297 | pdg_L->pd_step, | ||
| 2298 | pdg_L->pd_points, tmpL, type); | ||
| 2299 | |||
| 2300 | /* We are in a calibration | ||
| 2301 | * pier, no need to interpolate | ||
| 2302 | * between freq piers */ | ||
| 2303 | if (pcinfo_L == pcinfo_R) | ||
| 2304 | continue; | ||
| 2305 | |||
| 2306 | ath5k_create_power_curve(table_min[pdg], | ||
| 2307 | table_max[pdg], | ||
| 2308 | pdg_R->pd_pwr, | ||
| 2309 | pdg_R->pd_step, | ||
| 2310 | pdg_R->pd_points, tmpR, type); | ||
| 2311 | break; | ||
| 2312 | default: | ||
| 2313 | return -EINVAL; | ||
| 2314 | } | ||
| 2315 | |||
| 2316 | /* Interpolate between curves | ||
| 2317 | * of surounding freq piers to | ||
| 2318 | * get the final curve for this | ||
| 2319 | * pd gain. Re-use tmpL for interpolation | ||
| 2320 | * output */ | ||
| 2321 | for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) && | ||
| 2322 | (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) { | ||
| 2323 | tmpL[i] = (u8) ath5k_get_interpolated_value(target, | ||
| 2324 | (s16) pcinfo_L->freq, | ||
| 2325 | (s16) pcinfo_R->freq, | ||
| 2326 | (s16) tmpL[i], | ||
| 2327 | (s16) tmpR[i]); | ||
| 2328 | } | ||
| 1521 | } | 2329 | } |
| 1522 | 2330 | ||
| 2331 | /* Now we have a set of curves for this | ||
| 2332 | * channel on tmpL (x range is table_max - table_min | ||
| 2333 | * and y values are tmpL[pdg][]) sorted in the same | ||
| 2334 | * order as EEPROM (because we've used the backmaping). | ||
| 2335 | * So for RF5112 it's from higher power to lower power | ||
| 2336 | * and for RF2413 it's from lower power to higher power. | ||
| 2337 | * For RF5111 we only have one curve. */ | ||
| 2338 | |||
| 2339 | /* Fill min and max power levels for this | ||
| 2340 | * channel by interpolating the values on | ||
| 2341 | * surounding channels to complete the dataset */ | ||
| 2342 | ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, | ||
| 2343 | (s16) pcinfo_L->freq, | ||
| 2344 | (s16) pcinfo_R->freq, | ||
| 2345 | pcinfo_L->min_pwr, pcinfo_R->min_pwr); | ||
| 2346 | |||
| 2347 | ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target, | ||
| 2348 | (s16) pcinfo_L->freq, | ||
| 2349 | (s16) pcinfo_R->freq, | ||
| 2350 | pcinfo_L->max_pwr, pcinfo_R->max_pwr); | ||
| 2351 | |||
| 2352 | /* We are ready to go, fill PCDAC/PDADC | ||
| 2353 | * table and write settings on hardware */ | ||
| 2354 | switch (type) { | ||
| 2355 | case AR5K_PWRTABLE_LINEAR_PCDAC: | ||
| 2356 | /* For RF5112 we can have one or two curves | ||
| 2357 | * and each curve covers a certain power lvl | ||
| 2358 | * range so we need to do some more processing */ | ||
| 2359 | ath5k_combine_linear_pcdac_curves(ah, table_min, table_max, | ||
| 2360 | ee->ee_pd_gains[ee_mode]); | ||
| 2361 | |||
| 2362 | /* Set txp.offset so that we can | ||
| 2363 | * match max power value with max | ||
| 2364 | * table index */ | ||
| 2365 | ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2); | ||
| 2366 | |||
| 2367 | /* Write settings on hw */ | ||
| 2368 | ath5k_setup_pcdac_table(ah); | ||
| 2369 | break; | ||
| 2370 | case AR5K_PWRTABLE_PWR_TO_PCDAC: | ||
| 2371 | /* We are done for RF5111 since it has only | ||
| 2372 | * one curve, just fit the curve on the table */ | ||
| 2373 | ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max); | ||
| 2374 | |||
| 2375 | /* No rate powertable adjustment for RF5111 */ | ||
| 2376 | ah->ah_txpower.txp_min_idx = 0; | ||
| 2377 | ah->ah_txpower.txp_offset = 0; | ||
| 2378 | |||
| 2379 | /* Write settings on hw */ | ||
| 2380 | ath5k_setup_pcdac_table(ah); | ||
| 2381 | break; | ||
| 2382 | case AR5K_PWRTABLE_PWR_TO_PDADC: | ||
| 2383 | /* Set PDADC boundaries and fill | ||
| 2384 | * final PDADC table */ | ||
| 2385 | ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max, | ||
| 2386 | ee->ee_pd_gains[ee_mode]); | ||
| 2387 | |||
| 2388 | /* Write settings on hw */ | ||
| 2389 | ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx); | ||
| 2390 | |||
| 2391 | /* Set txp.offset, note that table_min | ||
| 2392 | * can be negative */ | ||
| 2393 | ah->ah_txpower.txp_offset = table_min[0]; | ||
| 2394 | break; | ||
| 2395 | default: | ||
| 2396 | return -EINVAL; | ||
| 2397 | } | ||
| 2398 | |||
| 2399 | return 0; | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | |||
| 2403 | /* | ||
| 2404 | * Per-rate tx power setting | ||
| 2405 | * | ||
| 2406 | * This is the code that sets the desired tx power (below | ||
| 2407 | * maximum) on hw for each rate (we also have TPC that sets | ||
| 2408 | * power per packet). We do that by providing an index on the | ||
| 2409 | * PCDAC/PDADC table we set up. | ||
| 2410 | */ | ||
| 2411 | |||
| 2412 | /* | ||
| 2413 | * Set rate power table | ||
| 2414 | * | ||
| 2415 | * For now we only limit txpower based on maximum tx power | ||
| 2416 | * supported by hw (what's inside rate_info). We need to limit | ||
| 2417 | * this even more, based on regulatory domain etc. | ||
| 2418 | * | ||
| 2419 | * Rate power table contains indices to PCDAC/PDADC table (0.5dB steps) | ||
| 2420 | * and is indexed as follows: | ||
| 2421 | * rates[0] - rates[7] -> OFDM rates | ||
| 2422 | * rates[8] - rates[14] -> CCK rates | ||
| 2423 | * rates[15] -> XR rates (they all have the same power) | ||
| 2424 | */ | ||
| 2425 | static void | ||
| 2426 | ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr, | ||
| 2427 | struct ath5k_rate_pcal_info *rate_info, | ||
| 2428 | u8 ee_mode) | ||
| 2429 | { | ||
| 2430 | unsigned int i; | ||
| 2431 | u16 *rates; | ||
| 2432 | |||
| 2433 | /* max_pwr is power level we got from driver/user in 0.5dB | ||
| 2434 | * units, switch to 0.25dB units so we can compare */ | ||
| 2435 | max_pwr *= 2; | ||
| 2436 | max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2; | ||
| 2437 | |||
| 2438 | /* apply rate limits */ | ||
| 2439 | rates = ah->ah_txpower.txp_rates_power_table; | ||
| 2440 | |||
| 2441 | /* OFDM rates 6 to 24Mb/s */ | ||
| 2442 | for (i = 0; i < 5; i++) | ||
| 2443 | rates[i] = min(max_pwr, rate_info->target_power_6to24); | ||
| 2444 | |||
| 2445 | /* Rest OFDM rates */ | ||
| 2446 | rates[5] = min(rates[0], rate_info->target_power_36); | ||
| 2447 | rates[6] = min(rates[0], rate_info->target_power_48); | ||
| 2448 | rates[7] = min(rates[0], rate_info->target_power_54); | ||
| 2449 | |||
| 2450 | /* CCK rates */ | ||
| 2451 | /* 1L */ | ||
| 2452 | rates[8] = min(rates[0], rate_info->target_power_6to24); | ||
| 2453 | /* 2L */ | ||
| 2454 | rates[9] = min(rates[0], rate_info->target_power_36); | ||
| 2455 | /* 2S */ | ||
| 2456 | rates[10] = min(rates[0], rate_info->target_power_36); | ||
| 2457 | /* 5L */ | ||
| 2458 | rates[11] = min(rates[0], rate_info->target_power_48); | ||
| 2459 | /* 5S */ | ||
| 2460 | rates[12] = min(rates[0], rate_info->target_power_48); | ||
| 2461 | /* 11L */ | ||
| 2462 | rates[13] = min(rates[0], rate_info->target_power_54); | ||
| 2463 | /* 11S */ | ||
| 2464 | rates[14] = min(rates[0], rate_info->target_power_54); | ||
| 2465 | |||
| 2466 | /* XR rates */ | ||
| 2467 | rates[15] = min(rates[0], rate_info->target_power_6to24); | ||
| 2468 | |||
| 2469 | /* CCK rates have different peak to average ratio | ||
| 2470 | * so we have to tweak their power so that gainf | ||
| 2471 | * correction works ok. For this we use OFDM to | ||
| 2472 | * CCK delta from eeprom */ | ||
| 2473 | if ((ee_mode == AR5K_EEPROM_MODE_11G) && | ||
| 2474 | (ah->ah_phy_revision < AR5K_SREV_PHY_5212A)) | ||
| 2475 | for (i = 8; i <= 15; i++) | ||
| 2476 | rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta; | ||
| 2477 | |||
| 2478 | ah->ah_txpower.txp_min_pwr = rates[7]; | ||
| 2479 | ah->ah_txpower.txp_max_pwr = rates[0]; | ||
| 2480 | ah->ah_txpower.txp_ofdm = rates[7]; | ||
| 2481 | } | ||
| 2482 | |||
| 2483 | |||
| 2484 | /* | ||
| 2485 | * Set transmition power | ||
| 2486 | */ | ||
| 2487 | int | ||
| 2488 | ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, | ||
| 2489 | u8 ee_mode, u8 txpower) | ||
| 2490 | { | ||
| 2491 | struct ath5k_rate_pcal_info rate_info; | ||
| 2492 | u8 type; | ||
| 2493 | int ret; | ||
| 2494 | |||
| 2495 | ATH5K_TRACE(ah->ah_sc); | ||
| 2496 | if (txpower > AR5K_TUNE_MAX_TXPOWER) { | ||
| 2497 | ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); | ||
| 2498 | return -EINVAL; | ||
| 2499 | } | ||
| 2500 | if (txpower == 0) | ||
| 2501 | txpower = AR5K_TUNE_DEFAULT_TXPOWER; | ||
| 2502 | |||
| 2503 | /* Reset TX power values */ | ||
| 2504 | memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); | ||
| 2505 | ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; | ||
| 2506 | ah->ah_txpower.txp_min_pwr = 0; | ||
| 2507 | ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER; | ||
| 2508 | |||
| 2509 | /* Initialize TX power table */ | ||
| 2510 | switch (ah->ah_radio) { | ||
| 2511 | case AR5K_RF5111: | ||
| 2512 | type = AR5K_PWRTABLE_PWR_TO_PCDAC; | ||
| 2513 | break; | ||
| 2514 | case AR5K_RF5112: | ||
| 2515 | type = AR5K_PWRTABLE_LINEAR_PCDAC; | ||
| 2516 | break; | ||
| 2517 | case AR5K_RF2413: | ||
| 2518 | case AR5K_RF5413: | ||
| 2519 | case AR5K_RF2316: | ||
| 2520 | case AR5K_RF2317: | ||
| 2521 | case AR5K_RF2425: | ||
| 2522 | type = AR5K_PWRTABLE_PWR_TO_PDADC; | ||
| 2523 | break; | ||
| 2524 | default: | ||
| 2525 | return -EINVAL; | ||
| 2526 | } | ||
| 2527 | |||
| 2528 | /* FIXME: Only on channel/mode change */ | ||
| 2529 | ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type); | ||
| 2530 | if (ret) | ||
| 2531 | return ret; | ||
| 2532 | |||
| 2533 | /* Limit max power if we have a CTL available */ | ||
| 2534 | ath5k_get_max_ctl_power(ah, channel); | ||
| 2535 | |||
| 2536 | /* FIXME: Tx power limit for this regdomain | ||
| 2537 | * XXX: Mac80211/CRDA will do that anyway ? */ | ||
| 2538 | |||
| 2539 | /* FIXME: Antenna reduction stuff */ | ||
| 2540 | |||
| 2541 | /* FIXME: Limit power on turbo modes */ | ||
| 2542 | |||
| 2543 | /* FIXME: TPC scale reduction */ | ||
| 2544 | |||
| 2545 | /* Get surounding channels for per-rate power table | ||
| 2546 | * calibration */ | ||
| 2547 | ath5k_get_rate_pcal_data(ah, channel, &rate_info); | ||
| 2548 | |||
| 2549 | /* Setup rate power table */ | ||
| 2550 | ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode); | ||
| 2551 | |||
| 2552 | /* Write rate power table on hw */ | ||
| 1523 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | | 2553 | ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | |
| 1524 | AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | | 2554 | AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | |
| 1525 | AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); | 2555 | AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); |
| @@ -1536,26 +2566,34 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
| 1536 | AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | | 2566 | AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | |
| 1537 | AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); | 2567 | AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); |
| 1538 | 2568 | ||
| 1539 | if (ah->ah_txpower.txp_tpc) | 2569 | /* FIXME: TPC support */ |
| 2570 | if (ah->ah_txpower.txp_tpc) { | ||
| 1540 | ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | | 2571 | ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | |
| 1541 | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); | 2572 | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); |
| 1542 | else | 2573 | |
| 2574 | ath5k_hw_reg_write(ah, | ||
| 2575 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) | | ||
| 2576 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) | | ||
| 2577 | AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP), | ||
| 2578 | AR5K_TPC); | ||
| 2579 | } else { | ||
| 1543 | ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | | 2580 | ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | |
| 1544 | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); | 2581 | AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); |
| 2582 | } | ||
| 1545 | 2583 | ||
| 1546 | return 0; | 2584 | return 0; |
| 1547 | } | 2585 | } |
| 1548 | 2586 | ||
| 1549 | int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power) | 2587 | int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 mode, u8 txpower) |
| 1550 | { | 2588 | { |
| 1551 | /*Just a try M.F.*/ | 2589 | /*Just a try M.F.*/ |
| 1552 | struct ieee80211_channel *channel = &ah->ah_current_channel; | 2590 | struct ieee80211_channel *channel = &ah->ah_current_channel; |
| 1553 | 2591 | ||
| 1554 | ATH5K_TRACE(ah->ah_sc); | 2592 | ATH5K_TRACE(ah->ah_sc); |
| 1555 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, | 2593 | ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, |
| 1556 | "changing txpower to %d\n", power); | 2594 | "changing txpower to %d\n", txpower); |
| 1557 | 2595 | ||
| 1558 | return ath5k_hw_txpower(ah, channel, power); | 2596 | return ath5k_hw_txpower(ah, channel, mode, txpower); |
| 1559 | } | 2597 | } |
| 1560 | 2598 | ||
| 1561 | #undef _ATH5K_PHY | 2599 | #undef _ATH5K_PHY |
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index 2dc008e10226..7070d1543cdc 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h | |||
| @@ -1554,6 +1554,19 @@ | |||
| 1554 | /*===5212 Specific PCU registers===*/ | 1554 | /*===5212 Specific PCU registers===*/ |
| 1555 | 1555 | ||
| 1556 | /* | 1556 | /* |
| 1557 | * Transmit power control register | ||
| 1558 | */ | ||
| 1559 | #define AR5K_TPC 0x80e8 | ||
| 1560 | #define AR5K_TPC_ACK 0x0000003f /* ack frames */ | ||
| 1561 | #define AR5K_TPC_ACK_S 0 | ||
| 1562 | #define AR5K_TPC_CTS 0x00003f00 /* cts frames */ | ||
| 1563 | #define AR5K_TPC_CTS_S 8 | ||
| 1564 | #define AR5K_TPC_CHIRP 0x003f0000 /* chirp frames */ | ||
| 1565 | #define AR5K_TPC_CHIRP_S 16 | ||
| 1566 | #define AR5K_TPC_DOPPLER 0x0f000000 /* doppler chirp span */ | ||
| 1567 | #define AR5K_TPC_DOPPLER_S 24 | ||
| 1568 | |||
| 1569 | /* | ||
| 1557 | * XR (eXtended Range) mode register | 1570 | * XR (eXtended Range) mode register |
| 1558 | */ | 1571 | */ |
| 1559 | #define AR5K_XRMODE 0x80c0 /* Register Address */ | 1572 | #define AR5K_XRMODE 0x80c0 /* Register Address */ |
| @@ -2550,6 +2563,12 @@ | |||
| 2550 | #define AR5K_PHY_TPC_RG1 0xa258 | 2563 | #define AR5K_PHY_TPC_RG1 0xa258 |
| 2551 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 | 2564 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN 0x0000c000 |
| 2552 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 | 2565 | #define AR5K_PHY_TPC_RG1_NUM_PD_GAIN_S 14 |
| 2566 | #define AR5K_PHY_TPC_RG1_PDGAIN_1 0x00030000 | ||
| 2567 | #define AR5K_PHY_TPC_RG1_PDGAIN_1_S 16 | ||
| 2568 | #define AR5K_PHY_TPC_RG1_PDGAIN_2 0x000c0000 | ||
| 2569 | #define AR5K_PHY_TPC_RG1_PDGAIN_2_S 18 | ||
| 2570 | #define AR5K_PHY_TPC_RG1_PDGAIN_3 0x00300000 | ||
| 2571 | #define AR5K_PHY_TPC_RG1_PDGAIN_3_S 20 | ||
| 2553 | 2572 | ||
| 2554 | #define AR5K_PHY_TPC_RG5 0xa26C | 2573 | #define AR5K_PHY_TPC_RG5 0xa26C |
| 2555 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F | 2574 | #define AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP 0x0000000F |
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 685dc213edae..7a17d31b2fd9 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c | |||
| @@ -664,29 +664,35 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, | |||
| 664 | struct ieee80211_channel *channel, u8 *ant, u8 ee_mode) | 664 | struct ieee80211_channel *channel, u8 *ant, u8 ee_mode) |
| 665 | { | 665 | { |
| 666 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | 666 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; |
| 667 | s16 cck_ofdm_pwr_delta; | ||
| 667 | 668 | ||
| 668 | /* Set CCK to OFDM power delta */ | 669 | /* Adjust power delta for channel 14 */ |
| 669 | if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { | 670 | if (channel->center_freq == 2484) |
| 670 | int16_t cck_ofdm_pwr_delta; | 671 | cck_ofdm_pwr_delta = |
| 671 | 672 | ((ee->ee_cck_ofdm_power_delta - | |
| 672 | /* Adjust power delta for channel 14 */ | 673 | ee->ee_scaled_cck_delta) * 2) / 10; |
| 673 | if (channel->center_freq == 2484) | 674 | else |
| 674 | cck_ofdm_pwr_delta = | 675 | cck_ofdm_pwr_delta = |
| 675 | ((ee->ee_cck_ofdm_power_delta - | 676 | (ee->ee_cck_ofdm_power_delta * 2) / 10; |
| 676 | ee->ee_scaled_cck_delta) * 2) / 10; | ||
| 677 | else | ||
| 678 | cck_ofdm_pwr_delta = | ||
| 679 | (ee->ee_cck_ofdm_power_delta * 2) / 10; | ||
| 680 | 677 | ||
| 678 | /* Set CCK to OFDM power delta on tx power | ||
| 679 | * adjustment register */ | ||
| 680 | if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { | ||
| 681 | if (channel->hw_value == CHANNEL_G) | 681 | if (channel->hw_value == CHANNEL_G) |
| 682 | ath5k_hw_reg_write(ah, | 682 | ath5k_hw_reg_write(ah, |
| 683 | AR5K_REG_SM((ee->ee_cck_ofdm_power_delta * -1), | 683 | AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), |
| 684 | AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | | 684 | AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | |
| 685 | AR5K_REG_SM((cck_ofdm_pwr_delta * -1), | 685 | AR5K_REG_SM((cck_ofdm_pwr_delta * -1), |
| 686 | AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX), | 686 | AR5K_PHY_TX_PWR_ADJ_CCK_PCDAC_INDEX), |
| 687 | AR5K_PHY_TX_PWR_ADJ); | 687 | AR5K_PHY_TX_PWR_ADJ); |
| 688 | else | 688 | else |
| 689 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ); | 689 | ath5k_hw_reg_write(ah, 0, AR5K_PHY_TX_PWR_ADJ); |
| 690 | } else { | ||
| 691 | /* For older revs we scale power on sw during tx power | ||
| 692 | * setup */ | ||
| 693 | ah->ah_txpower.txp_cck_ofdm_pwr_delta = cck_ofdm_pwr_delta; | ||
| 694 | ah->ah_txpower.txp_cck_ofdm_gainf_delta = | ||
| 695 | ee->ee_cck_ofdm_gain_delta; | ||
| 690 | } | 696 | } |
| 691 | 697 | ||
| 692 | /* Set antenna idle switch table */ | 698 | /* Set antenna idle switch table */ |
| @@ -994,7 +1000,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, | |||
| 994 | /* | 1000 | /* |
| 995 | * Set TX power (FIXME) | 1001 | * Set TX power (FIXME) |
| 996 | */ | 1002 | */ |
| 997 | ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); | 1003 | ret = ath5k_hw_txpower(ah, channel, ee_mode, |
| 1004 | AR5K_TUNE_DEFAULT_TXPOWER); | ||
| 998 | if (ret) | 1005 | if (ret) |
| 999 | return ret; | 1006 | return ret; |
| 1000 | 1007 | ||
diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c index 00cc7bb01f2e..0e65c51ba176 100644 --- a/drivers/net/wireless/ath9k/ahb.c +++ b/drivers/net/wireless/ath9k/ahb.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> | 3 | * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org> |
| 4 | * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> | 4 | * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org> |
| 5 | * | 5 | * |
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index a39eb760cbb7..6c5e887d50d7 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/ani.h b/drivers/net/wireless/ath9k/ani.h index 7315761f6d74..08b4e7ed5ff0 100644 --- a/drivers/net/wireless/ath9k/ani.h +++ b/drivers/net/wireless/ath9k/ani.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index b64be8e9a690..2689a08a2844 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -295,13 +295,9 @@ struct ath_tx_control { | |||
| 295 | enum ath9k_internal_frame_type frame_type; | 295 | enum ath9k_internal_frame_type frame_type; |
| 296 | }; | 296 | }; |
| 297 | 297 | ||
| 298 | struct ath_xmit_status { | ||
| 299 | int retries; | ||
| 300 | int flags; | ||
| 301 | #define ATH_TX_ERROR 0x01 | 298 | #define ATH_TX_ERROR 0x01 |
| 302 | #define ATH_TX_XRETRY 0x02 | 299 | #define ATH_TX_XRETRY 0x02 |
| 303 | #define ATH_TX_BAR 0x04 | 300 | #define ATH_TX_BAR 0x04 |
| 304 | }; | ||
| 305 | 301 | ||
| 306 | /* All RSSI values are noise floor adjusted */ | 302 | /* All RSSI values are noise floor adjusted */ |
| 307 | struct ath_tx_stat { | 303 | struct ath_tx_stat { |
| @@ -390,6 +386,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid | |||
| 390 | 386 | ||
| 391 | struct ath_vif { | 387 | struct ath_vif { |
| 392 | int av_bslot; | 388 | int av_bslot; |
| 389 | __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ | ||
| 393 | enum nl80211_iftype av_opmode; | 390 | enum nl80211_iftype av_opmode; |
| 394 | struct ath_buf *av_bcbuf; | 391 | struct ath_buf *av_bcbuf; |
| 395 | struct ath_tx_control av_btxctl; | 392 | struct ath_tx_control av_btxctl; |
| @@ -406,7 +403,7 @@ struct ath_vif { | |||
| 406 | * number of beacon intervals, the game's up. | 403 | * number of beacon intervals, the game's up. |
| 407 | */ | 404 | */ |
| 408 | #define BSTUCK_THRESH (9 * ATH_BCBUF) | 405 | #define BSTUCK_THRESH (9 * ATH_BCBUF) |
| 409 | #define ATH_BCBUF 1 | 406 | #define ATH_BCBUF 4 |
| 410 | #define ATH_DEFAULT_BINTVAL 100 /* TU */ | 407 | #define ATH_DEFAULT_BINTVAL 100 /* TU */ |
| 411 | #define ATH_DEFAULT_BMISS_LIMIT 10 | 408 | #define ATH_DEFAULT_BMISS_LIMIT 10 |
| 412 | #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) | 409 | #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) |
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 039c78136c50..ec995730632d 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -70,7 +70,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
| 70 | ds = bf->bf_desc; | 70 | ds = bf->bf_desc; |
| 71 | flags = ATH9K_TXDESC_NOACK; | 71 | flags = ATH9K_TXDESC_NOACK; |
| 72 | 72 | ||
| 73 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC && | 73 | if (((sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || |
| 74 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) && | ||
| 74 | (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { | 75 | (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)) { |
| 75 | ds->ds_link = bf->bf_daddr; /* self-linked */ | 76 | ds->ds_link = bf->bf_daddr; /* self-linked */ |
| 76 | flags |= ATH9K_TXDESC_VEOL; | 77 | flags |= ATH9K_TXDESC_VEOL; |
| @@ -153,6 +154,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
| 153 | bf->bf_mpdu = skb; | 154 | bf->bf_mpdu = skb; |
| 154 | if (skb == NULL) | 155 | if (skb == NULL) |
| 155 | return NULL; | 156 | return NULL; |
| 157 | ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = | ||
| 158 | avp->tsf_adjust; | ||
| 156 | 159 | ||
| 157 | info = IEEE80211_SKB_CB(skb); | 160 | info = IEEE80211_SKB_CB(skb); |
| 158 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { | 161 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { |
| @@ -253,7 +256,6 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
| 253 | { | 256 | { |
| 254 | struct ath_softc *sc = aphy->sc; | 257 | struct ath_softc *sc = aphy->sc; |
| 255 | struct ath_vif *avp; | 258 | struct ath_vif *avp; |
| 256 | struct ieee80211_hdr *hdr; | ||
| 257 | struct ath_buf *bf; | 259 | struct ath_buf *bf; |
| 258 | struct sk_buff *skb; | 260 | struct sk_buff *skb; |
| 259 | __le64 tstamp; | 261 | __le64 tstamp; |
| @@ -316,42 +318,33 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
| 316 | 318 | ||
| 317 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | 319 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; |
| 318 | sc->beacon.bc_tstamp = le64_to_cpu(tstamp); | 320 | sc->beacon.bc_tstamp = le64_to_cpu(tstamp); |
| 319 | 321 | /* Calculate a TSF adjustment factor required for staggered beacons. */ | |
| 320 | /* | ||
| 321 | * Calculate a TSF adjustment factor required for | ||
| 322 | * staggered beacons. Note that we assume the format | ||
| 323 | * of the beacon frame leaves the tstamp field immediately | ||
| 324 | * following the header. | ||
| 325 | */ | ||
| 326 | if (avp->av_bslot > 0) { | 322 | if (avp->av_bslot > 0) { |
| 327 | u64 tsfadjust; | 323 | u64 tsfadjust; |
| 328 | __le64 val; | ||
| 329 | int intval; | 324 | int intval; |
| 330 | 325 | ||
| 331 | intval = sc->hw->conf.beacon_int ? | 326 | intval = sc->hw->conf.beacon_int ? |
| 332 | sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; | 327 | sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; |
| 333 | 328 | ||
| 334 | /* | 329 | /* |
| 335 | * The beacon interval is in TU's; the TSF in usecs. | 330 | * Calculate the TSF offset for this beacon slot, i.e., the |
| 336 | * We figure out how many TU's to add to align the | 331 | * number of usecs that need to be added to the timestamp field |
| 337 | * timestamp then convert to TSF units and handle | 332 | * in Beacon and Probe Response frames. Beacon slot 0 is |
| 338 | * byte swapping before writing it in the frame. | 333 | * processed at the correct offset, so it does not require TSF |
| 339 | * The hardware will then add this each time a beacon | 334 | * adjustment. Other slots are adjusted to get the timestamp |
| 340 | * frame is sent. Note that we align vif's 1..N | 335 | * close to the TBTT for the BSS. |
| 341 | * and leave vif 0 untouched. This means vap 0 | ||
| 342 | * has a timestamp in one beacon interval while the | ||
| 343 | * others get a timestamp aligned to the next interval. | ||
| 344 | */ | 336 | */ |
| 345 | tsfadjust = (intval * (ATH_BCBUF - avp->av_bslot)) / ATH_BCBUF; | 337 | tsfadjust = intval * avp->av_bslot / ATH_BCBUF; |
| 346 | val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */ | 338 | avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); |
| 347 | 339 | ||
| 348 | DPRINTF(sc, ATH_DBG_BEACON, | 340 | DPRINTF(sc, ATH_DBG_BEACON, |
| 349 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", | 341 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", |
| 350 | avp->av_bslot, intval, (unsigned long long)tsfadjust); | 342 | avp->av_bslot, intval, (unsigned long long)tsfadjust); |
| 351 | 343 | ||
| 352 | hdr = (struct ieee80211_hdr *)skb->data; | 344 | ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = |
| 353 | memcpy(&hdr[1], &val, sizeof(val)); | 345 | avp->tsf_adjust; |
| 354 | } | 346 | } else |
| 347 | avp->tsf_adjust = cpu_to_le64(0); | ||
| 355 | 348 | ||
| 356 | bf->bf_mpdu = skb; | 349 | bf->bf_mpdu = skb; |
| 357 | bf->bf_buf_addr = bf->bf_dmacontext = | 350 | bf->bf_buf_addr = bf->bf_dmacontext = |
| @@ -447,8 +440,16 @@ void ath_beacon_tasklet(unsigned long data) | |||
| 447 | tsf = ath9k_hw_gettsf64(ah); | 440 | tsf = ath9k_hw_gettsf64(ah); |
| 448 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 441 | tsftu = TSF_TO_TU(tsf>>32, tsf); |
| 449 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 442 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; |
| 450 | vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; | 443 | /* |
| 451 | aphy = sc->beacon.bslot_aphy[(slot + 1) % ATH_BCBUF]; | 444 | * Reverse the slot order to get slot 0 on the TBTT offset that does |
| 445 | * not require TSF adjustment and other slots adding | ||
| 446 | * slot/ATH_BCBUF * beacon_int to timestamp. For example, with | ||
| 447 | * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. | ||
| 448 | * and slot 0 is at correct offset to TBTT. | ||
| 449 | */ | ||
| 450 | slot = ATH_BCBUF - slot - 1; | ||
| 451 | vif = sc->beacon.bslot[slot]; | ||
| 452 | aphy = sc->beacon.bslot_aphy[slot]; | ||
| 452 | 453 | ||
| 453 | DPRINTF(sc, ATH_DBG_BEACON, | 454 | DPRINTF(sc, ATH_DBG_BEACON, |
| 454 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | 455 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", |
| @@ -728,6 +729,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
| 728 | ath_beacon_config_ap(sc, &conf, avp); | 729 | ath_beacon_config_ap(sc, &conf, avp); |
| 729 | break; | 730 | break; |
| 730 | case NL80211_IFTYPE_ADHOC: | 731 | case NL80211_IFTYPE_ADHOC: |
| 732 | case NL80211_IFTYPE_MESH_POINT: | ||
| 731 | ath_beacon_config_adhoc(sc, &conf, avp, vif); | 733 | ath_beacon_config_adhoc(sc, &conf, avp, vif); |
| 732 | break; | 734 | break; |
| 733 | case NL80211_IFTYPE_STATION: | 735 | case NL80211_IFTYPE_STATION: |
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index c9446fb6b153..e2d62e97131c 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath9k/calib.h index 32589e0c5018..1c74bd50700d 100644 --- a/drivers/net/wireless/ath9k/calib.h +++ b/drivers/net/wireless/ath9k/calib.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index 82573cadb1ab..fdf9528fa49b 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h index 065268b8568f..7b0e5419d2bc 100644 --- a/drivers/net/wireless/ath9k/debug.h +++ b/drivers/net/wireless/ath9k/debug.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index 183c949bcca1..ffc36b0361c7 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -342,8 +342,7 @@ static int ath9k_hw_4k_get_eeprom_rev(struct ath_hw *ah) | |||
| 342 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | 342 | static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) |
| 343 | { | 343 | { |
| 344 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) | 344 | #define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) |
| 345 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | 345 | u16 *eep_data = (u16 *)&ah->eeprom.map4k; |
| 346 | u16 *eep_data; | ||
| 347 | int addr, eep_start_loc = 0; | 346 | int addr, eep_start_loc = 0; |
| 348 | 347 | ||
| 349 | eep_start_loc = 64; | 348 | eep_start_loc = 64; |
| @@ -353,8 +352,6 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | |||
| 353 | "Reading from EEPROM, not flash\n"); | 352 | "Reading from EEPROM, not flash\n"); |
| 354 | } | 353 | } |
| 355 | 354 | ||
| 356 | eep_data = (u16 *)eep; | ||
| 357 | |||
| 358 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { | 355 | for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { |
| 359 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { | 356 | if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { |
| 360 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 357 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, |
| @@ -363,6 +360,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) | |||
| 363 | } | 360 | } |
| 364 | eep_data++; | 361 | eep_data++; |
| 365 | } | 362 | } |
| 363 | |||
| 366 | return true; | 364 | return true; |
| 367 | #undef SIZE_EEPROM_4K | 365 | #undef SIZE_EEPROM_4K |
| 368 | } | 366 | } |
| @@ -379,16 +377,15 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | |||
| 379 | 377 | ||
| 380 | 378 | ||
| 381 | if (!ath9k_hw_use_flash(ah)) { | 379 | if (!ath9k_hw_use_flash(ah)) { |
| 382 | |||
| 383 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | 380 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, |
| 384 | &magic)) { | 381 | &magic)) { |
| 385 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 382 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 386 | "Reading Magic # failed\n"); | 383 | "Reading Magic # failed\n"); |
| 387 | return false; | 384 | return false; |
| 388 | } | 385 | } |
| 389 | 386 | ||
| 390 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 387 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, |
| 391 | "Read Magic = 0x%04X\n", magic); | 388 | "Read Magic = 0x%04X\n", magic); |
| 392 | 389 | ||
| 393 | if (magic != AR5416_EEPROM_MAGIC) { | 390 | if (magic != AR5416_EEPROM_MAGIC) { |
| 394 | magic2 = swab16(magic); | 391 | magic2 = swab16(magic); |
| @@ -401,16 +398,9 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | |||
| 401 | temp = swab16(*eepdata); | 398 | temp = swab16(*eepdata); |
| 402 | *eepdata = temp; | 399 | *eepdata = temp; |
| 403 | eepdata++; | 400 | eepdata++; |
| 404 | |||
| 405 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
| 406 | "0x%04X ", *eepdata); | ||
| 407 | |||
| 408 | if (((addr + 1) % 6) == 0) | ||
| 409 | DPRINTF(ah->ah_sc, | ||
| 410 | ATH_DBG_EEPROM, "\n"); | ||
| 411 | } | 401 | } |
| 412 | } else { | 402 | } else { |
| 413 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 403 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 414 | "Invalid EEPROM Magic. " | 404 | "Invalid EEPROM Magic. " |
| 415 | "endianness mismatch.\n"); | 405 | "endianness mismatch.\n"); |
| 416 | return -EINVAL; | 406 | return -EINVAL; |
| @@ -426,7 +416,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | |||
| 426 | else | 416 | else |
| 427 | el = ah->eeprom.map4k.baseEepHeader.length; | 417 | el = ah->eeprom.map4k.baseEepHeader.length; |
| 428 | 418 | ||
| 429 | if (el > sizeof(struct ar5416_eeprom_def)) | 419 | if (el > sizeof(struct ar5416_eeprom_4k)) |
| 430 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); | 420 | el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); |
| 431 | else | 421 | else |
| 432 | el = el / sizeof(u16); | 422 | el = el / sizeof(u16); |
| @@ -441,7 +431,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | |||
| 441 | u16 word; | 431 | u16 word; |
| 442 | 432 | ||
| 443 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 433 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, |
| 444 | "EEPROM Endianness is not native.. Changing \n"); | 434 | "EEPROM Endianness is not native.. Changing\n"); |
| 445 | 435 | ||
| 446 | word = swab16(eep->baseEepHeader.length); | 436 | word = swab16(eep->baseEepHeader.length); |
| 447 | eep->baseEepHeader.length = word; | 437 | eep->baseEepHeader.length = word; |
| @@ -483,7 +473,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) | |||
| 483 | 473 | ||
| 484 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | 474 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || |
| 485 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | 475 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { |
| 486 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 476 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 487 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | 477 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", |
| 488 | sum, ah->eep_ops->get_eeprom_ver(ah)); | 478 | sum, ah->eep_ops->get_eeprom_ver(ah)); |
| 489 | return -EINVAL; | 479 | return -EINVAL; |
| @@ -1203,57 +1193,63 @@ static void ath9k_hw_4k_set_addac(struct ath_hw *ah, | |||
| 1203 | } | 1193 | } |
| 1204 | } | 1194 | } |
| 1205 | 1195 | ||
| 1206 | static bool ath9k_hw_4k_set_board_values(struct ath_hw *ah, | 1196 | static void ath9k_hw_4k_set_gain(struct ath_hw *ah, |
| 1207 | struct ath9k_channel *chan) | 1197 | struct modal_eep_4k_header *pModal, |
| 1198 | struct ar5416_eeprom_4k *eep, | ||
| 1199 | u8 txRxAttenLocal, int regChainOffset) | ||
| 1208 | { | 1200 | { |
| 1209 | struct modal_eep_4k_header *pModal; | ||
| 1210 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
| 1211 | int regChainOffset; | ||
| 1212 | u8 txRxAttenLocal; | ||
| 1213 | u8 ob[5], db1[5], db2[5]; | ||
| 1214 | u8 ant_div_control1, ant_div_control2; | ||
| 1215 | u32 regVal; | ||
| 1216 | |||
| 1217 | |||
| 1218 | pModal = &eep->modalHeader; | ||
| 1219 | |||
| 1220 | txRxAttenLocal = 23; | ||
| 1221 | |||
| 1222 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
| 1223 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
| 1224 | |||
| 1225 | regChainOffset = 0; | ||
| 1226 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, | 1201 | REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, |
| 1227 | pModal->antCtrlChain[0]); | 1202 | pModal->antCtrlChain[0]); |
| 1228 | 1203 | ||
| 1229 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | 1204 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, |
| 1230 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & | 1205 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & |
| 1231 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | 1206 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | |
| 1232 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | 1207 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | |
| 1233 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | | 1208 | SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | |
| 1234 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | 1209 | SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); |
| 1235 | 1210 | ||
| 1236 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= | 1211 | if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= |
| 1237 | AR5416_EEP_MINOR_VER_3) { | 1212 | AR5416_EEP_MINOR_VER_3) { |
| 1238 | txRxAttenLocal = pModal->txRxAttenCh[0]; | 1213 | txRxAttenLocal = pModal->txRxAttenCh[0]; |
| 1214 | |||
| 1239 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | 1215 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, |
| 1240 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); | 1216 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); |
| 1241 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | 1217 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, |
| 1242 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); | 1218 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); |
| 1243 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | 1219 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, |
| 1244 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | 1220 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, |
| 1245 | pModal->xatten2Margin[0]); | 1221 | pModal->xatten2Margin[0]); |
| 1246 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | 1222 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, |
| 1247 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); | 1223 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); |
| 1248 | } | 1224 | } |
| 1249 | 1225 | ||
| 1250 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | 1226 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, |
| 1251 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | 1227 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); |
| 1252 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, | 1228 | REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, |
| 1253 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); | 1229 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); |
| 1254 | 1230 | ||
| 1255 | if (AR_SREV_9285_11(ah)) | 1231 | if (AR_SREV_9285_11(ah)) |
| 1256 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | 1232 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); |
| 1233 | } | ||
| 1234 | |||
| 1235 | static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, | ||
| 1236 | struct ath9k_channel *chan) | ||
| 1237 | { | ||
| 1238 | struct modal_eep_4k_header *pModal; | ||
| 1239 | struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; | ||
| 1240 | u8 txRxAttenLocal; | ||
| 1241 | u8 ob[5], db1[5], db2[5]; | ||
| 1242 | u8 ant_div_control1, ant_div_control2; | ||
| 1243 | u32 regVal; | ||
| 1244 | |||
| 1245 | pModal = &eep->modalHeader; | ||
| 1246 | txRxAttenLocal = 23; | ||
| 1247 | |||
| 1248 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | ||
| 1249 | ah->eep_ops->get_eeprom_antenna_cfg(ah, chan)); | ||
| 1250 | |||
| 1251 | /* Single chain for 4K EEPROM*/ | ||
| 1252 | ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0); | ||
| 1257 | 1253 | ||
| 1258 | /* Initialize Ant Diversity settings from EEPROM */ | 1254 | /* Initialize Ant Diversity settings from EEPROM */ |
| 1259 | if (pModal->version == 3) { | 1255 | if (pModal->version == 3) { |
| @@ -1295,9 +1291,6 @@ static bool ath9k_hw_4k_set_board_values(struct ath_hw *ah, | |||
| 1295 | db2[4] = ((pModal->db2_234 >> 8) & 0xf); | 1291 | db2[4] = ((pModal->db2_234 >> 8) & 0xf); |
| 1296 | 1292 | ||
| 1297 | } else if (pModal->version == 1) { | 1293 | } else if (pModal->version == 1) { |
| 1298 | |||
| 1299 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
| 1300 | "EEPROM Model version is set to 1 \n"); | ||
| 1301 | ob[0] = (pModal->ob_01 & 0xf); | 1294 | ob[0] = (pModal->ob_01 & 0xf); |
| 1302 | ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; | 1295 | ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; |
| 1303 | db1[0] = (pModal->db1_01 & 0xf); | 1296 | db1[0] = (pModal->db1_01 & 0xf); |
| @@ -1385,8 +1378,6 @@ static bool ath9k_hw_4k_set_board_values(struct ath_hw *ah, | |||
| 1385 | AR_PHY_SETTLING_SWITCH, | 1378 | AR_PHY_SETTLING_SWITCH, |
| 1386 | pModal->swSettleHt40); | 1379 | pModal->swSettleHt40); |
| 1387 | } | 1380 | } |
| 1388 | |||
| 1389 | return true; | ||
| 1390 | } | 1381 | } |
| 1391 | 1382 | ||
| 1392 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, | 1383 | static u16 ath9k_hw_4k_get_eeprom_antenna_cfg(struct ath_hw *ah, |
| @@ -1464,16 +1455,13 @@ static int ath9k_hw_def_get_eeprom_rev(struct ath_hw *ah) | |||
| 1464 | static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) | 1455 | static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) |
| 1465 | { | 1456 | { |
| 1466 | #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) | 1457 | #define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) |
| 1467 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | 1458 | u16 *eep_data = (u16 *)&ah->eeprom.def; |
| 1468 | u16 *eep_data; | ||
| 1469 | int addr, ar5416_eep_start_loc = 0x100; | 1459 | int addr, ar5416_eep_start_loc = 0x100; |
| 1470 | 1460 | ||
| 1471 | eep_data = (u16 *)eep; | ||
| 1472 | |||
| 1473 | for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { | 1461 | for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { |
| 1474 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, | 1462 | if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, |
| 1475 | eep_data)) { | 1463 | eep_data)) { |
| 1476 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 1464 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 1477 | "Unable to read eeprom region\n"); | 1465 | "Unable to read eeprom region\n"); |
| 1478 | return false; | 1466 | return false; |
| 1479 | } | 1467 | } |
| @@ -1492,17 +1480,14 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | |||
| 1492 | bool need_swap = false; | 1480 | bool need_swap = false; |
| 1493 | int i, addr, size; | 1481 | int i, addr, size; |
| 1494 | 1482 | ||
| 1495 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, | 1483 | if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { |
| 1496 | &magic)) { | 1484 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Reading Magic # failed\n"); |
| 1497 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
| 1498 | "Reading Magic # failed\n"); | ||
| 1499 | return false; | 1485 | return false; |
| 1500 | } | 1486 | } |
| 1501 | 1487 | ||
| 1502 | if (!ath9k_hw_use_flash(ah)) { | 1488 | if (!ath9k_hw_use_flash(ah)) { |
| 1503 | |||
| 1504 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 1489 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, |
| 1505 | "Read Magic = 0x%04X\n", magic); | 1490 | "Read Magic = 0x%04X\n", magic); |
| 1506 | 1491 | ||
| 1507 | if (magic != AR5416_EEPROM_MAGIC) { | 1492 | if (magic != AR5416_EEPROM_MAGIC) { |
| 1508 | magic2 = swab16(magic); | 1493 | magic2 = swab16(magic); |
| @@ -1516,18 +1501,11 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | |||
| 1516 | temp = swab16(*eepdata); | 1501 | temp = swab16(*eepdata); |
| 1517 | *eepdata = temp; | 1502 | *eepdata = temp; |
| 1518 | eepdata++; | 1503 | eepdata++; |
| 1519 | |||
| 1520 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
| 1521 | "0x%04X ", *eepdata); | ||
| 1522 | |||
| 1523 | if (((addr + 1) % 6) == 0) | ||
| 1524 | DPRINTF(ah->ah_sc, | ||
| 1525 | ATH_DBG_EEPROM, "\n"); | ||
| 1526 | } | 1504 | } |
| 1527 | } else { | 1505 | } else { |
| 1528 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 1506 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 1529 | "Invalid EEPROM Magic. " | 1507 | "Invalid EEPROM Magic. " |
| 1530 | "endianness mismatch.\n"); | 1508 | "Endianness mismatch.\n"); |
| 1531 | return -EINVAL; | 1509 | return -EINVAL; |
| 1532 | } | 1510 | } |
| 1533 | } | 1511 | } |
| @@ -1556,7 +1534,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | |||
| 1556 | u16 word; | 1534 | u16 word; |
| 1557 | 1535 | ||
| 1558 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 1536 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, |
| 1559 | "EEPROM Endianness is not native.. Changing \n"); | 1537 | "EEPROM Endianness is not native.. Changing.\n"); |
| 1560 | 1538 | ||
| 1561 | word = swab16(eep->baseEepHeader.length); | 1539 | word = swab16(eep->baseEepHeader.length); |
| 1562 | eep->baseEepHeader.length = word; | 1540 | eep->baseEepHeader.length = word; |
| @@ -1602,7 +1580,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | |||
| 1602 | 1580 | ||
| 1603 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || | 1581 | if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR5416_EEP_VER || |
| 1604 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { | 1582 | ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { |
| 1605 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | 1583 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
| 1606 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", | 1584 | "Bad EEPROM checksum 0x%x or revision 0x%04x\n", |
| 1607 | sum, ah->eep_ops->get_eeprom_ver(ah)); | 1585 | sum, ah->eep_ops->get_eeprom_ver(ah)); |
| 1608 | return -EINVAL; | 1586 | return -EINVAL; |
| @@ -1614,7 +1592,6 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) | |||
| 1614 | static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | 1592 | static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, |
| 1615 | enum eeprom_param param) | 1593 | enum eeprom_param param) |
| 1616 | { | 1594 | { |
| 1617 | #define AR5416_VER_MASK (pBase->version & AR5416_EEP_VER_MINOR_MASK) | ||
| 1618 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | 1595 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; |
| 1619 | struct modal_eep_header *pModal = eep->modalHeader; | 1596 | struct modal_eep_header *pModal = eep->modalHeader; |
| 1620 | struct base_eep_header *pBase = &eep->baseEepHeader; | 1597 | struct base_eep_header *pBase = &eep->baseEepHeader; |
| @@ -1681,21 +1658,73 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | |||
| 1681 | default: | 1658 | default: |
| 1682 | return 0; | 1659 | return 0; |
| 1683 | } | 1660 | } |
| 1684 | #undef AR5416_VER_MASK | ||
| 1685 | } | 1661 | } |
| 1686 | 1662 | ||
| 1687 | /* XXX: Clean me up, make me more legible */ | 1663 | static void ath9k_hw_def_set_gain(struct ath_hw *ah, |
| 1688 | static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | 1664 | struct modal_eep_header *pModal, |
| 1665 | struct ar5416_eeprom_def *eep, | ||
| 1666 | u8 txRxAttenLocal, int regChainOffset, int i) | ||
| 1667 | { | ||
| 1668 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | ||
| 1669 | txRxAttenLocal = pModal->txRxAttenCh[i]; | ||
| 1670 | |||
| 1671 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
| 1672 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1673 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
| 1674 | pModal->bswMargin[i]); | ||
| 1675 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1676 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
| 1677 | pModal->bswAtten[i]); | ||
| 1678 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1679 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
| 1680 | pModal->xatten2Margin[i]); | ||
| 1681 | REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1682 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
| 1683 | pModal->xatten2Db[i]); | ||
| 1684 | } else { | ||
| 1685 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1686 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
| 1687 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
| 1688 | | SM(pModal-> bswMargin[i], | ||
| 1689 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
| 1690 | REG_WRITE(ah, AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1691 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
| 1692 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
| 1693 | | SM(pModal->bswAtten[i], | ||
| 1694 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
| 1695 | } | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
| 1699 | REG_RMW_FIELD(ah, | ||
| 1700 | AR_PHY_RXGAIN + regChainOffset, | ||
| 1701 | AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); | ||
| 1702 | REG_RMW_FIELD(ah, | ||
| 1703 | AR_PHY_RXGAIN + regChainOffset, | ||
| 1704 | AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[i]); | ||
| 1705 | } else { | ||
| 1706 | REG_WRITE(ah, | ||
| 1707 | AR_PHY_RXGAIN + regChainOffset, | ||
| 1708 | (REG_READ(ah, AR_PHY_RXGAIN + regChainOffset) & | ||
| 1709 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | ||
| 1710 | | SM(txRxAttenLocal, AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
| 1711 | REG_WRITE(ah, | ||
| 1712 | AR_PHY_GAIN_2GHZ + regChainOffset, | ||
| 1713 | (REG_READ(ah, AR_PHY_GAIN_2GHZ + regChainOffset) & | ||
| 1714 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
| 1715 | SM(pModal->rxTxMarginCh[i], AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
| 1716 | } | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | static void ath9k_hw_def_set_board_values(struct ath_hw *ah, | ||
| 1689 | struct ath9k_channel *chan) | 1720 | struct ath9k_channel *chan) |
| 1690 | { | 1721 | { |
| 1691 | #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) | ||
| 1692 | struct modal_eep_header *pModal; | 1722 | struct modal_eep_header *pModal; |
| 1693 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; | 1723 | struct ar5416_eeprom_def *eep = &ah->eeprom.def; |
| 1694 | int i, regChainOffset; | 1724 | int i, regChainOffset; |
| 1695 | u8 txRxAttenLocal; | 1725 | u8 txRxAttenLocal; |
| 1696 | 1726 | ||
| 1697 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); | 1727 | pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); |
| 1698 | |||
| 1699 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; | 1728 | txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; |
| 1700 | 1729 | ||
| 1701 | REG_WRITE(ah, AR_PHY_SWITCH_COM, | 1730 | REG_WRITE(ah, AR_PHY_SWITCH_COM, |
| @@ -1708,8 +1737,7 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1708 | } | 1737 | } |
| 1709 | 1738 | ||
| 1710 | if (AR_SREV_5416_20_OR_LATER(ah) && | 1739 | if (AR_SREV_5416_20_OR_LATER(ah) && |
| 1711 | (ah->rxchainmask == 5 || ah->txchainmask == 5) | 1740 | (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) |
| 1712 | && (i != 0)) | ||
| 1713 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; | 1741 | regChainOffset = (i == 1) ? 0x2000 : 0x1000; |
| 1714 | else | 1742 | else |
| 1715 | regChainOffset = i * 0x1000; | 1743 | regChainOffset = i * 0x1000; |
| @@ -1718,9 +1746,7 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1718 | pModal->antCtrlChain[i]); | 1746 | pModal->antCtrlChain[i]); |
| 1719 | 1747 | ||
| 1720 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, | 1748 | REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, |
| 1721 | (REG_READ(ah, | 1749 | (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & |
| 1722 | AR_PHY_TIMING_CTRL4(0) + | ||
| 1723 | regChainOffset) & | ||
| 1724 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | | 1750 | ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | |
| 1725 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | | 1751 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | |
| 1726 | SM(pModal->iqCalICh[i], | 1752 | SM(pModal->iqCalICh[i], |
| @@ -1728,87 +1754,9 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1728 | SM(pModal->iqCalQCh[i], | 1754 | SM(pModal->iqCalQCh[i], |
| 1729 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); | 1755 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); |
| 1730 | 1756 | ||
| 1731 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { | 1757 | if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) |
| 1732 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) { | 1758 | ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, |
| 1733 | txRxAttenLocal = pModal->txRxAttenCh[i]; | 1759 | regChainOffset, i); |
| 1734 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
| 1735 | REG_RMW_FIELD(ah, | ||
| 1736 | AR_PHY_GAIN_2GHZ + | ||
| 1737 | regChainOffset, | ||
| 1738 | AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, | ||
| 1739 | pModal-> | ||
| 1740 | bswMargin[i]); | ||
| 1741 | REG_RMW_FIELD(ah, | ||
| 1742 | AR_PHY_GAIN_2GHZ + | ||
| 1743 | regChainOffset, | ||
| 1744 | AR_PHY_GAIN_2GHZ_XATTEN1_DB, | ||
| 1745 | pModal-> | ||
| 1746 | bswAtten[i]); | ||
| 1747 | REG_RMW_FIELD(ah, | ||
| 1748 | AR_PHY_GAIN_2GHZ + | ||
| 1749 | regChainOffset, | ||
| 1750 | AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, | ||
| 1751 | pModal-> | ||
| 1752 | xatten2Margin[i]); | ||
| 1753 | REG_RMW_FIELD(ah, | ||
| 1754 | AR_PHY_GAIN_2GHZ + | ||
| 1755 | regChainOffset, | ||
| 1756 | AR_PHY_GAIN_2GHZ_XATTEN2_DB, | ||
| 1757 | pModal-> | ||
| 1758 | xatten2Db[i]); | ||
| 1759 | } else { | ||
| 1760 | REG_WRITE(ah, | ||
| 1761 | AR_PHY_GAIN_2GHZ + | ||
| 1762 | regChainOffset, | ||
| 1763 | (REG_READ(ah, | ||
| 1764 | AR_PHY_GAIN_2GHZ + | ||
| 1765 | regChainOffset) & | ||
| 1766 | ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) | ||
| 1767 | | SM(pModal-> | ||
| 1768 | bswMargin[i], | ||
| 1769 | AR_PHY_GAIN_2GHZ_BSW_MARGIN)); | ||
| 1770 | REG_WRITE(ah, | ||
| 1771 | AR_PHY_GAIN_2GHZ + | ||
| 1772 | regChainOffset, | ||
| 1773 | (REG_READ(ah, | ||
| 1774 | AR_PHY_GAIN_2GHZ + | ||
| 1775 | regChainOffset) & | ||
| 1776 | ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) | ||
| 1777 | | SM(pModal->bswAtten[i], | ||
| 1778 | AR_PHY_GAIN_2GHZ_BSW_ATTEN)); | ||
| 1779 | } | ||
| 1780 | } | ||
| 1781 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
| 1782 | REG_RMW_FIELD(ah, | ||
| 1783 | AR_PHY_RXGAIN + | ||
| 1784 | regChainOffset, | ||
| 1785 | AR9280_PHY_RXGAIN_TXRX_ATTEN, | ||
| 1786 | txRxAttenLocal); | ||
| 1787 | REG_RMW_FIELD(ah, | ||
| 1788 | AR_PHY_RXGAIN + | ||
| 1789 | regChainOffset, | ||
| 1790 | AR9280_PHY_RXGAIN_TXRX_MARGIN, | ||
| 1791 | pModal->rxTxMarginCh[i]); | ||
| 1792 | } else { | ||
| 1793 | REG_WRITE(ah, | ||
| 1794 | AR_PHY_RXGAIN + regChainOffset, | ||
| 1795 | (REG_READ(ah, | ||
| 1796 | AR_PHY_RXGAIN + | ||
| 1797 | regChainOffset) & | ||
| 1798 | ~AR_PHY_RXGAIN_TXRX_ATTEN) | | ||
| 1799 | SM(txRxAttenLocal, | ||
| 1800 | AR_PHY_RXGAIN_TXRX_ATTEN)); | ||
| 1801 | REG_WRITE(ah, | ||
| 1802 | AR_PHY_GAIN_2GHZ + | ||
| 1803 | regChainOffset, | ||
| 1804 | (REG_READ(ah, | ||
| 1805 | AR_PHY_GAIN_2GHZ + | ||
| 1806 | regChainOffset) & | ||
| 1807 | ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | | ||
| 1808 | SM(pModal->rxTxMarginCh[i], | ||
| 1809 | AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); | ||
| 1810 | } | ||
| 1811 | } | ||
| 1812 | } | 1760 | } |
| 1813 | 1761 | ||
| 1814 | if (AR_SREV_9280_10_OR_LATER(ah)) { | 1762 | if (AR_SREV_9280_10_OR_LATER(ah)) { |
| @@ -1855,8 +1803,6 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1855 | AR_AN_TOP2_LOCALBIAS, | 1803 | AR_AN_TOP2_LOCALBIAS, |
| 1856 | AR_AN_TOP2_LOCALBIAS_S, | 1804 | AR_AN_TOP2_LOCALBIAS_S, |
| 1857 | pModal->local_bias); | 1805 | pModal->local_bias); |
| 1858 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", | ||
| 1859 | pModal->force_xpaon); | ||
| 1860 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, | 1806 | REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, |
| 1861 | pModal->force_xpaon); | 1807 | pModal->force_xpaon); |
| 1862 | } | 1808 | } |
| @@ -1882,6 +1828,7 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1882 | 1828 | ||
| 1883 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, | 1829 | REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, |
| 1884 | pModal->txEndToRxOn); | 1830 | pModal->txEndToRxOn); |
| 1831 | |||
| 1885 | if (AR_SREV_9280_10_OR_LATER(ah)) { | 1832 | if (AR_SREV_9280_10_OR_LATER(ah)) { |
| 1886 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, | 1833 | REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, |
| 1887 | pModal->thresh62); | 1834 | pModal->thresh62); |
| @@ -1912,10 +1859,10 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1912 | } | 1859 | } |
| 1913 | 1860 | ||
| 1914 | if (AR_SREV_9280_20_OR_LATER(ah) && | 1861 | if (AR_SREV_9280_20_OR_LATER(ah) && |
| 1915 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | 1862 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) |
| 1916 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | 1863 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, |
| 1917 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | 1864 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, |
| 1918 | pModal->miscBits); | 1865 | pModal->miscBits); |
| 1919 | 1866 | ||
| 1920 | 1867 | ||
| 1921 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | 1868 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { |
| @@ -1926,18 +1873,15 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
| 1926 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); | 1873 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, 0); |
| 1927 | else | 1874 | else |
| 1928 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | 1875 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, |
| 1929 | eep->baseEepHeader.dacLpMode); | 1876 | eep->baseEepHeader.dacLpMode); |
| 1930 | 1877 | ||
| 1931 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | 1878 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, |
| 1932 | pModal->miscBits >> 2); | 1879 | pModal->miscBits >> 2); |
| 1933 | 1880 | ||
| 1934 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | 1881 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, |
| 1935 | AR_PHY_TX_DESIRED_SCALE_CCK, | 1882 | AR_PHY_TX_DESIRED_SCALE_CCK, |
| 1936 | eep->baseEepHeader.desiredScaleCCK); | 1883 | eep->baseEepHeader.desiredScaleCCK); |
| 1937 | } | 1884 | } |
| 1938 | |||
| 1939 | return true; | ||
| 1940 | #undef AR5416_VER_MASK | ||
| 1941 | } | 1885 | } |
| 1942 | 1886 | ||
| 1943 | static void ath9k_hw_def_set_addac(struct ath_hw *ah, | 1887 | static void ath9k_hw_def_set_addac(struct ath_hw *ah, |
diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h index d6f6108f63c7..25b68c881ff1 100644 --- a/drivers/net/wireless/ath9k/eeprom.h +++ b/drivers/net/wireless/ath9k/eeprom.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -95,6 +95,7 @@ | |||
| 95 | #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) | 95 | #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) |
| 96 | #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) | 96 | #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) |
| 97 | 97 | ||
| 98 | #define AR5416_VER_MASK (eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) | ||
| 98 | #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ | 99 | #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ |
| 99 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | 100 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) |
| 100 | 101 | ||
| @@ -489,7 +490,7 @@ struct eeprom_ops { | |||
| 489 | u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band); | 490 | u8 (*get_num_ant_config)(struct ath_hw *hw, enum ieee80211_band band); |
| 490 | u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw, | 491 | u16 (*get_eeprom_antenna_cfg)(struct ath_hw *hw, |
| 491 | struct ath9k_channel *chan); | 492 | struct ath9k_channel *chan); |
| 492 | bool (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); | 493 | void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); |
| 493 | void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); | 494 | void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); |
| 494 | int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, | 495 | int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, |
| 495 | u16 cfgCtl, u8 twiceAntennaReduction, | 496 | u16 cfgCtl, u8 twiceAntennaReduction, |
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index d494e98ba971..b15eaf8417ff 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -588,6 +588,10 @@ static int ath9k_hw_post_attach(struct ath_hw *ah) | |||
| 588 | ecode = ath9k_hw_eeprom_attach(ah); | 588 | ecode = ath9k_hw_eeprom_attach(ah); |
| 589 | if (ecode != 0) | 589 | if (ecode != 0) |
| 590 | return ecode; | 590 | return ecode; |
| 591 | |||
| 592 | DPRINTF(ah->ah_sc, ATH_DBG_CONFIG, "Eeprom VER: %d, REV: %d\n", | ||
| 593 | ah->eep_ops->get_eeprom_ver(ah), ah->eep_ops->get_eeprom_rev(ah)); | ||
| 594 | |||
| 591 | ecode = ath9k_hw_rfattach(ah); | 595 | ecode = ath9k_hw_rfattach(ah); |
| 592 | if (ecode != 0) | 596 | if (ecode != 0) |
| 593 | return ecode; | 597 | return ecode; |
| @@ -1444,6 +1448,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode) | |||
| 1444 | REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | 1448 | REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
| 1445 | break; | 1449 | break; |
| 1446 | case NL80211_IFTYPE_ADHOC: | 1450 | case NL80211_IFTYPE_ADHOC: |
| 1451 | case NL80211_IFTYPE_MESH_POINT: | ||
| 1447 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | 1452 | REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC |
| 1448 | | AR_STA_ID1_KSRCH_MODE); | 1453 | | AR_STA_ID1_KSRCH_MODE); |
| 1449 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); | 1454 | REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); |
| @@ -2273,11 +2278,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, | |||
| 2273 | else | 2278 | else |
| 2274 | ath9k_hw_spur_mitigate(ah, chan); | 2279 | ath9k_hw_spur_mitigate(ah, chan); |
| 2275 | 2280 | ||
| 2276 | if (!ah->eep_ops->set_board_values(ah, chan)) { | 2281 | ah->eep_ops->set_board_values(ah, chan); |
| 2277 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
| 2278 | "error setting board options\n"); | ||
| 2279 | return -EIO; | ||
| 2280 | } | ||
| 2281 | 2282 | ||
| 2282 | ath9k_hw_decrease_chain_power(ah, chan); | 2283 | ath9k_hw_decrease_chain_power(ah, chan); |
| 2283 | 2284 | ||
| @@ -3149,6 +3150,7 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) | |||
| 3149 | flags |= AR_TBTT_TIMER_EN; | 3150 | flags |= AR_TBTT_TIMER_EN; |
| 3150 | break; | 3151 | break; |
| 3151 | case NL80211_IFTYPE_ADHOC: | 3152 | case NL80211_IFTYPE_ADHOC: |
| 3153 | case NL80211_IFTYPE_MESH_POINT: | ||
| 3152 | REG_SET_BIT(ah, AR_TXCFG, | 3154 | REG_SET_BIT(ah, AR_TXCFG, |
| 3153 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); | 3155 | AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); |
| 3154 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, | 3156 | REG_WRITE(ah, AR_NEXT_NDP_TIMER, |
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index dc681f011fdf..0b594e0ee260 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 1d60c3706f1c..e2f0a34b79a1 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index f757bc7eec68..e0a6dee45839 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath9k/mac.h index a75f65dae1d7..1176bce8b76c 100644 --- a/drivers/net/wireless/ath9k/mac.h +++ b/drivers/net/wireless/ath9k/mac.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 8db75f6de53e..13d4e6756c99 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -940,18 +940,25 @@ static void ath_led_blink_work(struct work_struct *work) | |||
| 940 | 940 | ||
| 941 | if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) | 941 | if (!(sc->sc_flags & SC_OP_LED_ASSOCIATED)) |
| 942 | return; | 942 | return; |
| 943 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | 943 | |
| 944 | (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); | 944 | if ((sc->led_on_duration == ATH_LED_ON_DURATION_IDLE) || |
| 945 | (sc->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) | ||
| 946 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); | ||
| 947 | else | ||
| 948 | ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, | ||
| 949 | (sc->sc_flags & SC_OP_LED_ON) ? 1 : 0); | ||
| 945 | 950 | ||
| 946 | queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, | 951 | queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work, |
| 947 | (sc->sc_flags & SC_OP_LED_ON) ? | 952 | (sc->sc_flags & SC_OP_LED_ON) ? |
| 948 | msecs_to_jiffies(sc->led_off_duration) : | 953 | msecs_to_jiffies(sc->led_off_duration) : |
| 949 | msecs_to_jiffies(sc->led_on_duration)); | 954 | msecs_to_jiffies(sc->led_on_duration)); |
| 950 | 955 | ||
| 951 | sc->led_on_duration = | 956 | sc->led_on_duration = sc->led_on_cnt ? |
| 952 | max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25); | 957 | max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) : |
| 953 | sc->led_off_duration = | 958 | ATH_LED_ON_DURATION_IDLE; |
| 954 | max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10); | 959 | sc->led_off_duration = sc->led_off_cnt ? |
| 960 | max((ATH_LED_OFF_DURATION_IDLE - sc->led_off_cnt), 10) : | ||
| 961 | ATH_LED_OFF_DURATION_IDLE; | ||
| 955 | sc->led_on_cnt = sc->led_off_cnt = 0; | 962 | sc->led_on_cnt = sc->led_off_cnt = 0; |
| 956 | if (sc->sc_flags & SC_OP_LED_ON) | 963 | if (sc->sc_flags & SC_OP_LED_ON) |
| 957 | sc->sc_flags &= ~SC_OP_LED_ON; | 964 | sc->sc_flags &= ~SC_OP_LED_ON; |
| @@ -1592,7 +1599,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) | |||
| 1592 | hw->wiphy->interface_modes = | 1599 | hw->wiphy->interface_modes = |
| 1593 | BIT(NL80211_IFTYPE_AP) | | 1600 | BIT(NL80211_IFTYPE_AP) | |
| 1594 | BIT(NL80211_IFTYPE_STATION) | | 1601 | BIT(NL80211_IFTYPE_STATION) | |
| 1595 | BIT(NL80211_IFTYPE_ADHOC); | 1602 | BIT(NL80211_IFTYPE_ADHOC) | |
| 1603 | BIT(NL80211_IFTYPE_MESH_POINT); | ||
| 1596 | 1604 | ||
| 1597 | hw->wiphy->reg_notifier = ath9k_reg_notifier; | 1605 | hw->wiphy->reg_notifier = ath9k_reg_notifier; |
| 1598 | hw->wiphy->strict_regulatory = true; | 1606 | hw->wiphy->strict_regulatory = true; |
| @@ -2200,18 +2208,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
| 2200 | ic_opmode = NL80211_IFTYPE_STATION; | 2208 | ic_opmode = NL80211_IFTYPE_STATION; |
| 2201 | break; | 2209 | break; |
| 2202 | case NL80211_IFTYPE_ADHOC: | 2210 | case NL80211_IFTYPE_ADHOC: |
| 2203 | if (sc->nbcnvifs >= ATH_BCBUF) { | ||
| 2204 | ret = -ENOBUFS; | ||
| 2205 | goto out; | ||
| 2206 | } | ||
| 2207 | ic_opmode = NL80211_IFTYPE_ADHOC; | ||
| 2208 | break; | ||
| 2209 | case NL80211_IFTYPE_AP: | 2211 | case NL80211_IFTYPE_AP: |
| 2212 | case NL80211_IFTYPE_MESH_POINT: | ||
| 2210 | if (sc->nbcnvifs >= ATH_BCBUF) { | 2213 | if (sc->nbcnvifs >= ATH_BCBUF) { |
| 2211 | ret = -ENOBUFS; | 2214 | ret = -ENOBUFS; |
| 2212 | goto out; | 2215 | goto out; |
| 2213 | } | 2216 | } |
| 2214 | ic_opmode = NL80211_IFTYPE_AP; | 2217 | ic_opmode = conf->type; |
| 2215 | break; | 2218 | break; |
| 2216 | default: | 2219 | default: |
| 2217 | DPRINTF(sc, ATH_DBG_FATAL, | 2220 | DPRINTF(sc, ATH_DBG_FATAL, |
| @@ -2247,7 +2250,8 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
| 2247 | * Note we only do this (at the moment) for station mode. | 2250 | * Note we only do this (at the moment) for station mode. |
| 2248 | */ | 2251 | */ |
| 2249 | if ((conf->type == NL80211_IFTYPE_STATION) || | 2252 | if ((conf->type == NL80211_IFTYPE_STATION) || |
| 2250 | (conf->type == NL80211_IFTYPE_ADHOC)) { | 2253 | (conf->type == NL80211_IFTYPE_ADHOC) || |
| 2254 | (conf->type == NL80211_IFTYPE_MESH_POINT)) { | ||
| 2251 | if (ath9k_hw_phycounters(sc->sc_ah)) | 2255 | if (ath9k_hw_phycounters(sc->sc_ah)) |
| 2252 | sc->imask |= ATH9K_INT_MIB; | 2256 | sc->imask |= ATH9K_INT_MIB; |
| 2253 | sc->imask |= ATH9K_INT_TSFOOR; | 2257 | sc->imask |= ATH9K_INT_TSFOOR; |
| @@ -2294,8 +2298,9 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
| 2294 | del_timer_sync(&sc->ani.timer); | 2298 | del_timer_sync(&sc->ani.timer); |
| 2295 | 2299 | ||
| 2296 | /* Reclaim beacon resources */ | 2300 | /* Reclaim beacon resources */ |
| 2297 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || | 2301 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || |
| 2298 | sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) { | 2302 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || |
| 2303 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { | ||
| 2299 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | 2304 | ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); |
| 2300 | ath_beacon_return(sc, avp); | 2305 | ath_beacon_return(sc, avp); |
| 2301 | } | 2306 | } |
| @@ -2428,6 +2433,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
| 2428 | switch (vif->type) { | 2433 | switch (vif->type) { |
| 2429 | case NL80211_IFTYPE_STATION: | 2434 | case NL80211_IFTYPE_STATION: |
| 2430 | case NL80211_IFTYPE_ADHOC: | 2435 | case NL80211_IFTYPE_ADHOC: |
| 2436 | case NL80211_IFTYPE_MESH_POINT: | ||
| 2431 | /* Set BSSID */ | 2437 | /* Set BSSID */ |
| 2432 | memcpy(sc->curbssid, conf->bssid, ETH_ALEN); | 2438 | memcpy(sc->curbssid, conf->bssid, ETH_ALEN); |
| 2433 | memcpy(avp->bssid, conf->bssid, ETH_ALEN); | 2439 | memcpy(avp->bssid, conf->bssid, ETH_ALEN); |
| @@ -2451,7 +2457,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, | |||
| 2451 | } | 2457 | } |
| 2452 | 2458 | ||
| 2453 | if ((vif->type == NL80211_IFTYPE_ADHOC) || | 2459 | if ((vif->type == NL80211_IFTYPE_ADHOC) || |
| 2454 | (vif->type == NL80211_IFTYPE_AP)) { | 2460 | (vif->type == NL80211_IFTYPE_AP) || |
| 2461 | (vif->type == NL80211_IFTYPE_MESH_POINT)) { | ||
| 2455 | if ((conf->changed & IEEE80211_IFCC_BEACON) || | 2462 | if ((conf->changed & IEEE80211_IFCC_BEACON) || |
| 2456 | (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && | 2463 | (conf->changed & IEEE80211_IFCC_BEACON_ENABLED && |
| 2457 | conf->enable_beacon)) { | 2464 | conf->enable_beacon)) { |
| @@ -2723,7 +2730,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
| 2723 | 2730 | ||
| 2724 | ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); | 2731 | ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); |
| 2725 | break; | 2732 | break; |
| 2726 | case IEEE80211_AMPDU_TX_RESUME: | 2733 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
| 2727 | ath_tx_aggr_resume(sc, sta, tid); | 2734 | ath_tx_aggr_resume(sc, sta, tid); |
| 2728 | break; | 2735 | break; |
| 2729 | default: | 2736 | default: |
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c index 9a58baabb9ca..6dbc58580abb 100644 --- a/drivers/net/wireless/ath9k/pci.c +++ b/drivers/net/wireless/ath9k/pci.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -87,7 +87,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 87 | struct ath_softc *sc; | 87 | struct ath_softc *sc; |
| 88 | struct ieee80211_hw *hw; | 88 | struct ieee80211_hw *hw; |
| 89 | u8 csz; | 89 | u8 csz; |
| 90 | u32 val; | ||
| 91 | int ret = 0; | 90 | int ret = 0; |
| 92 | struct ath_hw *ah; | 91 | struct ath_hw *ah; |
| 93 | 92 | ||
| @@ -134,14 +133,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 134 | 133 | ||
| 135 | pci_set_master(pdev); | 134 | pci_set_master(pdev); |
| 136 | 135 | ||
| 137 | /* | ||
| 138 | * Disable the RETRY_TIMEOUT register (0x41) to keep | ||
| 139 | * PCI Tx retries from interfering with C3 CPU state. | ||
| 140 | */ | ||
| 141 | pci_read_config_dword(pdev, 0x40, &val); | ||
| 142 | if ((val & 0x0000ff00) != 0) | ||
| 143 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
| 144 | |||
| 145 | ret = pci_request_region(pdev, 0, "ath9k"); | 136 | ret = pci_request_region(pdev, 0, "ath9k"); |
| 146 | if (ret) { | 137 | if (ret) { |
| 147 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); | 138 | dev_err(&pdev->dev, "PCI memory region reserve error\n"); |
| @@ -253,21 +244,12 @@ static int ath_pci_resume(struct pci_dev *pdev) | |||
| 253 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); | 244 | struct ieee80211_hw *hw = pci_get_drvdata(pdev); |
| 254 | struct ath_wiphy *aphy = hw->priv; | 245 | struct ath_wiphy *aphy = hw->priv; |
| 255 | struct ath_softc *sc = aphy->sc; | 246 | struct ath_softc *sc = aphy->sc; |
| 256 | u32 val; | ||
| 257 | int err; | 247 | int err; |
| 258 | 248 | ||
| 259 | err = pci_enable_device(pdev); | 249 | err = pci_enable_device(pdev); |
| 260 | if (err) | 250 | if (err) |
| 261 | return err; | 251 | return err; |
| 262 | pci_restore_state(pdev); | 252 | pci_restore_state(pdev); |
| 263 | /* | ||
| 264 | * Suspend/Resume resets the PCI configuration space, so we have to | ||
| 265 | * re-disable the RETRY_TIMEOUT register (0x41) to keep | ||
| 266 | * PCI Tx retries from interfering with C3 CPU state | ||
| 267 | */ | ||
| 268 | pci_read_config_dword(pdev, 0x40, &val); | ||
| 269 | if ((val & 0x0000ff00) != 0) | ||
| 270 | pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); | ||
| 271 | 253 | ||
| 272 | /* Enable LED */ | 254 | /* Enable LED */ |
| 273 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, | 255 | ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, |
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index e1494bae0f9f..8bcba906929a 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 1eac8c707342..0f7f8e0c9c95 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 832735677a46..824ccbb8b7b8 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004 Video54 Technologies, Inc. | 2 | * Copyright (c) 2004 Video54 Technologies, Inc. |
| 3 | * Copyright (c) 2004-2008 Atheros Communications, Inc. | 3 | * Copyright (c) 2004-2009 Atheros Communications, Inc. |
| 4 | * | 4 | * |
| 5 | * Permission to use, copy, modify, and/or distribute this software for any | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
| 6 | * purpose with or without fee is hereby granted, provided that the above | 6 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -864,6 +864,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, | |||
| 864 | rate_table, nrix, 1, 0); | 864 | rate_table, nrix, 1, 0); |
| 865 | ath_rc_rate_set_series(rate_table, &rates[i++], txrc, | 865 | ath_rc_rate_set_series(rate_table, &rates[i++], txrc, |
| 866 | try_per_rate, nrix, 0); | 866 | try_per_rate, nrix, 0); |
| 867 | |||
| 868 | tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; | ||
| 867 | } else { | 869 | } else { |
| 868 | try_per_rate = (ATH_11N_TXMAXTRY/4); | 870 | try_per_rate = (ATH_11N_TXMAXTRY/4); |
| 869 | /* Set the choosen rate. No RTS for first series entry. */ | 871 | /* Set the choosen rate. No RTS for first series entry. */ |
| @@ -1468,16 +1470,18 @@ static void ath_rc_init(struct ath_softc *sc, | |||
| 1468 | ath_rc_priv->ht_cap); | 1470 | ath_rc_priv->ht_cap); |
| 1469 | } | 1471 | } |
| 1470 | 1472 | ||
| 1471 | static u8 ath_rc_build_ht_caps(struct ath_softc *sc, bool is_ht, bool is_cw40, | 1473 | static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta, |
| 1472 | bool is_sgi40) | 1474 | bool is_cw40, bool is_sgi40) |
| 1473 | { | 1475 | { |
| 1474 | u8 caps = 0; | 1476 | u8 caps = 0; |
| 1475 | 1477 | ||
| 1476 | if (is_ht) { | 1478 | if (sta->ht_cap.ht_supported) { |
| 1477 | caps = WLAN_RC_HT_FLAG; | 1479 | caps = WLAN_RC_HT_FLAG; |
| 1478 | if (sc->sc_ah->caps.tx_chainmask != 1 && | 1480 | if (sc->sc_ah->caps.tx_chainmask != 1 && |
| 1479 | ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) | 1481 | ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) { |
| 1480 | caps |= WLAN_RC_DS_FLAG; | 1482 | if (sta->ht_cap.mcs.rx_mask[1]) |
| 1483 | caps |= WLAN_RC_DS_FLAG; | ||
| 1484 | } | ||
| 1481 | if (is_cw40) | 1485 | if (is_cw40) |
| 1482 | caps |= WLAN_RC_40_FLAG; | 1486 | caps |= WLAN_RC_40_FLAG; |
| 1483 | if (is_sgi40) | 1487 | if (is_sgi40) |
| @@ -1615,6 +1619,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
| 1615 | /* Choose rate table first */ | 1619 | /* Choose rate table first */ |
| 1616 | 1620 | ||
| 1617 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || | 1621 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || |
| 1622 | (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) || | ||
| 1618 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { | 1623 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { |
| 1619 | rate_table = ath_choose_rate_table(sc, sband->band, | 1624 | rate_table = ath_choose_rate_table(sc, sband->band, |
| 1620 | sta->ht_cap.ht_supported, | 1625 | sta->ht_cap.ht_supported, |
| @@ -1624,8 +1629,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
| 1624 | rate_table = sc->cur_rate_table; | 1629 | rate_table = sc->cur_rate_table; |
| 1625 | } | 1630 | } |
| 1626 | 1631 | ||
| 1627 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta->ht_cap.ht_supported, | 1632 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40); |
| 1628 | is_cw40, is_sgi40); | ||
| 1629 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | 1633 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); |
| 1630 | } | 1634 | } |
| 1631 | 1635 | ||
| @@ -1659,8 +1663,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, | |||
| 1659 | rate_table = ath_choose_rate_table(sc, sband->band, | 1663 | rate_table = ath_choose_rate_table(sc, sband->band, |
| 1660 | sta->ht_cap.ht_supported, | 1664 | sta->ht_cap.ht_supported, |
| 1661 | oper_cw40); | 1665 | oper_cw40); |
| 1662 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, | 1666 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, |
| 1663 | sta->ht_cap.ht_supported, | ||
| 1664 | oper_cw40, oper_sgi40); | 1667 | oper_cw40, oper_sgi40); |
| 1665 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | 1668 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); |
| 1666 | 1669 | ||
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index db9b0b9a3431..199a3ce57d64 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2004 Sam Leffler, Errno Consulting | 2 | * Copyright (c) 2004 Sam Leffler, Errno Consulting |
| 3 | * Copyright (c) 2004 Video54 Technologies, Inc. | 3 | * Copyright (c) 2004 Video54 Technologies, Inc. |
| 4 | * Copyright (c) 2008 Atheros Communications Inc. | 4 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 5 | * | 5 | * |
| 6 | * Permission to use, copy, modify, and/or distribute this software for any | 6 | * Permission to use, copy, modify, and/or distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above | 7 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 0bba17662a1f..71cb18d6757d 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -344,8 +344,13 @@ void ath_rx_cleanup(struct ath_softc *sc) | |||
| 344 | 344 | ||
| 345 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { | 345 | list_for_each_entry(bf, &sc->rx.rxbuf, list) { |
| 346 | skb = bf->bf_mpdu; | 346 | skb = bf->bf_mpdu; |
| 347 | if (skb) | 347 | if (skb) { |
| 348 | dma_unmap_single(sc->dev, | ||
| 349 | bf->bf_buf_addr, | ||
| 350 | sc->rx.bufsize, | ||
| 351 | DMA_FROM_DEVICE); | ||
| 348 | dev_kfree_skb(skb); | 352 | dev_kfree_skb(skb); |
| 353 | } | ||
| 349 | } | 354 | } |
| 350 | 355 | ||
| 351 | if (sc->rx.rxdma.dd_desc_len != 0) | 356 | if (sc->rx.rxdma.dd_desc_len != 0) |
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index d86e90e38173..52605246679f 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index b8f9b6d6bec4..4ca625102291 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 8f885f3bc8df..9f5fbd4eea7a 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath9k/regd_common.h index b41d0002f3fe..4d0e298cd1c7 100644 --- a/drivers/net/wireless/ath9k/regd_common.h +++ b/drivers/net/wireless/ath9k/regd_common.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index e3f376611f85..689bdbf78808 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2008 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
| 3 | * | 3 | * |
| 4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
| 5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
| @@ -64,6 +64,10 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | |||
| 64 | static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, | 64 | static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, |
| 65 | struct list_head *head); | 65 | struct list_head *head); |
| 66 | static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); | 66 | static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf); |
| 67 | static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, | ||
| 68 | int txok); | ||
| 69 | static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, | ||
| 70 | int nbad, int txok, bool update_rc); | ||
| 67 | 71 | ||
| 68 | /*********************/ | 72 | /*********************/ |
| 69 | /* Aggregation logic */ | 73 | /* Aggregation logic */ |
| @@ -274,9 +278,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 274 | struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; | 278 | struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; |
| 275 | struct ath_desc *ds = bf_last->bf_desc; | 279 | struct ath_desc *ds = bf_last->bf_desc; |
| 276 | struct list_head bf_head, bf_pending; | 280 | struct list_head bf_head, bf_pending; |
| 277 | u16 seq_st = 0; | 281 | u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; |
| 278 | u32 ba[WME_BA_BMP_SIZE >> 5]; | 282 | u32 ba[WME_BA_BMP_SIZE >> 5]; |
| 279 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0; | 283 | int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; |
| 284 | bool rc_update = true; | ||
| 280 | 285 | ||
| 281 | skb = (struct sk_buff *)bf->bf_mpdu; | 286 | skb = (struct sk_buff *)bf->bf_mpdu; |
| 282 | hdr = (struct ieee80211_hdr *)skb->data; | 287 | hdr = (struct ieee80211_hdr *)skb->data; |
| @@ -316,6 +321,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 316 | INIT_LIST_HEAD(&bf_pending); | 321 | INIT_LIST_HEAD(&bf_pending); |
| 317 | INIT_LIST_HEAD(&bf_head); | 322 | INIT_LIST_HEAD(&bf_head); |
| 318 | 323 | ||
| 324 | nbad = ath_tx_num_badfrms(sc, bf, txok); | ||
| 319 | while (bf) { | 325 | while (bf) { |
| 320 | txfail = txpending = 0; | 326 | txfail = txpending = 0; |
| 321 | bf_next = bf->bf_next; | 327 | bf_next = bf->bf_next; |
| @@ -323,8 +329,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 323 | if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { | 329 | if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) { |
| 324 | /* transmit completion, subframe is | 330 | /* transmit completion, subframe is |
| 325 | * acked by block ack */ | 331 | * acked by block ack */ |
| 332 | acked_cnt++; | ||
| 326 | } else if (!isaggr && txok) { | 333 | } else if (!isaggr && txok) { |
| 327 | /* transmit completion */ | 334 | /* transmit completion */ |
| 335 | acked_cnt++; | ||
| 328 | } else { | 336 | } else { |
| 329 | if (!(tid->state & AGGR_CLEANUP) && | 337 | if (!(tid->state & AGGR_CLEANUP) && |
| 330 | ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { | 338 | ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { |
| @@ -335,6 +343,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 335 | bf->bf_state.bf_type |= BUF_XRETRY; | 343 | bf->bf_state.bf_type |= BUF_XRETRY; |
| 336 | txfail = 1; | 344 | txfail = 1; |
| 337 | sendbar = 1; | 345 | sendbar = 1; |
| 346 | txfail_cnt++; | ||
| 338 | } | 347 | } |
| 339 | } else { | 348 | } else { |
| 340 | /* | 349 | /* |
| @@ -361,6 +370,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, | |||
| 361 | ath_tx_update_baw(sc, tid, bf->bf_seqno); | 370 | ath_tx_update_baw(sc, tid, bf->bf_seqno); |
| 362 | spin_unlock_bh(&txq->axq_lock); | 371 | spin_unlock_bh(&txq->axq_lock); |
| 363 | 372 | ||
| 373 | if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { | ||
| 374 | ath_tx_rc_status(bf, ds, nbad, txok, true); | ||
| 375 | rc_update = false; | ||
| 376 | } else { | ||
| 377 | ath_tx_rc_status(bf, ds, nbad, txok, false); | ||
| 378 | } | ||
| 379 | |||
| 364 | ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); | 380 | ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar); |
| 365 | } else { | 381 | } else { |
| 366 | /* retry the un-acked ones */ | 382 | /* retry the un-acked ones */ |
| @@ -1734,7 +1750,7 @@ exit: | |||
| 1734 | /*****************/ | 1750 | /*****************/ |
| 1735 | 1751 | ||
| 1736 | static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | 1752 | static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, |
| 1737 | struct ath_xmit_status *tx_status) | 1753 | int tx_flags) |
| 1738 | { | 1754 | { |
| 1739 | struct ieee80211_hw *hw = sc->hw; | 1755 | struct ieee80211_hw *hw = sc->hw; |
| 1740 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1756 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
| @@ -1755,18 +1771,14 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, | |||
| 1755 | tx_info->rate_driver_data[0] = NULL; | 1771 | tx_info->rate_driver_data[0] = NULL; |
| 1756 | } | 1772 | } |
| 1757 | 1773 | ||
| 1758 | if (tx_status->flags & ATH_TX_BAR) { | 1774 | if (tx_flags & ATH_TX_BAR) |
| 1759 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; | 1775 | tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; |
| 1760 | tx_status->flags &= ~ATH_TX_BAR; | ||
| 1761 | } | ||
| 1762 | 1776 | ||
| 1763 | if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { | 1777 | if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { |
| 1764 | /* Frame was ACKed */ | 1778 | /* Frame was ACKed */ |
| 1765 | tx_info->flags |= IEEE80211_TX_STAT_ACK; | 1779 | tx_info->flags |= IEEE80211_TX_STAT_ACK; |
| 1766 | } | 1780 | } |
| 1767 | 1781 | ||
| 1768 | tx_info->status.rates[0].count = tx_status->retries + 1; | ||
| 1769 | |||
| 1770 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); | 1782 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
| 1771 | padsize = hdrlen & 3; | 1783 | padsize = hdrlen & 3; |
| 1772 | if (padsize && hdrlen >= 24) { | 1784 | if (padsize && hdrlen >= 24) { |
| @@ -1789,29 +1801,22 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | |||
| 1789 | int txok, int sendbar) | 1801 | int txok, int sendbar) |
| 1790 | { | 1802 | { |
| 1791 | struct sk_buff *skb = bf->bf_mpdu; | 1803 | struct sk_buff *skb = bf->bf_mpdu; |
| 1792 | struct ath_xmit_status tx_status; | ||
| 1793 | unsigned long flags; | 1804 | unsigned long flags; |
| 1805 | int tx_flags = 0; | ||
| 1794 | 1806 | ||
| 1795 | /* | ||
| 1796 | * Set retry information. | ||
| 1797 | * NB: Don't use the information in the descriptor, because the frame | ||
| 1798 | * could be software retried. | ||
| 1799 | */ | ||
| 1800 | tx_status.retries = bf->bf_retries; | ||
| 1801 | tx_status.flags = 0; | ||
| 1802 | 1807 | ||
| 1803 | if (sendbar) | 1808 | if (sendbar) |
| 1804 | tx_status.flags = ATH_TX_BAR; | 1809 | tx_flags = ATH_TX_BAR; |
| 1805 | 1810 | ||
| 1806 | if (!txok) { | 1811 | if (!txok) { |
| 1807 | tx_status.flags |= ATH_TX_ERROR; | 1812 | tx_flags |= ATH_TX_ERROR; |
| 1808 | 1813 | ||
| 1809 | if (bf_isxretried(bf)) | 1814 | if (bf_isxretried(bf)) |
| 1810 | tx_status.flags |= ATH_TX_XRETRY; | 1815 | tx_flags |= ATH_TX_XRETRY; |
| 1811 | } | 1816 | } |
| 1812 | 1817 | ||
| 1813 | dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); | 1818 | dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE); |
| 1814 | ath_tx_complete(sc, skb, &tx_status); | 1819 | ath_tx_complete(sc, skb, tx_flags); |
| 1815 | 1820 | ||
| 1816 | /* | 1821 | /* |
| 1817 | * Return the list of ath_buf of this mpdu to free queue | 1822 | * Return the list of ath_buf of this mpdu to free queue |
| @@ -1852,27 +1857,40 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, | |||
| 1852 | return nbad; | 1857 | return nbad; |
| 1853 | } | 1858 | } |
| 1854 | 1859 | ||
| 1855 | static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) | 1860 | static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, |
| 1861 | int nbad, int txok, bool update_rc) | ||
| 1856 | { | 1862 | { |
| 1857 | struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; | 1863 | struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; |
| 1858 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 1864 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
| 1859 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1865 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
| 1860 | struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); | 1866 | struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); |
| 1867 | struct ieee80211_hw *hw = tx_info_priv->aphy->hw; | ||
| 1868 | u8 i, tx_rateindex; | ||
| 1869 | |||
| 1870 | if (txok) | ||
| 1871 | tx_info->status.ack_signal = ds->ds_txstat.ts_rssi; | ||
| 1861 | 1872 | ||
| 1862 | tx_info_priv->update_rc = false; | 1873 | tx_rateindex = ds->ds_txstat.ts_rateindex; |
| 1874 | WARN_ON(tx_rateindex >= hw->max_rates); | ||
| 1875 | |||
| 1876 | tx_info_priv->update_rc = update_rc; | ||
| 1863 | if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) | 1877 | if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) |
| 1864 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; | 1878 | tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; |
| 1865 | 1879 | ||
| 1866 | if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && | 1880 | if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && |
| 1867 | (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { | 1881 | (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { |
| 1868 | if (ieee80211_is_data(hdr->frame_control)) { | 1882 | if (ieee80211_is_data(hdr->frame_control)) { |
| 1869 | memcpy(&tx_info_priv->tx, &ds->ds_txstat, | 1883 | memcpy(&tx_info_priv->tx, &ds->ds_txstat, |
| 1870 | sizeof(tx_info_priv->tx)); | 1884 | sizeof(tx_info_priv->tx)); |
| 1871 | tx_info_priv->n_frames = bf->bf_nframes; | 1885 | tx_info_priv->n_frames = bf->bf_nframes; |
| 1872 | tx_info_priv->n_bad_frames = nbad; | 1886 | tx_info_priv->n_bad_frames = nbad; |
| 1873 | tx_info_priv->update_rc = true; | ||
| 1874 | } | 1887 | } |
| 1875 | } | 1888 | } |
| 1889 | |||
| 1890 | for (i = tx_rateindex + 1; i < hw->max_rates; i++) | ||
| 1891 | tx_info->status.rates[i].count = 0; | ||
| 1892 | |||
| 1893 | tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1; | ||
| 1876 | } | 1894 | } |
| 1877 | 1895 | ||
| 1878 | static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) | 1896 | static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) |
| @@ -1897,7 +1915,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1897 | struct ath_buf *bf, *lastbf, *bf_held = NULL; | 1915 | struct ath_buf *bf, *lastbf, *bf_held = NULL; |
| 1898 | struct list_head bf_head; | 1916 | struct list_head bf_head; |
| 1899 | struct ath_desc *ds; | 1917 | struct ath_desc *ds; |
| 1900 | int txok, nbad = 0; | 1918 | int txok; |
| 1901 | int status; | 1919 | int status; |
| 1902 | 1920 | ||
| 1903 | DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", | 1921 | DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", |
| @@ -1991,13 +2009,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | |||
| 1991 | bf->bf_retries = ds->ds_txstat.ts_longretry; | 2009 | bf->bf_retries = ds->ds_txstat.ts_longretry; |
| 1992 | if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) | 2010 | if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) |
| 1993 | bf->bf_state.bf_type |= BUF_XRETRY; | 2011 | bf->bf_state.bf_type |= BUF_XRETRY; |
| 1994 | nbad = 0; | 2012 | ath_tx_rc_status(bf, ds, 0, txok, true); |
| 1995 | } else { | ||
| 1996 | nbad = ath_tx_num_badfrms(sc, bf, txok); | ||
| 1997 | } | 2013 | } |
| 1998 | 2014 | ||
| 1999 | ath_tx_rc_status(bf, ds, nbad); | ||
| 2000 | |||
| 2001 | if (bf_isampdu(bf)) | 2015 | if (bf_isampdu(bf)) |
| 2002 | ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); | 2016 | ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok); |
| 2003 | else | 2017 | else |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b72ef3fd315a..4896e0831114 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
| @@ -3993,6 +3993,8 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev) | |||
| 3993 | dev->irq_reason = 0; | 3993 | dev->irq_reason = 0; |
| 3994 | memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); | 3994 | memset(dev->dma_reason, 0, sizeof(dev->dma_reason)); |
| 3995 | dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; | 3995 | dev->irq_savedstate = B43_IRQ_MASKTEMPLATE; |
| 3996 | if (b43_modparam_verbose < B43_VERBOSITY_DEBUG) | ||
| 3997 | dev->irq_savedstate &= ~B43_IRQ_PHY_TXERR; | ||
| 3996 | 3998 | ||
| 3997 | dev->mac_suspended = 1; | 3999 | dev->mac_suspended = 1; |
| 3998 | 4000 | ||
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 0f53c7e5e01e..a63d88841df8 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c | |||
| @@ -50,7 +50,7 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /* Extract the bitrate index out of an OFDM PLCP header. */ | 52 | /* Extract the bitrate index out of an OFDM PLCP header. */ |
| 53 | static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) | 53 | static int b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) |
| 54 | { | 54 | { |
| 55 | int base = aphy ? 0 : 4; | 55 | int base = aphy ? 0 : 4; |
| 56 | 56 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 205603d082aa..73f93a0ff2df 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h | |||
| @@ -233,7 +233,7 @@ struct iwl3945_eeprom { | |||
| 233 | #define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ | 233 | #define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ |
| 234 | 234 | ||
| 235 | #define TFD_QUEUE_MIN 0 | 235 | #define TFD_QUEUE_MIN 0 |
| 236 | #define TFD_QUEUE_MAX 6 | 236 | #define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */ |
| 237 | 237 | ||
| 238 | #define IWL_NUM_SCAN_RATES (2) | 238 | #define IWL_NUM_SCAN_RATES (2) |
| 239 | 239 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index f65c308a6714..af6b9d444778 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c | |||
| @@ -124,7 +124,7 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { | |||
| 124 | #define IWL39_RATE_HIGH_TH 11520 | 124 | #define IWL39_RATE_HIGH_TH 11520 |
| 125 | #define IWL_SUCCESS_UP_TH 8960 | 125 | #define IWL_SUCCESS_UP_TH 8960 |
| 126 | #define IWL_SUCCESS_DOWN_TH 10880 | 126 | #define IWL_SUCCESS_DOWN_TH 10880 |
| 127 | #define IWL_RATE_MIN_FAILURE_TH 8 | 127 | #define IWL_RATE_MIN_FAILURE_TH 6 |
| 128 | #define IWL_RATE_MIN_SUCCESS_TH 8 | 128 | #define IWL_RATE_MIN_SUCCESS_TH 8 |
| 129 | #define IWL_RATE_DECREASE_TH 1920 | 129 | #define IWL_RATE_DECREASE_TH 1920 |
| 130 | #define IWL_RATE_RETRY_TH 15 | 130 | #define IWL_RATE_RETRY_TH 15 |
| @@ -488,7 +488,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband | |||
| 488 | 488 | ||
| 489 | IWL_DEBUG_RATE(priv, "enter\n"); | 489 | IWL_DEBUG_RATE(priv, "enter\n"); |
| 490 | 490 | ||
| 491 | retries = info->status.rates[0].count - 1; | 491 | retries = info->status.rates[0].count; |
| 492 | /* Sanity Check for retries */ | 492 | /* Sanity Check for retries */ |
| 493 | if (retries > IWL_RATE_RETRY_TH) | 493 | if (retries > IWL_RATE_RETRY_TH) |
| 494 | retries = IWL_RATE_RETRY_TH; | 494 | retries = IWL_RATE_RETRY_TH; |
| @@ -791,16 +791,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
| 791 | if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { | 791 | if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) { |
| 792 | IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n"); | 792 | IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n"); |
| 793 | scale_action = -1; | 793 | scale_action = -1; |
| 794 | |||
| 795 | /* No throughput measured yet for adjacent rates, | 794 | /* No throughput measured yet for adjacent rates, |
| 796 | * try increase */ | 795 | * try increase */ |
| 797 | } else if ((low_tpt == IWL_INVALID_VALUE) && | 796 | } else if ((low_tpt == IWL_INVALID_VALUE) && |
| 798 | (high_tpt == IWL_INVALID_VALUE)) { | 797 | (high_tpt == IWL_INVALID_VALUE)) { |
| 799 | 798 | ||
| 800 | if (high != IWL_RATE_INVALID && window->success_counter >= IWL_RATE_INCREASE_TH) | 799 | if (high != IWL_RATE_INVALID && window->success_ratio >= IWL_RATE_INCREASE_TH) |
| 801 | scale_action = 1; | 800 | scale_action = 1; |
| 802 | else if (low != IWL_RATE_INVALID) | 801 | else if (low != IWL_RATE_INVALID) |
| 803 | scale_action = -1; | 802 | scale_action = 0; |
| 804 | 803 | ||
| 805 | /* Both adjacent throughputs are measured, but neither one has | 804 | /* Both adjacent throughputs are measured, but neither one has |
| 806 | * better throughput; we're using the best rate, don't change | 805 | * better throughput; we're using the best rate, don't change |
| @@ -826,14 +825,14 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, | |||
| 826 | else { | 825 | else { |
| 827 | IWL_DEBUG_RATE(priv, | 826 | IWL_DEBUG_RATE(priv, |
| 828 | "decrease rate because of high tpt\n"); | 827 | "decrease rate because of high tpt\n"); |
| 829 | scale_action = -1; | 828 | scale_action = 0; |
| 830 | } | 829 | } |
| 831 | } else if (low_tpt != IWL_INVALID_VALUE) { | 830 | } else if (low_tpt != IWL_INVALID_VALUE) { |
| 832 | if (low_tpt > current_tpt) { | 831 | if (low_tpt > current_tpt) { |
| 833 | IWL_DEBUG_RATE(priv, | 832 | IWL_DEBUG_RATE(priv, |
| 834 | "decrease rate because of low tpt\n"); | 833 | "decrease rate because of low tpt\n"); |
| 835 | scale_action = -1; | 834 | scale_action = -1; |
| 836 | } else if (window->success_counter >= IWL_RATE_INCREASE_TH) { | 835 | } else if (window->success_ratio >= IWL_RATE_INCREASE_TH) { |
| 837 | /* Lower rate has better | 836 | /* Lower rate has better |
| 838 | * throughput,decrease rate */ | 837 | * throughput,decrease rate */ |
| 839 | scale_action = 1; | 838 | scale_action = 1; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index ba7e720e73c1..2399328e8de7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
| @@ -293,7 +293,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv, | |||
| 293 | if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && | 293 | if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && |
| 294 | (txq_id != IWL_CMD_QUEUE_NUM) && | 294 | (txq_id != IWL_CMD_QUEUE_NUM) && |
| 295 | priv->mac80211_registered) | 295 | priv->mac80211_registered) |
| 296 | ieee80211_wake_queue(priv->hw, txq_id); | 296 | iwl_wake_queue(priv, txq_id); |
| 297 | } | 297 | } |
| 298 | 298 | ||
| 299 | /** | 299 | /** |
| @@ -747,11 +747,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
| 747 | int i; | 747 | int i; |
| 748 | int counter; | 748 | int counter; |
| 749 | 749 | ||
| 750 | /* classify bd */ | ||
| 751 | if (txq->q.id == IWL_CMD_QUEUE_NUM) | ||
| 752 | /* nothing to cleanup after for host commands */ | ||
| 753 | return; | ||
| 754 | |||
| 755 | /* sanity check */ | 750 | /* sanity check */ |
| 756 | counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); | 751 | counter = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); |
| 757 | if (counter > NUM_TFD_CHUNKS) { | 752 | if (counter > NUM_TFD_CHUNKS) { |
| @@ -1046,7 +1041,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) | |||
| 1046 | goto error; | 1041 | goto error; |
| 1047 | 1042 | ||
| 1048 | /* Tx queue(s) */ | 1043 | /* Tx queue(s) */ |
| 1049 | for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) { | 1044 | for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { |
| 1050 | slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? | 1045 | slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? |
| 1051 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; | 1046 | TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; |
| 1052 | rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, | 1047 | rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, |
| @@ -1184,7 +1179,7 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv) | |||
| 1184 | IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); | 1179 | IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id); |
| 1185 | 1180 | ||
| 1186 | rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); | 1181 | rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN); |
| 1187 | if(rc) | 1182 | if (rc) |
| 1188 | return rc; | 1183 | return rc; |
| 1189 | 1184 | ||
| 1190 | priv->cfg->ops->lib->apm_ops.config(priv); | 1185 | priv->cfg->ops->lib->apm_ops.config(priv); |
| @@ -1239,8 +1234,12 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv) | |||
| 1239 | int txq_id; | 1234 | int txq_id; |
| 1240 | 1235 | ||
| 1241 | /* Tx queues */ | 1236 | /* Tx queues */ |
| 1242 | for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) | 1237 | for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) |
| 1243 | iwl_tx_queue_free(priv, txq_id); | 1238 | if (txq_id == IWL_CMD_QUEUE_NUM) |
| 1239 | iwl_cmd_queue_free(priv); | ||
| 1240 | else | ||
| 1241 | iwl_tx_queue_free(priv, txq_id); | ||
| 1242 | |||
| 1244 | } | 1243 | } |
| 1245 | 1244 | ||
| 1246 | void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) | 1245 | void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) |
| @@ -1259,7 +1258,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv) | |||
| 1259 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); | 1258 | iwl_write_prph(priv, ALM_SCD_MODE_REG, 0); |
| 1260 | 1259 | ||
| 1261 | /* reset TFD queues */ | 1260 | /* reset TFD queues */ |
| 1262 | for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) { | 1261 | for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) { |
| 1263 | iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); | 1262 | iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0); |
| 1264 | iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, | 1263 | iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS, |
| 1265 | FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), | 1264 | FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id), |
| @@ -2488,6 +2487,9 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv) | |||
| 2488 | return -ENOMEM; | 2487 | return -ENOMEM; |
| 2489 | } | 2488 | } |
| 2490 | 2489 | ||
| 2490 | /* Assign number of Usable TX queues */ | ||
| 2491 | priv->hw_params.max_txq_num = TFD_QUEUE_MAX; | ||
| 2492 | |||
| 2491 | priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); | 2493 | priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd); |
| 2492 | priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; | 2494 | priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K; |
| 2493 | priv->hw_params.max_pkt_size = 2342; | 2495 | priv->hw_params.max_pkt_size = 2342; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index bd0140be774e..847a6220c5e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
| @@ -2178,10 +2178,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, | |||
| 2178 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && | 2178 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && |
| 2179 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { | 2179 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { |
| 2180 | if (agg->state == IWL_AGG_OFF) | 2180 | if (agg->state == IWL_AGG_OFF) |
| 2181 | ieee80211_wake_queue(priv->hw, txq_id); | 2181 | iwl_wake_queue(priv, txq_id); |
| 2182 | else | 2182 | else |
| 2183 | ieee80211_wake_queue(priv->hw, | 2183 | iwl_wake_queue(priv, txq->swq_id); |
| 2184 | txq->swq_id); | ||
| 2185 | } | 2184 | } |
| 2186 | } | 2185 | } |
| 2187 | } else { | 2186 | } else { |
| @@ -2205,7 +2204,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, | |||
| 2205 | 2204 | ||
| 2206 | if (priv->mac80211_registered && | 2205 | if (priv->mac80211_registered && |
| 2207 | (iwl_queue_space(&txq->q) > txq->q.low_mark)) | 2206 | (iwl_queue_space(&txq->q) > txq->q.low_mark)) |
| 2208 | ieee80211_wake_queue(priv->hw, txq_id); | 2207 | iwl_wake_queue(priv, txq_id); |
| 2209 | } | 2208 | } |
| 2210 | 2209 | ||
| 2211 | if (qc && likely(sta_id != IWL_INVALID_STATION)) | 2210 | if (qc && likely(sta_id != IWL_INVALID_STATION)) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 08c19bea71e3..e5ca2511a81a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
| @@ -1077,7 +1077,7 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, | |||
| 1077 | 1077 | ||
| 1078 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || | 1078 | if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) || |
| 1079 | (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { | 1079 | (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) { |
| 1080 | IWL_WARN(priv, | 1080 | IWL_ERR(priv, |
| 1081 | "queue number out of range: %d, must be %d to %d\n", | 1081 | "queue number out of range: %d, must be %d to %d\n", |
| 1082 | txq_id, IWL50_FIRST_AMPDU_QUEUE, | 1082 | txq_id, IWL50_FIRST_AMPDU_QUEUE, |
| 1083 | IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); | 1083 | IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1); |
| @@ -1295,10 +1295,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, | |||
| 1295 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && | 1295 | (iwl_queue_space(&txq->q) > txq->q.low_mark) && |
| 1296 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { | 1296 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { |
| 1297 | if (agg->state == IWL_AGG_OFF) | 1297 | if (agg->state == IWL_AGG_OFF) |
| 1298 | ieee80211_wake_queue(priv->hw, txq_id); | 1298 | iwl_wake_queue(priv, txq_id); |
| 1299 | else | 1299 | else |
| 1300 | ieee80211_wake_queue(priv->hw, | 1300 | iwl_wake_queue(priv, txq->swq_id); |
| 1301 | txq->swq_id); | ||
| 1302 | } | 1301 | } |
| 1303 | } | 1302 | } |
| 1304 | } else { | 1303 | } else { |
| @@ -1324,7 +1323,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, | |||
| 1324 | 1323 | ||
| 1325 | if (priv->mac80211_registered && | 1324 | if (priv->mac80211_registered && |
| 1326 | (iwl_queue_space(&txq->q) > txq->q.low_mark)) | 1325 | (iwl_queue_space(&txq->q) > txq->q.low_mark)) |
| 1327 | ieee80211_wake_queue(priv->hw, txq_id); | 1326 | iwl_wake_queue(priv, txq_id); |
| 1328 | } | 1327 | } |
| 1329 | 1328 | ||
| 1330 | if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) | 1329 | if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0db3bc011ac2..663dc83be501 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
| @@ -1567,9 +1567,8 @@ static void iwl_alive_start(struct iwl_priv *priv) | |||
| 1567 | if (iwl_is_associated(priv)) { | 1567 | if (iwl_is_associated(priv)) { |
| 1568 | struct iwl_rxon_cmd *active_rxon = | 1568 | struct iwl_rxon_cmd *active_rxon = |
| 1569 | (struct iwl_rxon_cmd *)&priv->active_rxon; | 1569 | (struct iwl_rxon_cmd *)&priv->active_rxon; |
| 1570 | 1570 | /* apply any changes in staging */ | |
| 1571 | memcpy(&priv->staging_rxon, &priv->active_rxon, | 1571 | priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; |
| 1572 | sizeof(priv->staging_rxon)); | ||
| 1573 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; | 1572 | active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; |
| 1574 | } else { | 1573 | } else { |
| 1575 | /* Initialize our rx_config data */ | 1574 | /* Initialize our rx_config data */ |
| @@ -2184,110 +2183,112 @@ static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
| 2184 | struct iwl_priv *priv = hw->priv; | 2183 | struct iwl_priv *priv = hw->priv; |
| 2185 | const struct iwl_channel_info *ch_info; | 2184 | const struct iwl_channel_info *ch_info; |
| 2186 | struct ieee80211_conf *conf = &hw->conf; | 2185 | struct ieee80211_conf *conf = &hw->conf; |
| 2187 | unsigned long flags; | 2186 | unsigned long flags = 0; |
| 2188 | int ret = 0; | 2187 | int ret = 0; |
| 2189 | u16 channel; | 2188 | u16 ch; |
| 2189 | int scan_active = 0; | ||
| 2190 | 2190 | ||
| 2191 | mutex_lock(&priv->mutex); | 2191 | mutex_lock(&priv->mutex); |
| 2192 | IWL_DEBUG_MAC80211(priv, "enter to channel %d\n", conf->channel->hw_value); | 2192 | IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", |
| 2193 | conf->channel->hw_value, changed); | ||
| 2193 | 2194 | ||
| 2194 | priv->current_ht_config.is_ht = conf_is_ht(conf); | 2195 | if (unlikely(!priv->cfg->mod_params->disable_hw_scan && |
| 2195 | 2196 | test_bit(STATUS_SCANNING, &priv->status))) { | |
| 2196 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { | 2197 | scan_active = 1; |
| 2197 | IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - waiting for uCode\n"); | 2198 | IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); |
| 2198 | goto out; | ||
| 2199 | } | 2199 | } |
| 2200 | 2200 | ||
| 2201 | if (!conf->radio_enabled) | ||
| 2202 | iwl_radio_kill_sw_disable_radio(priv); | ||
| 2203 | 2201 | ||
| 2204 | if (!iwl_is_ready(priv)) { | 2202 | /* during scanning mac80211 will delay channel setting until |
| 2205 | IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); | 2203 | * scan finish with changed = 0 |
| 2206 | ret = -EIO; | 2204 | */ |
| 2207 | goto out; | 2205 | if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { |
| 2208 | } | 2206 | if (scan_active) |
| 2207 | goto set_ch_out; | ||
| 2208 | |||
| 2209 | ch = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||
| 2210 | ch_info = iwl_get_channel_info(priv, conf->channel->band, ch); | ||
| 2211 | if (!is_channel_valid(ch_info)) { | ||
| 2212 | IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); | ||
| 2213 | ret = -EINVAL; | ||
| 2214 | goto set_ch_out; | ||
| 2215 | } | ||
| 2209 | 2216 | ||
| 2210 | if (unlikely(!priv->cfg->mod_params->disable_hw_scan && | 2217 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && |
| 2211 | test_bit(STATUS_SCANNING, &priv->status))) { | 2218 | !is_channel_ibss(ch_info)) { |
| 2212 | IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); | 2219 | IWL_ERR(priv, "channel %d in band %d not " |
| 2213 | mutex_unlock(&priv->mutex); | 2220 | "IBSS channel\n", |
| 2214 | return 0; | 2221 | conf->channel->hw_value, conf->channel->band); |
| 2215 | } | 2222 | ret = -EINVAL; |
| 2223 | goto set_ch_out; | ||
| 2224 | } | ||
| 2216 | 2225 | ||
| 2217 | channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | 2226 | priv->current_ht_config.is_ht = conf_is_ht(conf); |
| 2218 | ch_info = iwl_get_channel_info(priv, conf->channel->band, channel); | ||
| 2219 | if (!is_channel_valid(ch_info)) { | ||
| 2220 | IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); | ||
| 2221 | ret = -EINVAL; | ||
| 2222 | goto out; | ||
| 2223 | } | ||
| 2224 | 2227 | ||
| 2225 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC && | 2228 | spin_lock_irqsave(&priv->lock, flags); |
| 2226 | !is_channel_ibss(ch_info)) { | ||
| 2227 | IWL_ERR(priv, "channel %d in band %d not IBSS channel\n", | ||
| 2228 | conf->channel->hw_value, conf->channel->band); | ||
| 2229 | ret = -EINVAL; | ||
| 2230 | goto out; | ||
| 2231 | } | ||
| 2232 | 2229 | ||
| 2233 | spin_lock_irqsave(&priv->lock, flags); | ||
| 2234 | 2230 | ||
| 2231 | /* if we are switching from ht to 2.4 clear flags | ||
| 2232 | * from any ht related info since 2.4 does not | ||
| 2233 | * support ht */ | ||
| 2234 | if ((le16_to_cpu(priv->staging_rxon.channel) != ch)) | ||
| 2235 | priv->staging_rxon.flags = 0; | ||
| 2235 | 2236 | ||
| 2236 | /* if we are switching from ht to 2.4 clear flags | 2237 | iwl_set_rxon_channel(priv, conf->channel); |
| 2237 | * from any ht related info since 2.4 does not | ||
| 2238 | * support ht */ | ||
| 2239 | if ((le16_to_cpu(priv->staging_rxon.channel) != channel) | ||
| 2240 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH | ||
| 2241 | && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) | ||
| 2242 | #endif | ||
| 2243 | ) | ||
| 2244 | priv->staging_rxon.flags = 0; | ||
| 2245 | 2238 | ||
| 2246 | iwl_set_rxon_channel(priv, conf->channel); | 2239 | iwl_set_flags_for_band(priv, conf->channel->band); |
| 2240 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2241 | set_ch_out: | ||
| 2242 | /* The list of supported rates and rate mask can be different | ||
| 2243 | * for each band; since the band may have changed, reset | ||
| 2244 | * the rate mask to what mac80211 lists */ | ||
| 2245 | iwl_set_rate(priv); | ||
| 2246 | } | ||
| 2247 | 2247 | ||
| 2248 | iwl_set_flags_for_band(priv, conf->channel->band); | 2248 | if (changed & IEEE80211_CONF_CHANGE_PS) { |
| 2249 | if (conf->flags & IEEE80211_CONF_PS) | ||
| 2250 | ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); | ||
| 2251 | else | ||
| 2252 | ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); | ||
| 2253 | if (ret) | ||
| 2254 | IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); | ||
| 2249 | 2255 | ||
| 2250 | /* The list of supported rates and rate mask can be different | 2256 | } |
| 2251 | * for each band; since the band may have changed, reset | ||
| 2252 | * the rate mask to what mac80211 lists */ | ||
| 2253 | iwl_set_rate(priv); | ||
| 2254 | 2257 | ||
| 2255 | spin_unlock_irqrestore(&priv->lock, flags); | 2258 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |
| 2259 | IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", | ||
| 2260 | priv->tx_power_user_lmt, conf->power_level); | ||
| 2256 | 2261 | ||
| 2257 | #ifdef IEEE80211_CONF_CHANNEL_SWITCH | 2262 | iwl_set_tx_power(priv, conf->power_level, false); |
| 2258 | if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { | 2263 | } |
| 2259 | iwl_hw_channel_switch(priv, conf->channel); | 2264 | |
| 2260 | goto out; | 2265 | /* call to ensure that 4965 rx_chain is set properly in monitor mode */ |
| 2266 | iwl_set_rxon_chain(priv); | ||
| 2267 | |||
| 2268 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { | ||
| 2269 | if (conf->radio_enabled && | ||
| 2270 | iwl_radio_kill_sw_enable_radio(priv)) { | ||
| 2271 | IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " | ||
| 2272 | "waiting for uCode\n"); | ||
| 2273 | goto out; | ||
| 2274 | } | ||
| 2275 | |||
| 2276 | if (!conf->radio_enabled) | ||
| 2277 | iwl_radio_kill_sw_disable_radio(priv); | ||
| 2261 | } | 2278 | } |
| 2262 | #endif | ||
| 2263 | 2279 | ||
| 2264 | if (!conf->radio_enabled) { | 2280 | if (!conf->radio_enabled) { |
| 2265 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); | 2281 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); |
| 2266 | goto out; | 2282 | goto out; |
| 2267 | } | 2283 | } |
| 2268 | 2284 | ||
| 2269 | if (iwl_is_rfkill(priv)) { | 2285 | if (!iwl_is_ready(priv)) { |
| 2270 | IWL_DEBUG_MAC80211(priv, "leave - RF kill\n"); | 2286 | IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); |
| 2271 | ret = -EIO; | ||
| 2272 | goto out; | 2287 | goto out; |
| 2273 | } | 2288 | } |
| 2274 | 2289 | ||
| 2275 | if (conf->flags & IEEE80211_CONF_PS) | 2290 | if (scan_active) |
| 2276 | ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3); | 2291 | goto out; |
| 2277 | else | ||
| 2278 | ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM); | ||
| 2279 | if (ret) | ||
| 2280 | IWL_DEBUG_MAC80211(priv, "Error setting power level\n"); | ||
| 2281 | |||
| 2282 | IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", | ||
| 2283 | priv->tx_power_user_lmt, conf->power_level); | ||
| 2284 | |||
| 2285 | iwl_set_tx_power(priv, conf->power_level, false); | ||
| 2286 | |||
| 2287 | iwl_set_rate(priv); | ||
| 2288 | |||
| 2289 | /* call to ensure that 4965 rx_chain is set properly in monitor mode */ | ||
| 2290 | iwl_set_rxon_chain(priv); | ||
| 2291 | 2292 | ||
| 2292 | if (memcmp(&priv->active_rxon, | 2293 | if (memcmp(&priv->active_rxon, |
| 2293 | &priv->staging_rxon, sizeof(priv->staging_rxon))) | 2294 | &priv->staging_rxon, sizeof(priv->staging_rxon))) |
| @@ -2295,9 +2296,9 @@ static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
| 2295 | else | 2296 | else |
| 2296 | IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n"); | 2297 | IWL_DEBUG_INFO(priv, "No re-sending same RXON configuration.\n"); |
| 2297 | 2298 | ||
| 2298 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
| 2299 | 2299 | ||
| 2300 | out: | 2300 | out: |
| 2301 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
| 2301 | mutex_unlock(&priv->mutex); | 2302 | mutex_unlock(&priv->mutex); |
| 2302 | return ret; | 2303 | return ret; |
| 2303 | } | 2304 | } |
| @@ -2682,6 +2683,7 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
| 2682 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) | 2683 | struct ieee80211_sta *sta, u16 tid, u16 *ssn) |
| 2683 | { | 2684 | { |
| 2684 | struct iwl_priv *priv = hw->priv; | 2685 | struct iwl_priv *priv = hw->priv; |
| 2686 | int ret; | ||
| 2685 | 2687 | ||
| 2686 | IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", | 2688 | IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", |
| 2687 | sta->addr, tid); | 2689 | sta->addr, tid); |
| @@ -2695,13 +2697,21 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, | |||
| 2695 | return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); | 2697 | return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); |
| 2696 | case IEEE80211_AMPDU_RX_STOP: | 2698 | case IEEE80211_AMPDU_RX_STOP: |
| 2697 | IWL_DEBUG_HT(priv, "stop Rx\n"); | 2699 | IWL_DEBUG_HT(priv, "stop Rx\n"); |
| 2698 | return iwl_sta_rx_agg_stop(priv, sta->addr, tid); | 2700 | ret = iwl_sta_rx_agg_stop(priv, sta->addr, tid); |
| 2701 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
| 2702 | return 0; | ||
| 2703 | else | ||
| 2704 | return ret; | ||
| 2699 | case IEEE80211_AMPDU_TX_START: | 2705 | case IEEE80211_AMPDU_TX_START: |
| 2700 | IWL_DEBUG_HT(priv, "start Tx\n"); | 2706 | IWL_DEBUG_HT(priv, "start Tx\n"); |
| 2701 | return iwl_tx_agg_start(priv, sta->addr, tid, ssn); | 2707 | return iwl_tx_agg_start(priv, sta->addr, tid, ssn); |
| 2702 | case IEEE80211_AMPDU_TX_STOP: | 2708 | case IEEE80211_AMPDU_TX_STOP: |
| 2703 | IWL_DEBUG_HT(priv, "stop Tx\n"); | 2709 | IWL_DEBUG_HT(priv, "stop Tx\n"); |
| 2704 | return iwl_tx_agg_stop(priv, sta->addr, tid); | 2710 | ret = iwl_tx_agg_stop(priv, sta->addr, tid); |
| 2711 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
| 2712 | return 0; | ||
| 2713 | else | ||
| 2714 | return ret; | ||
| 2705 | default: | 2715 | default: |
| 2706 | IWL_DEBUG_HT(priv, "unknown\n"); | 2716 | IWL_DEBUG_HT(priv, "unknown\n"); |
| 2707 | return -EINVAL; | 2717 | return -EINVAL; |
| @@ -3083,11 +3093,6 @@ static ssize_t store_power_level(struct device *d, | |||
| 3083 | 3093 | ||
| 3084 | mutex_lock(&priv->mutex); | 3094 | mutex_lock(&priv->mutex); |
| 3085 | 3095 | ||
| 3086 | if (!iwl_is_ready(priv)) { | ||
| 3087 | ret = -EAGAIN; | ||
| 3088 | goto out; | ||
| 3089 | } | ||
| 3090 | |||
| 3091 | ret = strict_strtoul(buf, 10, &mode); | 3096 | ret = strict_strtoul(buf, 10, &mode); |
| 3092 | if (ret) | 3097 | if (ret) |
| 3093 | goto out; | 3098 | goto out; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 085e9cf1cac9..c54fb93e9d72 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
| @@ -1298,6 +1298,7 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
| 1298 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 1298 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
| 1299 | IEEE80211_HW_NOISE_DBM | | 1299 | IEEE80211_HW_NOISE_DBM | |
| 1300 | IEEE80211_HW_AMPDU_AGGREGATION | | 1300 | IEEE80211_HW_AMPDU_AGGREGATION | |
| 1301 | IEEE80211_HW_SPECTRUM_MGMT | | ||
| 1301 | IEEE80211_HW_SUPPORTS_PS; | 1302 | IEEE80211_HW_SUPPORTS_PS; |
| 1302 | hw->wiphy->interface_modes = | 1303 | hw->wiphy->interface_modes = |
| 1303 | BIT(NL80211_IFTYPE_STATION) | | 1304 | BIT(NL80211_IFTYPE_STATION) | |
| @@ -1308,9 +1309,6 @@ int iwl_setup_mac(struct iwl_priv *priv) | |||
| 1308 | 1309 | ||
| 1309 | /* Default value; 4 EDCA QOS priorities */ | 1310 | /* Default value; 4 EDCA QOS priorities */ |
| 1310 | hw->queues = 4; | 1311 | hw->queues = 4; |
| 1311 | /* queues to support 11n aggregation */ | ||
| 1312 | if (priv->cfg->sku & IWL_SKU_N) | ||
| 1313 | hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues; | ||
| 1314 | 1312 | ||
| 1315 | hw->conf.beacon_int = 100; | 1313 | hw->conf.beacon_int = 100; |
| 1316 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; | 1314 | hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL; |
| @@ -1437,6 +1435,10 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) | |||
| 1437 | 1435 | ||
| 1438 | priv->tx_power_user_lmt = tx_power; | 1436 | priv->tx_power_user_lmt = tx_power; |
| 1439 | 1437 | ||
| 1438 | /* if nic is not up don't send command */ | ||
| 1439 | if (!iwl_is_ready_rf(priv)) | ||
| 1440 | return ret; | ||
| 1441 | |||
| 1440 | if (force && priv->cfg->ops->lib->send_tx_power) | 1442 | if (force && priv->cfg->ops->lib->send_tx_power) |
| 1441 | ret = priv->cfg->ops->lib->send_tx_power(priv); | 1443 | ret = priv->cfg->ops->lib->send_tx_power(priv); |
| 1442 | 1444 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 27310fec2e43..a8eac8c3c1fa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
| @@ -264,6 +264,7 @@ void iwl_rx_reply_error(struct iwl_priv *priv, | |||
| 264 | * RX | 264 | * RX |
| 265 | ******************************************************/ | 265 | ******************************************************/ |
| 266 | void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 266 | void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
| 267 | void iwl_cmd_queue_free(struct iwl_priv *priv); | ||
| 267 | int iwl_rx_queue_alloc(struct iwl_priv *priv); | 268 | int iwl_rx_queue_alloc(struct iwl_priv *priv); |
| 268 | void iwl_rx_handle(struct iwl_priv *priv); | 269 | void iwl_rx_handle(struct iwl_priv *priv); |
| 269 | int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, | 270 | int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, |
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 36cfeccfafbc..64eb585f1578 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c | |||
| @@ -425,6 +425,56 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, | |||
| 425 | return ret; | 425 | return ret; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | static ssize_t iwl_dbgfs_status_read(struct file *file, | ||
| 429 | char __user *user_buf, | ||
| 430 | size_t count, loff_t *ppos) { | ||
| 431 | |||
| 432 | struct iwl_priv *priv = (struct iwl_priv *)file->private_data; | ||
| 433 | char buf[512]; | ||
| 434 | int pos = 0; | ||
| 435 | const size_t bufsz = sizeof(buf); | ||
| 436 | |||
| 437 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n", | ||
| 438 | test_bit(STATUS_HCMD_ACTIVE, &priv->status)); | ||
| 439 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_SYNC_ACTIVE: %d\n", | ||
| 440 | test_bit(STATUS_HCMD_SYNC_ACTIVE, &priv->status)); | ||
| 441 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n", | ||
| 442 | test_bit(STATUS_INT_ENABLED, &priv->status)); | ||
| 443 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", | ||
| 444 | test_bit(STATUS_RF_KILL_HW, &priv->status)); | ||
| 445 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_SW:\t %d\n", | ||
| 446 | test_bit(STATUS_RF_KILL_SW, &priv->status)); | ||
| 447 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", | ||
| 448 | test_bit(STATUS_INIT, &priv->status)); | ||
| 449 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", | ||
| 450 | test_bit(STATUS_ALIVE, &priv->status)); | ||
| 451 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n", | ||
| 452 | test_bit(STATUS_READY, &priv->status)); | ||
| 453 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n", | ||
| 454 | test_bit(STATUS_TEMPERATURE, &priv->status)); | ||
| 455 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n", | ||
| 456 | test_bit(STATUS_GEO_CONFIGURED, &priv->status)); | ||
| 457 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n", | ||
| 458 | test_bit(STATUS_EXIT_PENDING, &priv->status)); | ||
| 459 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_IN_SUSPEND:\t %d\n", | ||
| 460 | test_bit(STATUS_IN_SUSPEND, &priv->status)); | ||
| 461 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n", | ||
| 462 | test_bit(STATUS_STATISTICS, &priv->status)); | ||
| 463 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n", | ||
| 464 | test_bit(STATUS_SCANNING, &priv->status)); | ||
| 465 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n", | ||
| 466 | test_bit(STATUS_SCAN_ABORTING, &priv->status)); | ||
| 467 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n", | ||
| 468 | test_bit(STATUS_SCAN_HW, &priv->status)); | ||
| 469 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n", | ||
| 470 | test_bit(STATUS_POWER_PMI, &priv->status)); | ||
| 471 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n", | ||
| 472 | test_bit(STATUS_FW_ERROR, &priv->status)); | ||
| 473 | pos += scnprintf(buf + pos, bufsz - pos, "STATUS_MODE_PENDING:\t %d\n", | ||
| 474 | test_bit(STATUS_MODE_PENDING, &priv->status)); | ||
| 475 | return simple_read_from_buffer(user_buf, count, ppos, buf, pos); | ||
| 476 | } | ||
| 477 | |||
| 428 | DEBUGFS_READ_WRITE_FILE_OPS(sram); | 478 | DEBUGFS_READ_WRITE_FILE_OPS(sram); |
| 429 | DEBUGFS_WRITE_FILE_OPS(log_event); | 479 | DEBUGFS_WRITE_FILE_OPS(log_event); |
| 430 | DEBUGFS_READ_FILE_OPS(eeprom); | 480 | DEBUGFS_READ_FILE_OPS(eeprom); |
| @@ -432,6 +482,7 @@ DEBUGFS_READ_FILE_OPS(stations); | |||
| 432 | DEBUGFS_READ_FILE_OPS(rx_statistics); | 482 | DEBUGFS_READ_FILE_OPS(rx_statistics); |
| 433 | DEBUGFS_READ_FILE_OPS(tx_statistics); | 483 | DEBUGFS_READ_FILE_OPS(tx_statistics); |
| 434 | DEBUGFS_READ_FILE_OPS(channels); | 484 | DEBUGFS_READ_FILE_OPS(channels); |
| 485 | DEBUGFS_READ_FILE_OPS(status); | ||
| 435 | 486 | ||
| 436 | /* | 487 | /* |
| 437 | * Create the debugfs files and directories | 488 | * Create the debugfs files and directories |
| @@ -466,7 +517,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) | |||
| 466 | DEBUGFS_ADD_FILE(rx_statistics, data); | 517 | DEBUGFS_ADD_FILE(rx_statistics, data); |
| 467 | DEBUGFS_ADD_FILE(tx_statistics, data); | 518 | DEBUGFS_ADD_FILE(tx_statistics, data); |
| 468 | DEBUGFS_ADD_FILE(channels, data); | 519 | DEBUGFS_ADD_FILE(channels, data); |
| 469 | DEBUGFS_ADD_X32(status, data, (u32 *)&priv->status); | 520 | DEBUGFS_ADD_FILE(status, data); |
| 470 | DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); | 521 | DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); |
| 471 | DEBUGFS_ADD_BOOL(disable_chain_noise, rf, | 522 | DEBUGFS_ADD_BOOL(disable_chain_noise, rf, |
| 472 | &priv->disable_chain_noise_cal); | 523 | &priv->disable_chain_noise_cal); |
| @@ -496,6 +547,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) | |||
| 496 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); | 547 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); |
| 497 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); | 548 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); |
| 498 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); | 549 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); |
| 550 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status); | ||
| 499 | DEBUGFS_REMOVE(priv->dbgfs->dir_data); | 551 | DEBUGFS_REMOVE(priv->dbgfs->dir_data); |
| 500 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); | 552 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); |
| 501 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); | 553 | DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 0baae8022824..ec9a13846edd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
| @@ -996,6 +996,12 @@ struct iwl_priv { | |||
| 996 | u8 key_mapping_key; | 996 | u8 key_mapping_key; |
| 997 | unsigned long ucode_key_table; | 997 | unsigned long ucode_key_table; |
| 998 | 998 | ||
| 999 | /* queue refcounts */ | ||
| 1000 | #define IWL_MAX_HW_QUEUES 32 | ||
| 1001 | unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; | ||
| 1002 | /* for each AC */ | ||
| 1003 | atomic_t queue_stop_count[4]; | ||
| 1004 | |||
| 999 | /* Indication if ieee80211_ops->open has been called */ | 1005 | /* Indication if ieee80211_ops->open has been called */ |
| 1000 | u8 is_open; | 1006 | u8 is_open; |
| 1001 | 1007 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index fb64d297dd4e..a1328c3c81ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h | |||
| @@ -93,4 +93,56 @@ static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, | |||
| 93 | return (desc->v_addr != NULL) ? 0 : -ENOMEM; | 93 | return (desc->v_addr != NULL) ? 0 : -ENOMEM; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | /* | ||
| 97 | * we have 8 bits used like this: | ||
| 98 | * | ||
| 99 | * 7 6 5 4 3 2 1 0 | ||
| 100 | * | | | | | | | | | ||
| 101 | * | | | | | | +-+-------- AC queue (0-3) | ||
| 102 | * | | | | | | | ||
| 103 | * | +-+-+-+-+------------ HW A-MPDU queue | ||
| 104 | * | | ||
| 105 | * +---------------------- indicates agg queue | ||
| 106 | */ | ||
| 107 | static inline u8 iwl_virtual_agg_queue_num(u8 ac, u8 hwq) | ||
| 108 | { | ||
| 109 | BUG_ON(ac > 3); /* only have 2 bits */ | ||
| 110 | BUG_ON(hwq > 31); /* only have 5 bits */ | ||
| 111 | |||
| 112 | return 0x80 | (hwq << 2) | ac; | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline void iwl_wake_queue(struct iwl_priv *priv, u8 queue) | ||
| 116 | { | ||
| 117 | u8 ac = queue; | ||
| 118 | u8 hwq = queue; | ||
| 119 | |||
| 120 | if (queue & 0x80) { | ||
| 121 | ac = queue & 3; | ||
| 122 | hwq = (queue >> 2) & 0x1f; | ||
| 123 | } | ||
| 124 | |||
| 125 | if (test_and_clear_bit(hwq, priv->queue_stopped)) | ||
| 126 | if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0) | ||
| 127 | ieee80211_wake_queue(priv->hw, ac); | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue) | ||
| 131 | { | ||
| 132 | u8 ac = queue; | ||
| 133 | u8 hwq = queue; | ||
| 134 | |||
| 135 | if (queue & 0x80) { | ||
| 136 | ac = queue & 3; | ||
| 137 | hwq = (queue >> 2) & 0x1f; | ||
| 138 | } | ||
| 139 | |||
| 140 | if (!test_and_set_bit(hwq, priv->queue_stopped)) | ||
| 141 | if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0) | ||
| 142 | ieee80211_stop_queue(priv->hw, ac); | ||
| 143 | } | ||
| 144 | |||
| 145 | #define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue | ||
| 146 | #define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue | ||
| 147 | |||
| 96 | #endif /* __iwl_helpers_h__ */ | 148 | #endif /* __iwl_helpers_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 18b7e4195ea1..47c894530eb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c | |||
| @@ -273,7 +273,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) | |||
| 273 | if (priv->iw_mode != NL80211_IFTYPE_STATION) | 273 | if (priv->iw_mode != NL80211_IFTYPE_STATION) |
| 274 | final_mode = IWL_POWER_MODE_CAM; | 274 | final_mode = IWL_POWER_MODE_CAM; |
| 275 | 275 | ||
| 276 | if (!iwl_is_rfkill(priv) && !setting->power_disabled && | 276 | if (iwl_is_ready_rf(priv) && !setting->power_disabled && |
| 277 | ((setting->power_mode != final_mode) || force)) { | 277 | ((setting->power_mode != final_mode) || force)) { |
| 278 | struct iwl_powertable_cmd cmd; | 278 | struct iwl_powertable_cmd cmd; |
| 279 | 279 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 1684490d93c0..5798fe49c771 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c | |||
| @@ -1138,8 +1138,10 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) | |||
| 1138 | int sta_id; | 1138 | int sta_id; |
| 1139 | 1139 | ||
| 1140 | sta_id = iwl_find_station(priv, addr); | 1140 | sta_id = iwl_find_station(priv, addr); |
| 1141 | if (sta_id == IWL_INVALID_STATION) | 1141 | if (sta_id == IWL_INVALID_STATION) { |
| 1142 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | ||
| 1142 | return -ENXIO; | 1143 | return -ENXIO; |
| 1144 | } | ||
| 1143 | 1145 | ||
| 1144 | spin_lock_irqsave(&priv->sta_lock, flags); | 1146 | spin_lock_irqsave(&priv->sta_lock, flags); |
| 1145 | priv->stations[sta_id].sta.station_flags_msk = 0; | 1147 | priv->stations[sta_id].sta.station_flags_msk = 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index dff60fb70214..1f117a49c569 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
| @@ -174,7 +174,7 @@ EXPORT_SYMBOL(iwl_tx_queue_free); | |||
| 174 | * Free all buffers. | 174 | * Free all buffers. |
| 175 | * 0-fill, but do not free "txq" descriptor structure. | 175 | * 0-fill, but do not free "txq" descriptor structure. |
| 176 | */ | 176 | */ |
| 177 | static void iwl_cmd_queue_free(struct iwl_priv *priv) | 177 | void iwl_cmd_queue_free(struct iwl_priv *priv) |
| 178 | { | 178 | { |
| 179 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; | 179 | struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; |
| 180 | struct iwl_queue *q = &txq->q; | 180 | struct iwl_queue *q = &txq->q; |
| @@ -193,12 +193,14 @@ static void iwl_cmd_queue_free(struct iwl_priv *priv) | |||
| 193 | 193 | ||
| 194 | /* De-alloc circular buffer of TFDs */ | 194 | /* De-alloc circular buffer of TFDs */ |
| 195 | if (txq->q.n_bd) | 195 | if (txq->q.n_bd) |
| 196 | pci_free_consistent(dev, sizeof(struct iwl_tfd) * | 196 | pci_free_consistent(dev, priv->hw_params.tfd_size * |
| 197 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); | 197 | txq->q.n_bd, txq->tfds, txq->q.dma_addr); |
| 198 | 198 | ||
| 199 | /* 0-fill queue descriptor structure */ | 199 | /* 0-fill queue descriptor structure */ |
| 200 | memset(txq, 0, sizeof(*txq)); | 200 | memset(txq, 0, sizeof(*txq)); |
| 201 | } | 201 | } |
| 202 | EXPORT_SYMBOL(iwl_cmd_queue_free); | ||
| 203 | |||
| 202 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** | 204 | /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** |
| 203 | * DMA services | 205 | * DMA services |
| 204 | * | 206 | * |
| @@ -761,8 +763,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
| 761 | hdr->seq_ctrl |= cpu_to_le16(seq_number); | 763 | hdr->seq_ctrl |= cpu_to_le16(seq_number); |
| 762 | seq_number += 0x10; | 764 | seq_number += 0x10; |
| 763 | /* aggregation is on for this <sta,tid> */ | 765 | /* aggregation is on for this <sta,tid> */ |
| 764 | if (info->flags & IEEE80211_TX_CTL_AMPDU) | 766 | if (info->flags & IEEE80211_TX_CTL_AMPDU) { |
| 765 | txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; | 767 | txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; |
| 768 | swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id); | ||
| 769 | } | ||
| 766 | priv->stations[sta_id].tid[tid].tfds_in_queue++; | 770 | priv->stations[sta_id].tid[tid].tfds_in_queue++; |
| 767 | } | 771 | } |
| 768 | 772 | ||
| @@ -893,7 +897,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
| 893 | iwl_txq_update_write_ptr(priv, txq); | 897 | iwl_txq_update_write_ptr(priv, txq); |
| 894 | spin_unlock_irqrestore(&priv->lock, flags); | 898 | spin_unlock_irqrestore(&priv->lock, flags); |
| 895 | } else { | 899 | } else { |
| 896 | ieee80211_stop_queue(priv->hw, txq->swq_id); | 900 | iwl_stop_queue(priv, txq->swq_id); |
| 897 | } | 901 | } |
| 898 | } | 902 | } |
| 899 | 903 | ||
| @@ -1221,8 +1225,10 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) | |||
| 1221 | 1225 | ||
| 1222 | sta_id = iwl_find_station(priv, ra); | 1226 | sta_id = iwl_find_station(priv, ra); |
| 1223 | 1227 | ||
| 1224 | if (sta_id == IWL_INVALID_STATION) | 1228 | if (sta_id == IWL_INVALID_STATION) { |
| 1229 | IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid); | ||
| 1225 | return -ENXIO; | 1230 | return -ENXIO; |
| 1231 | } | ||
| 1226 | 1232 | ||
| 1227 | if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) | 1233 | if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) |
| 1228 | IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n"); | 1234 | IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n"); |
| @@ -1429,7 +1435,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
| 1429 | if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && | 1435 | if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && |
| 1430 | priv->mac80211_registered && | 1436 | priv->mac80211_registered && |
| 1431 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) | 1437 | (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) |
| 1432 | ieee80211_wake_queue(priv->hw, txq->swq_id); | 1438 | iwl_wake_queue(priv, txq->swq_id); |
| 1433 | 1439 | ||
| 1434 | iwl_txq_check_empty(priv, sta_id, tid, scd_flow); | 1440 | iwl_txq_check_empty(priv, sta_id, tid, scd_flow); |
| 1435 | } | 1441 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4465320f2735..a71b08ca7c71 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
| @@ -485,14 +485,14 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv, | |||
| 485 | memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, | 485 | memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key, |
| 486 | keyconf->keylen); | 486 | keyconf->keylen); |
| 487 | 487 | ||
| 488 | if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) | 488 | if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK) |
| 489 | == STA_KEY_FLG_NO_ENC) | 489 | == STA_KEY_FLG_NO_ENC) |
| 490 | priv->stations[sta_id].sta.key.key_offset = | 490 | priv->stations_39[sta_id].sta.key.key_offset = |
| 491 | iwl_get_free_ucode_key_index(priv); | 491 | iwl_get_free_ucode_key_index(priv); |
| 492 | /* else, we are overriding an existing key => no need to allocated room | 492 | /* else, we are overriding an existing key => no need to allocated room |
| 493 | * in uCode. */ | 493 | * in uCode. */ |
| 494 | 494 | ||
| 495 | WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, | 495 | WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET, |
| 496 | "no space for a new key"); | 496 | "no space for a new key"); |
| 497 | 497 | ||
| 498 | priv->stations_39[sta_id].sta.key.key_flags = key_flags; | 498 | priv->stations_39[sta_id].sta.key.key_flags = key_flags; |
| @@ -560,7 +560,7 @@ static int iwl3945_set_dynamic_key(struct iwl_priv *priv, | |||
| 560 | ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id); | 560 | ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id); |
| 561 | break; | 561 | break; |
| 562 | default: | 562 | default: |
| 563 | IWL_ERR(priv,"Unknown alg: %s alg = %d\n", __func__, keyconf->alg); | 563 | IWL_ERR(priv, "Unknown alg: %s alg = %d\n", __func__, keyconf->alg); |
| 564 | ret = -EINVAL; | 564 | ret = -EINVAL; |
| 565 | } | 565 | } |
| 566 | 566 | ||
| @@ -1168,7 +1168,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
| 1168 | spin_unlock_irqrestore(&priv->lock, flags); | 1168 | spin_unlock_irqrestore(&priv->lock, flags); |
| 1169 | } | 1169 | } |
| 1170 | 1170 | ||
| 1171 | ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb)); | 1171 | iwl_stop_queue(priv, skb_get_queue_mapping(skb)); |
| 1172 | } | 1172 | } |
| 1173 | 1173 | ||
| 1174 | return 0; | 1174 | return 0; |
| @@ -3773,15 +3773,19 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
| 3773 | } | 3773 | } |
| 3774 | #endif | 3774 | #endif |
| 3775 | 3775 | ||
| 3776 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { | 3776 | if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { |
| 3777 | IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - waiting for uCode\n"); | 3777 | if (conf->radio_enabled && |
| 3778 | goto out; | 3778 | iwl_radio_kill_sw_enable_radio(priv)) { |
| 3779 | } | 3779 | IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - " |
| 3780 | "waiting for uCode\n"); | ||
| 3781 | goto out; | ||
| 3782 | } | ||
| 3780 | 3783 | ||
| 3781 | if (!conf->radio_enabled) { | 3784 | if (!conf->radio_enabled) { |
| 3782 | iwl_radio_kill_sw_disable_radio(priv); | 3785 | iwl_radio_kill_sw_disable_radio(priv); |
| 3783 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); | 3786 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); |
| 3784 | goto out; | 3787 | goto out; |
| 3788 | } | ||
| 3785 | } | 3789 | } |
| 3786 | 3790 | ||
| 3787 | if (iwl_is_rfkill(priv)) { | 3791 | if (iwl_is_rfkill(priv)) { |
| @@ -4546,11 +4550,6 @@ static ssize_t store_power_level(struct device *d, | |||
| 4546 | 4550 | ||
| 4547 | mutex_lock(&priv->mutex); | 4551 | mutex_lock(&priv->mutex); |
| 4548 | 4552 | ||
| 4549 | if (!iwl_is_ready(priv)) { | ||
| 4550 | ret = -EAGAIN; | ||
| 4551 | goto out; | ||
| 4552 | } | ||
| 4553 | |||
| 4554 | ret = strict_strtoul(buf, 10, &mode); | 4553 | ret = strict_strtoul(buf, 10, &mode); |
| 4555 | if (ret) | 4554 | if (ret) |
| 4556 | goto out; | 4555 | goto out; |
| @@ -4905,7 +4904,8 @@ static int iwl3945_setup_mac(struct iwl_priv *priv) | |||
| 4905 | 4904 | ||
| 4906 | /* Tell mac80211 our characteristics */ | 4905 | /* Tell mac80211 our characteristics */ |
| 4907 | hw->flags = IEEE80211_HW_SIGNAL_DBM | | 4906 | hw->flags = IEEE80211_HW_SIGNAL_DBM | |
| 4908 | IEEE80211_HW_NOISE_DBM; | 4907 | IEEE80211_HW_NOISE_DBM | |
| 4908 | IEEE80211_HW_SPECTRUM_MGMT; | ||
| 4909 | 4909 | ||
| 4910 | hw->wiphy->interface_modes = | 4910 | hw->wiphy->interface_modes = |
| 4911 | BIT(NL80211_IFTYPE_STATION) | | 4911 | BIT(NL80211_IFTYPE_STATION) | |
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h index f8eb9097ff0a..d16b26416e82 100644 --- a/drivers/net/wireless/libertas/radiotap.h +++ b/drivers/net/wireless/libertas/radiotap.h | |||
| @@ -33,22 +33,12 @@ struct rx_radiotap_hdr { | |||
| 33 | struct ieee80211_radiotap_header hdr; | 33 | struct ieee80211_radiotap_header hdr; |
| 34 | u8 flags; | 34 | u8 flags; |
| 35 | u8 rate; | 35 | u8 rate; |
| 36 | u16 chan_freq; | ||
| 37 | u16 chan_flags; | ||
| 38 | u8 antenna; | ||
| 39 | u8 antsignal; | 36 | u8 antsignal; |
| 40 | u16 rx_flags; | ||
| 41 | #if 0 | ||
| 42 | u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18]; | ||
| 43 | #endif | ||
| 44 | } __attribute__ ((packed)); | 37 | } __attribute__ ((packed)); |
| 45 | 38 | ||
| 46 | #define RX_RADIOTAP_PRESENT ( \ | 39 | #define RX_RADIOTAP_PRESENT ( \ |
| 47 | (1 << IEEE80211_RADIOTAP_FLAGS) | \ | 40 | (1 << IEEE80211_RADIOTAP_FLAGS) | \ |
| 48 | (1 << IEEE80211_RADIOTAP_RATE) | \ | 41 | (1 << IEEE80211_RADIOTAP_RATE) | \ |
| 49 | (1 << IEEE80211_RADIOTAP_CHANNEL) | \ | ||
| 50 | (1 << IEEE80211_RADIOTAP_ANTENNA) | \ | ||
| 51 | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ | 42 | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ |
| 52 | (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \ | ||
| 53 | 0) | 43 | 0) |
| 54 | 44 | ||
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 4f60948dde9c..63d7e19ce9bd 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c | |||
| @@ -351,19 +351,11 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, | |||
| 351 | radiotap_hdr.hdr.it_pad = 0; | 351 | radiotap_hdr.hdr.it_pad = 0; |
| 352 | radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); | 352 | radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); |
| 353 | radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); | 353 | radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); |
| 354 | /* unknown values */ | 354 | if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) |
| 355 | radiotap_hdr.flags = 0; | 355 | radiotap_hdr.flags |= IEEE80211_RADIOTAP_F_BADFCS; |
| 356 | radiotap_hdr.chan_freq = 0; | ||
| 357 | radiotap_hdr.chan_flags = 0; | ||
| 358 | radiotap_hdr.antenna = 0; | ||
| 359 | /* known values */ | ||
| 360 | radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); | 356 | radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); |
| 361 | /* XXX must check no carryout */ | 357 | /* XXX must check no carryout */ |
| 362 | radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; | 358 | radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; |
| 363 | radiotap_hdr.rx_flags = 0; | ||
| 364 | if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) | ||
| 365 | radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; | ||
| 366 | //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); | ||
| 367 | 359 | ||
| 368 | /* chop the rxpd */ | 360 | /* chop the rxpd */ |
| 369 | skb_pull(skb, sizeof(struct rxpd)); | 361 | skb_pull(skb, sizeof(struct rxpd)); |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 2368b7f825a2..d4fdc8b7d7d8 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
| @@ -933,7 +933,6 @@ static int __init init_mac80211_hwsim(void) | |||
| 933 | BIT(NL80211_IFTYPE_STATION) | | 933 | BIT(NL80211_IFTYPE_STATION) | |
| 934 | BIT(NL80211_IFTYPE_AP) | | 934 | BIT(NL80211_IFTYPE_AP) | |
| 935 | BIT(NL80211_IFTYPE_MESH_POINT); | 935 | BIT(NL80211_IFTYPE_MESH_POINT); |
| 936 | hw->ampdu_queues = 1; | ||
| 937 | 936 | ||
| 938 | hw->flags = IEEE80211_HW_MFP_CAPABLE; | 937 | hw->flags = IEEE80211_HW_MFP_CAPABLE; |
| 939 | 938 | ||
| @@ -1041,6 +1040,9 @@ static int __init init_mac80211_hwsim(void) | |||
| 1041 | break; | 1040 | break; |
| 1042 | } | 1041 | } |
| 1043 | 1042 | ||
| 1043 | /* give the regulatory workqueue a chance to run */ | ||
| 1044 | if (regtest) | ||
| 1045 | schedule_timeout_interruptible(1); | ||
| 1044 | err = ieee80211_register_hw(hw); | 1046 | err = ieee80211_register_hw(hw); |
| 1045 | if (err < 0) { | 1047 | if (err < 0) { |
| 1046 | printk(KERN_DEBUG "mac80211_hwsim: " | 1048 | printk(KERN_DEBUG "mac80211_hwsim: " |
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig index cfc5f41aa136..b45d6a4ed1e8 100644 --- a/drivers/net/wireless/p54/Kconfig +++ b/drivers/net/wireless/p54/Kconfig | |||
| @@ -1,9 +1,10 @@ | |||
| 1 | config P54_COMMON | 1 | config P54_COMMON |
| 2 | tristate "Softmac Prism54 support" | 2 | tristate "Softmac Prism54 support" |
| 3 | depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL | 3 | depends on MAC80211 && WLAN_80211 && EXPERIMENTAL |
| 4 | select FW_LOADER | ||
| 4 | ---help--- | 5 | ---help--- |
| 5 | This is common code for isl38xx based cards. | 6 | This is common code for isl38xx/stlc45xx based modules. |
| 6 | This module does nothing by itself - the USB/PCI frontends | 7 | This module does nothing by itself - the USB/PCI/SPI front-ends |
| 7 | also need to be enabled in order to support any devices. | 8 | also need to be enabled in order to support any devices. |
| 8 | 9 | ||
| 9 | These devices require softmac firmware which can be found at | 10 | These devices require softmac firmware which can be found at |
| @@ -17,31 +18,6 @@ config P54_USB | |||
| 17 | select CRC32 | 18 | select CRC32 |
| 18 | ---help--- | 19 | ---help--- |
| 19 | This driver is for USB isl38xx based wireless cards. | 20 | This driver is for USB isl38xx based wireless cards. |
| 20 | These are USB based adapters found in devices such as: | ||
| 21 | |||
| 22 | 3COM 3CRWE254G72 | ||
| 23 | SMC 2862W-G | ||
| 24 | Accton 802.11g WN4501 USB | ||
| 25 | Siemens Gigaset USB | ||
| 26 | Netgear WG121 | ||
| 27 | Netgear WG111 | ||
| 28 | Medion 40900, Roper Europe | ||
| 29 | Shuttle PN15, Airvast WM168g, IOGear GWU513 | ||
| 30 | Linksys WUSB54G | ||
| 31 | Linksys WUSB54G Portable | ||
| 32 | DLink DWL-G120 Spinnaker | ||
| 33 | DLink DWL-G122 | ||
| 34 | Belkin F5D7050 ver 1000 | ||
| 35 | Cohiba Proto board | ||
| 36 | SMC 2862W-G version 2 | ||
| 37 | U.S. Robotics U5 802.11g Adapter | ||
| 38 | FUJITSU E-5400 USB D1700 | ||
| 39 | Sagem XG703A | ||
| 40 | DLink DWL-G120 Cohiba | ||
| 41 | Spinnaker Proto board | ||
| 42 | Linksys WUSB54AG | ||
| 43 | Inventel UR054G | ||
| 44 | Spinnaker DUT | ||
| 45 | 21 | ||
| 46 | These devices require softmac firmware which can be found at | 22 | These devices require softmac firmware which can be found at |
| 47 | http://prism54.org/ | 23 | http://prism54.org/ |
| @@ -64,10 +40,15 @@ config P54_PCI | |||
| 64 | 40 | ||
| 65 | config P54_SPI | 41 | config P54_SPI |
| 66 | tristate "Prism54 SPI (stlc45xx) support" | 42 | tristate "Prism54 SPI (stlc45xx) support" |
| 67 | depends on P54_COMMON && SPI_MASTER | 43 | depends on P54_COMMON && SPI_MASTER && GENERIC_HARDIRQS |
| 68 | ---help--- | 44 | ---help--- |
| 69 | This driver is for stlc4550 or stlc4560 based wireless chips. | 45 | This driver is for stlc4550 or stlc4560 based wireless chips. |
| 70 | This driver is experimental, untested and will probably only work on | 46 | This driver is experimental, untested and will probably only work on |
| 71 | Nokia's N800/N810 Portable Internet Tablet. | 47 | Nokia's N800/N810 Portable Internet Tablet. |
| 72 | 48 | ||
| 73 | If you choose to build a module, it'll be called p54spi. | 49 | If you choose to build a module, it'll be called p54spi. |
| 50 | |||
| 51 | config P54_LEDS | ||
| 52 | bool | ||
| 53 | depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON) | ||
| 54 | default y | ||
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 0a989834b70d..0c1b0577d4ee 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
| @@ -21,9 +21,9 @@ | |||
| 21 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
| 22 | 22 | ||
| 23 | #include <net/mac80211.h> | 23 | #include <net/mac80211.h> |
| 24 | #ifdef CONFIG_MAC80211_LEDS | 24 | #ifdef CONFIG_P54_LEDS |
| 25 | #include <linux/leds.h> | 25 | #include <linux/leds.h> |
| 26 | #endif /* CONFIG_MAC80211_LEDS */ | 26 | #endif /* CONFIG_P54_LEDS */ |
| 27 | 27 | ||
| 28 | #include "p54.h" | 28 | #include "p54.h" |
| 29 | #include "p54common.h" | 29 | #include "p54common.h" |
| @@ -2420,7 +2420,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, | |||
| 2420 | return 0; | 2420 | return 0; |
| 2421 | } | 2421 | } |
| 2422 | 2422 | ||
| 2423 | #ifdef CONFIG_MAC80211_LEDS | 2423 | #ifdef CONFIG_P54_LEDS |
| 2424 | static void p54_led_brightness_set(struct led_classdev *led_dev, | 2424 | static void p54_led_brightness_set(struct led_classdev *led_dev, |
| 2425 | enum led_brightness brightness) | 2425 | enum led_brightness brightness) |
| 2426 | { | 2426 | { |
| @@ -2508,7 +2508,7 @@ static void p54_unregister_leds(struct ieee80211_hw *dev) | |||
| 2508 | if (priv->assoc_led.registered) | 2508 | if (priv->assoc_led.registered) |
| 2509 | led_classdev_unregister(&priv->assoc_led.led_dev); | 2509 | led_classdev_unregister(&priv->assoc_led.led_dev); |
| 2510 | } | 2510 | } |
| 2511 | #endif /* CONFIG_MAC80211_LEDS */ | 2511 | #endif /* CONFIG_P54_LEDS */ |
| 2512 | 2512 | ||
| 2513 | static const struct ieee80211_ops p54_ops = { | 2513 | static const struct ieee80211_ops p54_ops = { |
| 2514 | .tx = p54_tx, | 2514 | .tx = p54_tx, |
| @@ -2592,11 +2592,11 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) | |||
| 2592 | return err; | 2592 | return err; |
| 2593 | } | 2593 | } |
| 2594 | 2594 | ||
| 2595 | #ifdef CONFIG_MAC80211_LEDS | 2595 | #ifdef CONFIG_P54_LEDS |
| 2596 | err = p54_init_leds(dev); | 2596 | err = p54_init_leds(dev); |
| 2597 | if (err) | 2597 | if (err) |
| 2598 | return err; | 2598 | return err; |
| 2599 | #endif /* CONFIG_MAC80211_LEDS */ | 2599 | #endif /* CONFIG_P54_LEDS */ |
| 2600 | 2600 | ||
| 2601 | dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); | 2601 | dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); |
| 2602 | return 0; | 2602 | return 0; |
| @@ -2610,9 +2610,9 @@ void p54_free_common(struct ieee80211_hw *dev) | |||
| 2610 | kfree(priv->output_limit); | 2610 | kfree(priv->output_limit); |
| 2611 | kfree(priv->curve_data); | 2611 | kfree(priv->curve_data); |
| 2612 | 2612 | ||
| 2613 | #ifdef CONFIG_MAC80211_LEDS | 2613 | #ifdef CONFIG_P54_LEDS |
| 2614 | p54_unregister_leds(dev); | 2614 | p54_unregister_leds(dev); |
| 2615 | #endif /* CONFIG_MAC80211_LEDS */ | 2615 | #endif /* CONFIG_P54_LEDS */ |
| 2616 | } | 2616 | } |
| 2617 | EXPORT_SYMBOL_GPL(p54_free_common); | 2617 | EXPORT_SYMBOL_GPL(p54_free_common); |
| 2618 | 2618 | ||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 24fdfdfee3df..420fff42c0dd 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
| @@ -2425,6 +2425,8 @@ static struct usb_device_id rt73usb_device_table[] = { | |||
| 2425 | { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, | 2425 | { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) }, |
| 2426 | /* Surecom */ | 2426 | /* Surecom */ |
| 2427 | { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, | 2427 | { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) }, |
| 2428 | /* Tilgin */ | ||
| 2429 | { USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
| 2428 | /* Philips */ | 2430 | /* Philips */ |
| 2429 | { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) }, | 2431 | { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) }, |
| 2430 | /* Planex */ | 2432 | /* Planex */ |
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index b1b947edcf01..540a2948596c 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig | |||
| @@ -53,11 +53,11 @@ config SSB_B43_PCI_BRIDGE | |||
| 53 | 53 | ||
| 54 | config SSB_PCMCIAHOST_POSSIBLE | 54 | config SSB_PCMCIAHOST_POSSIBLE |
| 55 | bool | 55 | bool |
| 56 | depends on SSB && (PCMCIA = y || PCMCIA = SSB) && EXPERIMENTAL | 56 | depends on SSB && (PCMCIA = y || PCMCIA = SSB) |
| 57 | default y | 57 | default y |
| 58 | 58 | ||
| 59 | config SSB_PCMCIAHOST | 59 | config SSB_PCMCIAHOST |
| 60 | bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)" | 60 | bool "Support for SSB on PCMCIA-bus host" |
| 61 | depends on SSB_PCMCIAHOST_POSSIBLE | 61 | depends on SSB_PCMCIAHOST_POSSIBLE |
| 62 | select SSB_SPROM | 62 | select SSB_SPROM |
| 63 | help | 63 | help |
| @@ -107,14 +107,14 @@ config SSB_DRIVER_PCICORE | |||
| 107 | If unsure, say Y | 107 | If unsure, say Y |
| 108 | 108 | ||
| 109 | config SSB_PCICORE_HOSTMODE | 109 | config SSB_PCICORE_HOSTMODE |
| 110 | bool "Hostmode support for SSB PCI core (EXPERIMENTAL)" | 110 | bool "Hostmode support for SSB PCI core" |
| 111 | depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL | 111 | depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS |
| 112 | help | 112 | help |
| 113 | PCIcore hostmode operation (external PCI bus). | 113 | PCIcore hostmode operation (external PCI bus). |
| 114 | 114 | ||
| 115 | config SSB_DRIVER_MIPS | 115 | config SSB_DRIVER_MIPS |
| 116 | bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)" | 116 | bool "SSB Broadcom MIPS core driver" |
| 117 | depends on SSB && MIPS && EXPERIMENTAL | 117 | depends on SSB && MIPS |
| 118 | select SSB_SERIAL | 118 | select SSB_SERIAL |
| 119 | help | 119 | help |
| 120 | Driver for the Sonics Silicon Backplane attached | 120 | Driver for the Sonics Silicon Backplane attached |
| @@ -129,8 +129,8 @@ config SSB_EMBEDDED | |||
| 129 | default y | 129 | default y |
| 130 | 130 | ||
| 131 | config SSB_DRIVER_EXTIF | 131 | config SSB_DRIVER_EXTIF |
| 132 | bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)" | 132 | bool "SSB Broadcom EXTIF core driver" |
| 133 | depends on SSB_DRIVER_MIPS && EXPERIMENTAL | 133 | depends on SSB_DRIVER_MIPS |
| 134 | help | 134 | help |
| 135 | Driver for the Sonics Silicon Backplane attached | 135 | Driver for the Sonics Silicon Backplane attached |
| 136 | Broadcom EXTIF core. | 136 | Broadcom EXTIF core. |
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index 27a677584a4c..ef9c6a04ad8f 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | static const struct pci_device_id b43_pci_bridge_tbl[] = { | 19 | static const struct pci_device_id b43_pci_bridge_tbl[] = { |
| 20 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, | 20 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) }, |
| 21 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4306) }, | ||
| 21 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) }, | 22 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) }, |
| 22 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, | 23 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) }, |
| 23 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, | 24 | { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) }, |
