8442d62654
SVN-Revision: 24033
305 lines
8.6 KiB
Diff
305 lines
8.6 KiB
Diff
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
|
|
@@ -3271,6 +3271,18 @@ static bool ar9300_check_eeprom_header(s
|
|
return ar9300_check_header(header);
|
|
}
|
|
|
|
+static int ar9300_eeprom_restore_flash(struct ath_hw *ah, u8 *mptr,
|
|
+ int mdata_size)
|
|
+{
|
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
|
+ u16 *data = (u16 *) mptr;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < mdata_size / 2; i++, data++)
|
|
+ ath9k_hw_nvram_read(common, i, data);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
/*
|
|
* Read the configuration data from the eeprom.
|
|
* The data can be put in any specified memory buffer.
|
|
@@ -3293,6 +3305,9 @@ static int ar9300_eeprom_restore_interna
|
|
struct ath_common *common = ath9k_hw_common(ah);
|
|
eeprom_read_op read;
|
|
|
|
+ if (ath9k_hw_use_flash(ah))
|
|
+ return ar9300_eeprom_restore_flash(ah, mptr, mdata_size);
|
|
+
|
|
word = kzalloc(2048, GFP_KERNEL);
|
|
if (!word)
|
|
return -1;
|
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
|
@@ -419,10 +419,6 @@ static void ath9k_hw_init_defaults(struc
|
|
ah->hw_version.magic = AR5416_MAGIC;
|
|
ah->hw_version.subvendorid = 0;
|
|
|
|
- ah->ah_flags = 0;
|
|
- if (!AR_SREV_9100(ah))
|
|
- ah->ah_flags = AH_USE_EEPROM;
|
|
-
|
|
ah->atim_window = 0;
|
|
ah->sta_id1_defaults =
|
|
AR_STA_ID1_CRPT_MIC_ENABLE |
|
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
|
@@ -533,6 +533,9 @@ static int ath9k_init_softc(u16 devid, s
|
|
ah->hw_version.subsysid = subsysid;
|
|
sc->sc_ah = ah;
|
|
|
|
+ if (!sc->dev->platform_data)
|
|
+ ah->ah_flags |= AH_USE_EEPROM;
|
|
+
|
|
common = ath9k_hw_common(ah);
|
|
common->ops = &ath9k_common_ops;
|
|
common->bus_ops = bus_ops;
|
|
--- a/drivers/net/wireless/ath/ath9k/pci.c
|
|
+++ b/drivers/net/wireless/ath/ath9k/pci.c
|
|
@@ -16,6 +16,7 @@
|
|
|
|
#include <linux/nl80211.h>
|
|
#include <linux/pci.h>
|
|
+#include <linux/ath9k_platform.h>
|
|
#include "ath9k.h"
|
|
|
|
static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
|
|
@@ -53,21 +54,36 @@ static void ath_pci_read_cachesize(struc
|
|
|
|
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
|
|
{
|
|
- struct ath_hw *ah = (struct ath_hw *) common->ah;
|
|
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
|
|
+ struct ath9k_platform_data *pdata = sc->dev->platform_data;
|
|
|
|
- common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
|
|
+ if (pdata) {
|
|
+ if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
|
|
+ ath_print(common, ATH_DBG_FATAL,
|
|
+ "%s: eeprom read failed, offset %08x "
|
|
+ "is out of range\n",
|
|
+ __func__, off);
|
|
+ }
|
|
+
|
|
+ *data = pdata->eeprom_data[off];
|
|
+ } else {
|
|
+ struct ath_hw *ah = (struct ath_hw *) common->ah;
|
|
+
|
|
+ common->ops->read(ah, AR5416_EEPROM_OFFSET +
|
|
+ (off << AR5416_EEPROM_S));
|
|
+
|
|
+ if (!ath9k_hw_wait(ah,
|
|
+ AR_EEPROM_STATUS_DATA,
|
|
+ AR_EEPROM_STATUS_DATA_BUSY |
|
|
+ AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
|
|
+ AH_WAIT_TIMEOUT)) {
|
|
+ return false;
|
|
+ }
|
|
|
|
- if (!ath9k_hw_wait(ah,
|
|
- AR_EEPROM_STATUS_DATA,
|
|
- AR_EEPROM_STATUS_DATA_BUSY |
|
|
- AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
|
|
- AH_WAIT_TIMEOUT)) {
|
|
- return false;
|
|
+ *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
|
|
+ AR_EEPROM_STATUS_DATA_VAL);
|
|
}
|
|
|
|
- *data = MS(common->ops->read(ah, AR_EEPROM_STATUS_DATA),
|
|
- AR_EEPROM_STATUS_DATA_VAL);
|
|
-
|
|
return true;
|
|
}
|
|
|
|
--- a/include/net/regulatory.h
|
|
+++ b/include/net/regulatory.h
|
|
@@ -43,6 +43,12 @@ enum environment_cap {
|
|
* @intersect: indicates whether the wireless core should intersect
|
|
* the requested regulatory domain with the presently set regulatory
|
|
* domain.
|
|
+ * @processed: indicates whether or not this requests has already been
|
|
+ * processed. When the last request is processed it means that the
|
|
+ * currently regulatory domain set on cfg80211 is updated from
|
|
+ * CRDA and can be used by other regulatory requests. When a
|
|
+ * the last request is not yet processed we must yield until it
|
|
+ * is processed before processing any new requests.
|
|
* @country_ie_checksum: checksum of the last processed and accepted
|
|
* country IE
|
|
* @country_ie_env: lets us know if the AP is telling us we are outdoor,
|
|
@@ -54,6 +60,7 @@ struct regulatory_request {
|
|
enum nl80211_reg_initiator initiator;
|
|
char alpha2[2];
|
|
bool intersect;
|
|
+ bool processed;
|
|
enum environment_cap country_ie_env;
|
|
struct list_head list;
|
|
};
|
|
--- a/net/wireless/reg.c
|
|
+++ b/net/wireless/reg.c
|
|
@@ -96,6 +96,9 @@ struct reg_beacon {
|
|
struct ieee80211_channel chan;
|
|
};
|
|
|
|
+static void reg_todo(struct work_struct *work);
|
|
+static DECLARE_WORK(reg_work, reg_todo);
|
|
+
|
|
/* We keep a static world regulatory domain in case of the absence of CRDA */
|
|
static const struct ieee80211_regdomain world_regdom = {
|
|
.n_reg_rules = 5,
|
|
@@ -1317,6 +1320,21 @@ static int ignore_request(struct wiphy *
|
|
return -EINVAL;
|
|
}
|
|
|
|
+static void reg_set_request_processed(void)
|
|
+{
|
|
+ bool need_more_processing = false;
|
|
+
|
|
+ last_request->processed = true;
|
|
+
|
|
+ spin_lock(®_requests_lock);
|
|
+ if (!list_empty(®_requests_list))
|
|
+ need_more_processing = true;
|
|
+ spin_unlock(®_requests_lock);
|
|
+
|
|
+ if (need_more_processing)
|
|
+ schedule_work(®_work);
|
|
+}
|
|
+
|
|
/**
|
|
* __regulatory_hint - hint to the wireless core a regulatory domain
|
|
* @wiphy: if the hint comes from country information from an AP, this
|
|
@@ -1392,8 +1410,10 @@ new_request:
|
|
* have applied the requested regulatory domain before we just
|
|
* inform userspace we have processed the request
|
|
*/
|
|
- if (r == -EALREADY)
|
|
+ if (r == -EALREADY) {
|
|
nl80211_send_reg_change_event(last_request);
|
|
+ reg_set_request_processed();
|
|
+ }
|
|
return r;
|
|
}
|
|
|
|
@@ -1409,16 +1429,13 @@ static void reg_process_hint(struct regu
|
|
|
|
BUG_ON(!reg_request->alpha2);
|
|
|
|
- mutex_lock(&cfg80211_mutex);
|
|
- mutex_lock(®_mutex);
|
|
-
|
|
if (wiphy_idx_valid(reg_request->wiphy_idx))
|
|
wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
|
|
|
|
if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
|
!wiphy) {
|
|
kfree(reg_request);
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
|
|
r = __regulatory_hint(wiphy, reg_request);
|
|
@@ -1426,28 +1443,46 @@ static void reg_process_hint(struct regu
|
|
if (r == -EALREADY && wiphy &&
|
|
wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
|
|
wiphy_update_regulatory(wiphy, initiator);
|
|
-out:
|
|
- mutex_unlock(®_mutex);
|
|
- mutex_unlock(&cfg80211_mutex);
|
|
}
|
|
|
|
-/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */
|
|
+/*
|
|
+ * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_*
|
|
+ * Regulatory hints come on a first come first serve basis and we
|
|
+ * must process each one atomically.
|
|
+ */
|
|
static void reg_process_pending_hints(void)
|
|
- {
|
|
+{
|
|
struct regulatory_request *reg_request;
|
|
|
|
+ mutex_lock(&cfg80211_mutex);
|
|
+ mutex_lock(®_mutex);
|
|
+
|
|
+ /* When last_request->processed becomes true this will be rescheduled */
|
|
+ if (last_request && !last_request->processed) {
|
|
+ REG_DBG_PRINT("Pending regulatory request, waiting "
|
|
+ "for it to be processed...");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
spin_lock(®_requests_lock);
|
|
- while (!list_empty(®_requests_list)) {
|
|
- reg_request = list_first_entry(®_requests_list,
|
|
- struct regulatory_request,
|
|
- list);
|
|
- list_del_init(®_request->list);
|
|
|
|
+ if (list_empty(®_requests_list)) {
|
|
spin_unlock(®_requests_lock);
|
|
- reg_process_hint(reg_request);
|
|
- spin_lock(®_requests_lock);
|
|
+ goto out;
|
|
}
|
|
+
|
|
+ reg_request = list_first_entry(®_requests_list,
|
|
+ struct regulatory_request,
|
|
+ list);
|
|
+ list_del_init(®_request->list);
|
|
+
|
|
spin_unlock(®_requests_lock);
|
|
+
|
|
+ reg_process_hint(reg_request);
|
|
+
|
|
+out:
|
|
+ mutex_unlock(®_mutex);
|
|
+ mutex_unlock(&cfg80211_mutex);
|
|
}
|
|
|
|
/* Processes beacon hints -- this has nothing to do with country IEs */
|
|
@@ -1494,8 +1529,6 @@ static void reg_todo(struct work_struct
|
|
reg_process_pending_beacon_hints();
|
|
}
|
|
|
|
-static DECLARE_WORK(reg_work, reg_todo);
|
|
-
|
|
static void queue_regulatory_request(struct regulatory_request *request)
|
|
{
|
|
if (isalpha(request->alpha2[0]))
|
|
@@ -1530,12 +1563,7 @@ static int regulatory_hint_core(const ch
|
|
request->alpha2[1] = alpha2[1];
|
|
request->initiator = NL80211_REGDOM_SET_BY_CORE;
|
|
|
|
- /*
|
|
- * This ensures last_request is populated once modules
|
|
- * come swinging in and calling regulatory hints and
|
|
- * wiphy_apply_custom_regulatory().
|
|
- */
|
|
- reg_process_hint(request);
|
|
+ queue_regulatory_request(request);
|
|
|
|
return 0;
|
|
}
|
|
@@ -2061,6 +2089,8 @@ int set_regdom(const struct ieee80211_re
|
|
|
|
nl80211_send_reg_change_event(last_request);
|
|
|
|
+ reg_set_request_processed();
|
|
+
|
|
mutex_unlock(®_mutex);
|
|
|
|
return r;
|
|
--- a/net/wireless/chan.c
|
|
+++ b/net/wireless/chan.c
|
|
@@ -54,8 +54,10 @@ static bool can_beacon_sec_chan(struct w
|
|
switch (channel_type) {
|
|
case NL80211_CHAN_HT40PLUS:
|
|
diff = 20;
|
|
+ break;
|
|
case NL80211_CHAN_HT40MINUS:
|
|
diff = -20;
|
|
+ break;
|
|
default:
|
|
return false;
|
|
}
|