From 7f93ea3e246db512c0c17b79847f57dd3a2891e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Aug 2008 21:45:26 +0200 Subject: mac80211: fill start-sequence-number for BA session start Otherwise, drivers are required to keep track of the sequence numbers themselves, and they really shouldn't be since we already do it for them. I'll fix the race once we figure out how this code should work at all, it's currently disabled. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 398ca66..638b75f 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -598,7 +598,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) struct ieee80211_local *local = hw_to_local(hw); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; - u16 start_seq_num = 0; + u16 start_seq_num; u8 *state; int ret; DECLARE_MAC_BUF(mac); @@ -678,6 +678,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) * call back right away, it must see that the flow has begun */ *state |= HT_ADDBA_REQUESTED_MSK; + /* This is slightly racy because the queue isn't stopped */ + start_seq_num = sta->tid_seq[tid]; + if (local->ops->ampdu_action) ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, ra, tid, &start_seq_num); -- cgit v0.10.2 From 9f1ba9062e032fb7b395cd27fc564754fe4e9867 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 7 Aug 2008 20:07:01 +0300 Subject: mac80211/cfg80211: Add BSS configuration options for AP mode This change adds a new cfg80211 command, NL80211_CMD_SET_BSS, to allow AP mode BSS parameters to be changed from user space (e.g., hostapd). The drivers using mac80211 are expected to be modified with separate changes to use the new BSS info parameter for short slot time in the bss_info_changed() handler. Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2be7c63..447c02a 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -89,6 +89,8 @@ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC * or, if no MAC address given, all mesh paths, on the interface identified * by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by + * %NL80211_ATTR_IFINDEX. * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use @@ -127,6 +129,8 @@ enum nl80211_commands { NL80211_CMD_NEW_MPATH, NL80211_CMD_DEL_MPATH, + NL80211_CMD_SET_BSS, + /* add commands here */ /* used to define NL80211_CMD_MAX below */ @@ -134,6 +138,11 @@ enum nl80211_commands { NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 }; +/* + * Allow user space programs to use #ifdef on new commands by defining them + * here + */ +#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS /** * enum nl80211_attrs - nl80211 netlink attributes @@ -192,6 +201,12 @@ enum nl80211_commands { * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of * &enum nl80211_mntr_flags. * + * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled + * (u8, 0 or 1) + * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled + * (u8, 0 or 1) + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -235,6 +250,10 @@ enum nl80211_attrs { NL80211_ATTR_MPATH_NEXT_HOP, NL80211_ATTR_MPATH_INFO, + NL80211_ATTR_BSS_CTS_PROT, + NL80211_ATTR_BSS_SHORT_PREAMBLE, + NL80211_ATTR_BSS_SHORT_SLOT_TIME, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e007508..7afef14 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -268,6 +268,23 @@ struct mpath_info { u8 flags; }; +/** + * struct bss_parameters - BSS parameters + * + * Used to change BSS parameters (mainly for AP mode). + * + * @use_cts_prot: Whether to use CTS protection + * (0 = no, 1 = yes, -1 = do not change) + * @use_short_preamble: Whether the use of short preambles is allowed + * (0 = no, 1 = yes, -1 = do not change) + * @use_short_slot_time: Whether the use of short slot time is allowed + * (0 = no, 1 = yes, -1 = do not change) + */ +struct bss_parameters { + int use_cts_prot; + int use_short_preamble; + int use_short_slot_time; +}; /* from net/wireless.h */ struct wiphy; @@ -318,6 +335,8 @@ struct wiphy; * @change_station: Modify a given station. * * @set_mesh_cfg: set mesh parameters (by now, just mesh id) + * + * @change_bss: Modify parameters for a given BSS. */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name, @@ -370,6 +389,9 @@ struct cfg80211_ops { int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *dst, u8 *next_hop, struct mpath_info *pinfo); + + int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params); }; #endif /* __NET_CFG80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 0fdc3da..7c399a9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -158,12 +158,14 @@ struct ieee80211_low_level_stats { * also implies a change in the AID. * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed * @BSS_CHANGED_ERP_PREAMBLE: preamble changed + * @BSS_CHANGED_ERP_SLOT: slot timing changed * @BSS_CHANGED_HT: 802.11n parameters changed */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, BSS_CHANGED_ERP_CTS_PROT = 1<<1, BSS_CHANGED_ERP_PREAMBLE = 1<<2, + BSS_CHANGED_ERP_SLOT = 1<<3, BSS_CHANGED_HT = 1<<4, }; @@ -177,6 +179,7 @@ enum ieee80211_bss_change { * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble + * @use_short_slot: use short slot time (only relevant for ERP) * @dtim_period: num of beacons before the next DTIM, for PSM * @timestamp: beacon timestamp * @beacon_int: beacon interval @@ -192,6 +195,7 @@ struct ieee80211_bss_conf { /* erp related data */ bool use_cts_prot; bool use_short_preamble; + bool use_short_slot; u8 dtim_period; u16 beacon_int; u16 assoc_capability; @@ -420,6 +424,11 @@ struct ieee80211_rx_status { * @IEEE80211_CONF_PS: Enable 802.11 power save mode */ enum ieee80211_conf_flags { + /* + * TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers + * have been converted to use bss_info_changed() for slot time + * configuration + */ IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0), IEEE80211_CONF_RADIOTAP = (1<<1), IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2), diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6d2ad2b..2b19532 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1010,6 +1010,42 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, } #endif +static int ieee80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata; + u32 changed = 0; + + if (dev == local->mdev) + return -EOPNOTSUPP; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type != IEEE80211_IF_TYPE_AP) + return -EINVAL; + + if (params->use_cts_prot >= 0) { + sdata->bss_conf.use_cts_prot = params->use_cts_prot; + changed |= BSS_CHANGED_ERP_CTS_PROT; + } + if (params->use_short_preamble >= 0) { + sdata->bss_conf.use_short_preamble = + params->use_short_preamble; + changed |= BSS_CHANGED_ERP_PREAMBLE; + } + if (params->use_short_slot_time >= 0) { + sdata->bss_conf.use_short_slot = + params->use_short_slot_time; + changed |= BSS_CHANGED_ERP_SLOT; + } + + ieee80211_bss_info_change_notify(sdata, changed); + + return 0; +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1033,4 +1069,5 @@ struct cfg80211_ops mac80211_config_ops = { .get_mpath = ieee80211_get_mpath, .dump_mpath = ieee80211_dump_mpath, #endif + .change_bss = ieee80211_change_bss, }; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 59eb2cf..47542ee 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -87,6 +87,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_MESH_ID_LEN }, [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, + + [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, }; /* message building helper */ @@ -1525,6 +1529,48 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct bss_parameters params; + + memset(¶ms, 0, sizeof(params)); + /* default to not changing parameters */ + params.use_cts_prot = -1; + params.use_short_preamble = -1; + params.use_short_slot_time = -1; + + if (info->attrs[NL80211_ATTR_BSS_CTS_PROT]) + params.use_cts_prot = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]); + if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]) + params.use_short_preamble = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]); + if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) + params.use_short_slot_time = + nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + return err; + + if (!drv->ops->change_bss) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -1656,6 +1702,12 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_SET_BSS, + .doit = nl80211_set_bss, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ -- cgit v0.10.2 From f45144ef412422edf8018825328768e3db3ea45b Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:02:53 +0530 Subject: ath9k: Merge reset functions Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index caf5694..67a8046 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -719,7 +719,7 @@ void ath_bstuck_process(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_BEACON, "%s: stuck beacon; resetting (bmiss count %u)\n", __func__, sc->sc_bmisscount); - ath_internal_reset(sc); + ath_reset(sc, false); } /* diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index f6c4528..10f2729 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -828,29 +828,30 @@ done: return error; } -/* - * Reset the hardware w/o losing operational state. This is - * basically a more efficient way of doing ath_stop, ath_init, - * followed by state transitions to the current 802.11 - * operational state. Used to recover from errors rx overrun - * and to reset the hardware when rf gain settings must be reset. - */ - -static int ath_reset_start(struct ath_softc *sc, u32 flag) +int ath_reset(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; + enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, flag & RESET_RETRY_TXQ); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ - - return 0; -} + ath_draintxq(sc, retry_tx); /* stop xmit */ + ath_stoprecv(sc); /* stop recv */ + ath_flushrecv(sc); /* flush recv queue */ -static int ath_reset_end(struct ath_softc *sc, u32 flag) -{ - struct ath_hal *ah = sc->sc_ah; + /* Reset chip */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, + ht_macmode, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "%s: unable to reset hardware; hal status %u\n", + __func__, status); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) /* restart recv */ DPRINTF(sc, ATH_DBG_FATAL, @@ -863,14 +864,15 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) */ ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan)); - ath_update_txpow(sc); /* update tx power state */ + ath_update_txpow(sc); if (sc->sc_beacons) ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + ath9k_hw_set_interrupts(ah, sc->sc_imask); /* Restart the txq */ - if (flag & RESET_RETRY_TXQ) { + if (retry_tx) { int i; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { @@ -880,28 +882,6 @@ static int ath_reset_end(struct ath_softc *sc, u32 flag) } } } - return 0; -} - -int ath_reset(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - - /* NB: indicate channel change so we do a full reset */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, - ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, status); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); return error; } @@ -1050,7 +1030,7 @@ static void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_FATAL) { /* need a chip reset */ - ath_internal_reset(sc); + ath_reset(sc, false); return; } else { @@ -1815,13 +1795,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, /* Utilities */ /*************/ -void ath_internal_reset(struct ath_softc *sc) -{ - ath_reset_start(sc, 0); - ath_reset(sc); - ath_reset_end(sc, 0); -} - int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) { int qnum; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 673b3d8..ef8f637 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1030,7 +1030,7 @@ void ath_deinit(struct ath_softc *sc); int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); int ath_suspend(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); -int ath_reset(struct ath_softc *sc); +int ath_reset(struct ath_softc *sc, bool retry_tx); void ath_scan_start(struct ath_softc *sc); void ath_scan_end(struct ath_softc *sc); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); @@ -1056,7 +1056,6 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -void ath_internal_reset(struct ath_softc *sc); u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc); dma_addr_t ath_skb_map_single(struct ath_softc *sc, struct sk_buff *skb, diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 2fe8061..838b656 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -1089,7 +1089,7 @@ rx_next: "%s: Reset rx chain mask. " "Do internal reset\n", __func__); ASSERT(flush == 0); - ath_internal_reset(sc); + ath_reset(sc, false); } return 0; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 157f830..93064cc 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1242,7 +1242,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, } if (needreset) - ath_internal_reset(sc); + ath_reset(sc, false); return; } -- cgit v0.10.2 From 7dcfdcd908a4540512aaf06b2b35e8c8a084fb69 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:13 +0530 Subject: ath9k: RX Filter cleanup Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 10f2729..7f92d469 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -21,9 +21,6 @@ static int ath_outdoor; /* enable outdoor use */ -static const u8 ath_bcast_mac[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - static u32 ath_chainmask_sel_up_rssi_thres = ATH_CHAINMASK_SEL_UP_RSSI_THRES; static u32 ath_chainmask_sel_down_rssi_thres = @@ -307,56 +304,6 @@ static int ath_stop(struct ath_softc *sc) } /* - * Start Scan - * - * This function is called when starting a channel scan. It will perform - * power save wakeup processing, set the filter for the scan, and get the - * chip ready to send broadcast packets out during the scan. -*/ - -void ath_scan_start(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, ath_bcast_mac, 0); - - /* Restore previous power management state. */ - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n", - now / 1000, now % 1000, __func__, rfilt); -} - -/* - * Scan End - * - * This routine is called by the upper layer when the scan is completed. This - * will set the filters back to normal operating mode, set the BSSID to the - * correct value, and restore the power save state. -*/ - -void ath_scan_end(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 rfilt; - u32 now = (u32) jiffies_to_msecs(get_timestamp()); - - sc->sc_scanning = 0; - /* Request for a full reset due to rx packet filter changes */ - sc->sc_full_reset = 1; - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - - DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n", - now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid); -} - -/* * Set the current channel * * Set/change channels. If the channel is really being changed, it's done diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ef8f637..07c9588 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -95,6 +95,8 @@ static inline unsigned long get_timestamp(void) return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ); } +static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + /*************/ /* Debugging */ /*************/ @@ -919,10 +921,9 @@ struct ath_softc { struct ath_rate_softc *sc_rc; /* tx rate control support */ u32 sc_intrstatus; enum ath9k_opmode sc_opmode; /* current operating mode */ - + unsigned int rx_filter; u8 sc_invalid; /* being detached */ u8 sc_beacons; /* beacons running */ - u8 sc_scanning; /* scanning active */ u8 sc_txaggr; /* enable 11n tx aggregation */ u8 sc_rxaggr; /* enable 11n rx aggregation */ u8 sc_update_chainmask; /* change chain mask */ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2888778..262fd7a 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -549,10 +549,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Update ratectrl about the new state */ ath_rate_newstate(sc, avp); - /* Set rx filter */ - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(sc->sc_ah, rfilt); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -636,8 +632,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | \ FIF_FCSFAIL) -/* Accept unicast, bcast and mcast frames */ - +/* FIXME: sc->sc_full_reset ? */ static void ath9k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -645,16 +640,22 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, struct dev_mc_list *mclist) { struct ath_softc *sc = hw->priv; + u32 rfilt; changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; + sc->rx_filter = *total_flags; + rfilt = ath_calcrxfilter(sc); + ath9k_hw_setrxfilter(sc->sc_ah, rfilt); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - ath_scan_start(sc); - else - ath_scan_end(sc); + ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } + + DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", + __func__, sc->rx_filter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 838b656..a125849 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -597,6 +597,7 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) + u32 rfilt; rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) @@ -608,14 +609,17 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (((sc->sc_opmode != ATH9K_M_HOSTAP) && + (sc->rx_filter & FIF_PROMISC_IN_BSS)) || + (sc->sc_opmode == ATH9K_M_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS || - sc->sc_scanning) + if (((sc->sc_opmode == ATH9K_M_STA) && + (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || + (sc->sc_opmode == ATH9K_M_IBSS)) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames @@ -623,6 +627,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) if (sc->sc_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; + #undef RX_FILTER_PRESERVE } -- cgit v0.10.2 From cd3d39a6875507f4f4d585391fe3d344f0b64b5c Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:34 +0530 Subject: ath9k: Use bitfields for buffer type Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 07c9588..9e16c6c 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -177,11 +177,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht); /* Descriptor Management */ /*************************/ -/* Number of descriptors per buffer. The only case where we see skbuff -chains is due to FF aggregation in the driver. */ -#define ATH_TXDESC 1 -/* if there's more fragment for this MSDU */ -#define ATH_BF_MORE_MPDU 1 #define ATH_TXBUF_RESET(_bf) do { \ (_bf)->bf_status = 0; \ (_bf)->bf_lastbf = NULL; \ @@ -191,28 +186,29 @@ chains is due to FF aggregation in the driver. */ sizeof(struct ath_buf_state)); \ } while (0) +enum buffer_type { + BUF_DATA = BIT(0), + BUF_AGGR = BIT(1), + BUF_AMPDU = BIT(2), + BUF_HT = BIT(3), + BUF_RETRY = BIT(4), + BUF_XRETRY = BIT(5), + BUF_SHORT_PREAMBLE = BIT(6), + BUF_BAR = BIT(7), + BUF_PSPOLL = BIT(8), + BUF_AGGR_BURST = BIT(9), + BUF_CALC_AIRTIME = BIT(10), +}; + struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ + int bfs_nframes; /* # frames in aggregate */ + u16 bfs_al; /* length of aggregate */ + u16 bfs_frmlen; /* length of frame */ + int bfs_seqno; /* sequence number */ + int bfs_tidno; /* tid of this frame */ + int bfs_retries; /* current retries */ struct ath_rc_series bfs_rcs[4]; /* rate series */ - u8 bfs_isdata:1; /* is a data frame/aggregate */ - u8 bfs_isaggr:1; /* is an aggregate */ - u8 bfs_isampdu:1; /* is an a-mpdu, aggregate or not */ - u8 bfs_ht:1; /* is an HT frame */ - u8 bfs_isretried:1; /* is retried */ - u8 bfs_isxretried:1; /* is excessive retried */ - u8 bfs_shpreamble:1; /* is short preamble */ - u8 bfs_isbar:1; /* is a BAR */ - u8 bfs_ispspoll:1; /* is a PS-Poll */ - u8 bfs_aggrburst:1; /* is a aggr burst */ - u8 bfs_calcairtime:1; /* requests airtime be calculated - when set for tx frame */ - int bfs_rifsburst_elem; /* RIFS burst/bar */ - int bfs_nrifsubframes; /* # of elements in burst */ + u32 bf_type; /* BUF_* (enum buffer_type) */ /* key type use to encrypt this frame */ enum ath9k_key_type bfs_keytype; }; @@ -224,26 +220,22 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs -#define bf_isdata bf_state.bfs_isdata -#define bf_isaggr bf_state.bfs_isaggr -#define bf_isampdu bf_state.bfs_isampdu -#define bf_ht bf_state.bfs_ht -#define bf_isretried bf_state.bfs_isretried -#define bf_isxretried bf_state.bfs_isxretried -#define bf_shpreamble bf_state.bfs_shpreamble -#define bf_rifsburst_elem bf_state.bfs_rifsburst_elem -#define bf_nrifsubframes bf_state.bfs_nrifsubframes #define bf_keytype bf_state.bfs_keytype -#define bf_isbar bf_state.bfs_isbar -#define bf_ispspoll bf_state.bfs_ispspoll -#define bf_aggrburst bf_state.bfs_aggrburst -#define bf_calcairtime bf_state.bfs_calcairtime +#define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) +#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) +#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) +#define bf_isht(bf) (bf->bf_state.bf_type & BUF_HT) +#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY) +#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) +#define bf_isshpreamble(bf) (bf->bf_state.bf_type & BUF_SHORT_PREAMBLE) +#define bf_isbar(bf) (bf->bf_state.bf_type & BUF_BAR) +#define bf_ispspoll(bf) (bf->bf_state.bf_type & BUF_PSPOLL) +#define bf_isaggrburst(bf) (bf->bf_state.bf_type & BUF_AGGR_BURST) /* * Abstraction of a contiguous buffer to transmit/receive. There is only * a single hw descriptor encapsulated here. */ - struct ath_buf { struct list_head list; struct list_head *last; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 93064cc..47cf9f3 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -518,7 +518,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (!txok) { tx_status.flags |= ATH_TX_ERROR; - if (bf->bf_isxretried) + if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } /* Unmap this frame */ @@ -629,7 +629,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { seq_st = ATH_DS_BA_SEQ(ds); memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3); @@ -651,7 +651,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) struct sk_buff *skb; struct ieee80211_hdr *hdr; - bf->bf_isretried = 1; + bf->bf_state.bf_type |= BUF_RETRY; bf->bf_retries++; skb = bf->bf_mpdu; @@ -698,7 +698,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rc; int streams, pktlen; - pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen; + pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; rc = rt->info[rix].rateCode; /* @@ -781,7 +781,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * let rate series flags determine which rates will actually * use RTS. */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) { + if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { BUG_ON(!an); /* * 802.11g protection not needed, use our default behavior @@ -793,7 +793,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * and the second aggregate should have any protection at all. */ if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf->bf_aggrburst) { + if (!bf_isaggrburst(bf)) { flags = ATH9K_TXDESC_RTSENA; dynamic_mimops = 1; } else { @@ -806,7 +806,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && - (!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) { + (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; cix = rt->info[sc->sc_protrix].controlRate; rtsctsena = 1; @@ -815,7 +815,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* * For AR5416 - RTS cannot be followed by a frame larger than 8K. */ - if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) { + if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { /* * Ensure that in the case of SM Dynamic power save * while we are bursting the second aggregate the @@ -832,7 +832,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) /* NB: cix is set above where RTS/CTS is enabled */ BUG_ON(cix == 0xff); ctsrate = rt->info[cix].rateCode | - (bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); /* * Setup HAL rate series @@ -846,7 +846,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) rix = bf->bf_rcs[i].rix; series[i].Rate = rt->info[rix].rateCode | - (bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0); + (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); series[i].Tries = bf->bf_rcs[i].tries; @@ -862,7 +862,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) sc, rix, bf, (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf->bf_shpreamble); + bf_isshpreamble(bf)); if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { @@ -875,7 +875,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) */ series[i].ChSel = sc->sc_tx_chainmask; } else { - if (bf->bf_ht) + if (bf_isht(bf)) series[i].ChSel = ath_chainmask_sel_logic(sc, an); else @@ -908,7 +908,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * use the precalculated ACK durations. */ if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[cix].spAckDuration : rt->info[cix].lpAckDuration; } @@ -916,7 +916,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) ctsduration += series[0].PktDuration; if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf->bf_shpreamble ? + ctsduration += bf_isshpreamble(bf) ? rt->info[rix].spAckDuration : rt->info[rix].lpAckDuration; } @@ -932,10 +932,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * set dur_update_en for l-sig computation except for PS-Poll frames */ ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf->bf_ispspoll, - ctsrate, - ctsduration, - series, 4, flags); + !bf_ispspoll(bf), + ctsrate, + ctsduration, + series, 4, flags); if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -958,7 +958,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 0; /* regular HT frame */ + bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); @@ -998,7 +998,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - ASSERT(!bf->bf_isretried); + ASSERT(!bf_isretried(bf)); list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); ath_tx_send_normal(sc, txq, tid, &bf_head); } @@ -1025,7 +1025,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, int isaggr, txfail, txpending, sendbar = 0, needreset = 0; int isnodegone = (an->an_flags & ATH_NODE_CLEAN); - isaggr = bf->bf_isaggr; + isaggr = bf_isaggr(bf); if (isaggr) { if (txok) { if (ATH_DS_TX_BA(ds)) { @@ -1075,7 +1075,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, ath_tx_set_retry(sc, bf); txpending = 1; } else { - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; txfail = 1; sendbar = 1; } @@ -1331,7 +1331,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) txq->axq_depth--; - if (bf->bf_isaggr) + if (bf_isaggr(bf)) txq->axq_aggr_depth--; txok = (ds->ds_txstat.ts_status == 0); @@ -1345,14 +1345,14 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_unlock_bh(&sc->sc_txbuflock); } - if (!bf->bf_isampdu) { + if (!bf_isampdu(bf)) { /* * This frame is sent out as a single frame. * Use hardware retry status for this frame. */ bf->bf_retries = ds->ds_txstat.ts_longretry; if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) - bf->bf_isxretried = 1; + bf->bf_state.bf_type |= BUF_XRETRY; nbad = 0; } else { nbad = ath_tx_num_badfrms(sc, bf, txok); @@ -1368,7 +1368,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (ds->ds_txstat.ts_status == 0) nacked++; - if (bf->bf_isdata) { + if (bf_isdata(bf)) { if (isrifs) tmp_ds = bf->bf_rifslast->bf_desc; else @@ -1384,7 +1384,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * Complete this transmit unit */ - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok); else ath_tx_complete_buf(sc, bf, &bf_head, txok, 0); @@ -1481,7 +1481,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, { int index, cindex; - if (bf->bf_isretried) + if (bf_isretried(bf)) return; index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno); @@ -1516,7 +1516,7 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_isampdu = 1; + bf->bf_state.bf_type |= BUF_AMPDU; bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ bf->bf_tidno = txctl->tidno; @@ -1860,7 +1860,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, if (bf->bf_nframes == 1) { ASSERT(bf->bf_lastfrm == bf_last); - bf->bf_isaggr = 0; + bf->bf_state.bf_type &= ~BUF_AGGR; /* * clear aggr bits for every descriptor * XXX TODO: is there a way to optimize it? @@ -1877,7 +1877,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, /* * setup first desc with rate and aggr info */ - bf->bf_isaggr = 1; + bf->bf_state.bf_type |= BUF_AGGR; ath_buf_set_rate(sc, bf); ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al); @@ -1925,7 +1925,7 @@ static void ath_tid_drain(struct ath_softc *sc, list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list); /* update baw for software retried frame */ - if (bf->bf_isretried) + if (bf_isretried(bf)) ath_tx_update_baw(sc, tid, bf->bf_seqno); /* @@ -2014,11 +2014,21 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* set up this buffer */ ATH_TXBUF_RESET(bf); bf->bf_frmlen = txctl->frmlen; - bf->bf_isdata = ieee80211_is_data(fc); - bf->bf_isbar = ieee80211_is_back_req(fc); - bf->bf_ispspoll = ieee80211_is_pspoll(fc); + + ieee80211_is_data(fc) ? + (bf->bf_state.bf_type |= BUF_DATA) : + (bf->bf_state.bf_type &= ~BUF_DATA); + ieee80211_is_back_req(fc) ? + (bf->bf_state.bf_type |= BUF_BAR) : + (bf->bf_state.bf_type &= ~BUF_BAR); + ieee80211_is_pspoll(fc) ? + (bf->bf_state.bf_type |= BUF_PSPOLL) : + (bf->bf_state.bf_type &= ~BUF_PSPOLL); + (sc->sc_flags & ATH_PREAMBLE_SHORT) ? + (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : + (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + bf->bf_flags = txctl->flags; - bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT; bf->bf_keytype = txctl->keytype; tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; rcs = tx_info_priv->rcs; @@ -2060,7 +2070,9 @@ static int ath_tx_start_dma(struct ath_softc *sc, ds); /* first descriptor */ bf->bf_lastfrm = bf; - bf->bf_ht = txctl->ht; + (txctl->ht) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); spin_lock_bh(&txq->axq_lock); @@ -2162,7 +2174,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) /* Setup tx descriptors */ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC); + "tx", nbufs * ATH_FRAG_PER_MSDU, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: failed to allocate tx descriptors: %d\n", @@ -2486,7 +2498,7 @@ void ath_tx_draintxq(struct ath_softc *sc, spin_unlock_bh(&txq->axq_lock); - if (bf->bf_isampdu) + if (bf_isampdu(bf)) ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0); else ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); @@ -2647,7 +2659,7 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, spin_lock_bh(&txq->axq_lock); while (!list_empty(&txtid->buf_q)) { bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); - if (!bf->bf_isretried) { + if (!bf_isretried(bf)) { /* * NB: it's based on the assumption that * software retried frame will always stay -- cgit v0.10.2 From 556bb8f141d702a84281064751a3242359a9f257 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:03:53 +0530 Subject: ath9k: Remove a few unnecessary macros Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 9e16c6c..19399da 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -396,8 +396,7 @@ int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, /* TX */ /******/ -#define ATH_FRAG_PER_MSDU 1 -#define ATH_TXBUF (512/ATH_FRAG_PER_MSDU) +#define ATH_TXBUF 512 /* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 /* max number of 11n transmit attempts (tries) */ @@ -551,10 +550,10 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); void ath_draintxq(struct ath_softc *sc, bool retry_tx); void ath_tx_draintxq(struct ath_softc *sc, - struct ath_txq *txq, bool retry_tx); + struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag); + struct ath_node *an, bool bh_flag); void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); @@ -579,7 +578,6 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, /* indicates the node is 80211 power save */ #define ATH_NODE_PWRSAVE 0x2 -#define ADDBA_TIMEOUT 200 /* 200 milliseconds */ #define ADDBA_EXCHANGE_ATTEMPTS 10 #define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ #define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ @@ -699,9 +697,6 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); #define ATH_BCBUF 4 /* number of beacon buffers */ #define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 -#define ATH_BEACON_AIFS_DEFAULT 0 /* Default aifs for ap beacon q */ -#define ATH_BEACON_CWMIN_DEFAULT 0 /* Default cwmin for ap beacon q */ -#define ATH_BEACON_CWMAX_DEFAULT 0 /* Default cwmax for ap beacon q */ #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) /* beacon configuration */ @@ -838,8 +833,6 @@ void ath_setdefantenna(void *sc, u32 antenna); #define ATH_PREAMBLE_SHORT (1<<0) #define ATH_PROTECT_ENABLE (1<<1) #define ATH_MAX_SW_RETRIES 10 -/* Num farmes difference in tx to flip default recv */ -#define ATH_ANTENNA_DIFF 2 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ #define IEEE80211_RATE_VAL 0x7f @@ -853,9 +846,7 @@ void ath_setdefantenna(void *sc, u32 antenna); */ #define ATH_KEYMAX 128 /* max key cache size we handle */ -#define RESET_RETRY_TXQ 0x00000001 #define ATH_IF_ID_ANY 0xff - #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ #define RSSI_LPF_THRESHOLD -20 diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 47cf9f3..a24a3a5 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2174,7 +2174,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) /* Setup tx descriptors */ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", nbufs * ATH_FRAG_PER_MSDU, 1); + "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, "%s: failed to allocate tx descriptors: %d\n", -- cgit v0.10.2 From d2d80ee9c6ae3d60bcbffb200959db645f5a558f Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:13 +0530 Subject: ath9k: Remove ar5416hal and assign default values directly Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index a17eb13..3d879e7 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -85,29 +85,6 @@ static const struct hal_percal_data adc_init_dc_cal = { ath9k_hw_adc_dccal_calibrate }; -static const struct ath_hal ar5416hal = { - AR5416_MAGIC, - 0, - 0, - NULL, - NULL, - CTRY_DEFAULT, - 0, - 0, - 0, - 0, - 0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }, -}; - static struct ath9k_rate_table ar5416_11a_table = { 8, {0}, @@ -1196,11 +1173,12 @@ static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, ah = &ahp->ah; - memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal)); - ah->ah_sc = sc; ah->ah_sh = mem; + ah->ah_magic = AR5416_MAGIC; + ah->ah_countryCode = CTRY_DEFAULT; + ah->ah_devid = devid; ah->ah_subvendorid = 0; -- cgit v0.10.2 From 6a2b9e8c8f4be9954933051719b312adcfb7263d Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:32 +0530 Subject: ath9k: Unused macros, variables Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index d1b0fba..3e7072d 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -790,19 +790,20 @@ struct ath_hal { u32 ah_magic; u16 ah_devid; u16 ah_subvendorid; - struct ath_softc *ah_sc; - void __iomem *ah_sh; - u16 ah_countryCode; u32 ah_macVersion; u16 ah_macRev; u16 ah_phyRev; u16 ah_analog5GhzRev; u16 ah_analog2GhzRev; - u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE]; - u32 ah_flags; + + void __iomem *ah_sh; + struct ath_softc *ah_sc; enum ath9k_opmode ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; + + u16 ah_countryCode; + u32 ah_flags; int16_t ah_powerLimit; u16 ah_maxPowerLevel; u32 ah_tpScale; @@ -812,15 +813,16 @@ struct ath_hal { u16 ah_currentRD5G; u16 ah_currentRD2G; char ah_iso[4]; - enum start_adhoc_option ah_adHocMode; - bool ah_commonMode; + struct ath9k_channel ah_channels[150]; - u32 ah_nchan; struct ath9k_channel *ah_curchan; + u32 ah_nchan; + u16 ah_rfsilent; bool ah_rfkillEnabled; bool ah_isPciExpress; u16 ah_txTrigLevel; + #ifndef ATH_NF_PER_CHAN struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; #endif diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index ae680f2..5cb3912 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -314,14 +314,11 @@ struct ar5416_desc { #define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ MS(ads->ds_rxstatus0, AR_RxRate) : \ (ads->ds_rxstatus3 >> 2) & 0xFF) -#define RXSTATUS_DUPLICATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus3, AR_Parallel40) : \ - (ads->ds_rxstatus3 >> 10) & 0x1) -#define set11nTries(_series, _index) \ +#define set11nTries(_series, _index) \ (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) -#define set11nRate(_series, _index) \ +#define set11nRate(_series, _index) \ (SM((_series)[_index].Rate, AR_XmitRate##_index)) #define set11nPktDurRTSCTS(_series, _index) \ @@ -330,11 +327,11 @@ struct ar5416_desc { AR_RTSCTSQual##_index : 0)) #define set11nRateFlags(_series, _index) \ - (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ - AR_2040_##_index : 0) \ - |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ - AR_GI##_index : 0) \ - |SM((_series)[_index].ChSel, AR_ChainSel##_index)) + (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \ + AR_2040_##_index : 0) \ + |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \ + AR_GI##_index : 0) \ + |SM((_series)[_index].ChSel, AR_ChainSel##_index)) #define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100) @@ -346,9 +343,6 @@ struct ar5416_desc { #define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1) #define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD -#define NUM_CORNER_FIX_BITS_2133 7 -#define CCK_OFDM_GAIN_DELTA 15 - struct ar5416AniState { struct ath9k_channel c; u8 noiseImmunityLevel; @@ -377,11 +371,8 @@ struct ar5416AniState { }; #define HAL_PROCESS_ANI 0x00000001 -#define HAL_RADAR_EN 0x80000000 -#define HAL_AR_EN 0x40000000 - #define DO_ANI(ah) \ - ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) + ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI)) struct ar5416Stats { u32 ast_ani_niup; @@ -425,7 +416,6 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 -#define AR5416_EEP_START_LOC 256 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 #define AR5416_NUM_5G_20_TARGET_POWERS 8 @@ -441,25 +431,10 @@ struct ar5416Stats { #define AR5416_EEPROM_MODAL_SPURS 5 #define AR5416_MAX_RATE_POWER 63 #define AR5416_NUM_PDADC_VALUES 128 -#define AR5416_NUM_RATES 16 #define AR5416_BCHAN_UNUSED 0xFF #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64 -#define AR5416_EEPMISC_BIG_ENDIAN 0x01 #define AR5416_MAX_CHAINS 3 -#define AR5416_ANT_16S 25 - -#define AR5416_NUM_ANT_CHAIN_FIELDS 7 -#define AR5416_NUM_ANT_COMMON_FIELDS 4 -#define AR5416_SIZE_ANT_CHAIN_FIELD 3 -#define AR5416_SIZE_ANT_COMMON_FIELD 4 -#define AR5416_ANT_CHAIN_MASK 0x7 -#define AR5416_ANT_COMMON_MASK 0xf -#define AR5416_CHAIN_0_IDX 0 -#define AR5416_CHAIN_1_IDX 1 -#define AR5416_CHAIN_2_IDX 2 - #define AR5416_PWR_TABLE_OFFSET -5 -#define AR5416_LEGACY_CHAINMASK 1 enum eeprom_param { EEP_NFTHRESH_5, @@ -633,7 +608,7 @@ struct ar5416IniArray { }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ - (iniarray)->ia_array = (u32 *)(array); \ + (iniarray)->ia_array = (u32 *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) @@ -641,16 +616,16 @@ struct ar5416IniArray { #define INI_RA(iniarray, row, column) \ (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) -#define INIT_CAL(_perCal) do { \ - (_perCal)->calState = CAL_WAITING; \ - (_perCal)->calNext = NULL; \ +#define INIT_CAL(_perCal) do { \ + (_perCal)->calState = CAL_WAITING; \ + (_perCal)->calNext = NULL; \ } while (0) #define INSERT_CAL(_ahp, _perCal) \ do { \ if ((_ahp)->ah_cal_list_last == NULL) { \ - (_ahp)->ah_cal_list = \ - (_ahp)->ah_cal_list_last = (_perCal); \ + (_ahp)->ah_cal_list = \ + (_ahp)->ah_cal_list_last = (_perCal); \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ } else { \ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \ @@ -696,25 +671,29 @@ struct hal_cal_list { struct ath_hal_5416 { struct ath_hal ah; struct ar5416_eeprom ah_eeprom; + struct ar5416Stats ah_stats; + struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; + void __iomem *ah_cal_mem; + u8 ah_macaddr[ETH_ALEN]; u8 ah_bssid[ETH_ALEN]; u8 ah_bssidmask[ETH_ALEN]; u16 ah_assocId; + int16_t ah_curchanRadIndex; u32 ah_maskReg; - struct ar5416Stats ah_stats; - u32 ah_txDescMask; u32 ah_txOkInterruptMask; u32 ah_txErrInterruptMask; u32 ah_txDescInterruptMask; u32 ah_txEolInterruptMask; u32 ah_txUrnInterruptMask; - struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; - enum ath9k_power_mode ah_powerMode; bool ah_chipFullSleep; u32 ah_atimWindow; - enum ath9k_ant_setting ah_diversityControl; u16 ah_antennaSwitchSwap; + enum ath9k_power_mode ah_powerMode; + enum ath9k_ant_setting ah_diversityControl; + + /* Calibration */ enum hal_cal_types ah_suppCals; struct hal_cal_list ah_iqCalData; struct hal_cal_list ah_adcGainCalData; @@ -751,16 +730,16 @@ struct ath_hal_5416 { int32_t sign[AR5416_MAX_CHAINS]; } ah_Meas3; u16 ah_CalSamples; - u32 ah_tx6PowerInHalfDbm; + u32 ah_staId1Defaults; u32 ah_miscMode; - bool ah_tpcEnabled; - u32 ah_beaconInterval; enum { AUTO_32KHZ, USE_32KHZ, DONT_USE_32KHZ, } ah_enable32kHzClock; + + /* RF */ u32 *ah_analogBank0Data; u32 *ah_analogBank1Data; u32 *ah_analogBank2Data; @@ -770,8 +749,9 @@ struct ath_hal_5416 { u32 *ah_analogBank7Data; u32 *ah_addac5416_21; u32 *ah_bank6Temp; - u32 ah_ofdmTxPower; + int16_t ah_txPowerIndexOffset; + u32 ah_beaconInterval; u32 ah_slottime; u32 ah_acktimeout; u32 ah_ctstimeout; @@ -780,7 +760,8 @@ struct ath_hal_5416 { u32 ah_gpioSelect; u32 ah_polarity; u32 ah_gpioBit; - bool ah_eepEnabled; + + /* ANI */ u32 ah_procPhyErr; bool ah_hasHwPhyCounters; u32 ah_aniPeriod; @@ -790,18 +771,14 @@ struct ath_hal_5416 { int ah_coarseHigh[5]; int ah_coarseLow[5]; int ah_firpwr[5]; - u16 ah_ratesArray[16]; + enum ath9k_ani_cmd ah_ani_function; + u32 ah_intrTxqs; bool ah_intrMitigation; - u32 ah_cycleCount; - u32 ah_ctlBusy; - u32 ah_extBusy; enum ath9k_ht_extprotspacing ah_extprotspacing; u8 ah_txchainmask; u8 ah_rxchainmask; - int ah_hwp; - void __iomem *ah_cal_mem; - enum ath9k_ani_cmd ah_ani_function; + struct ar5416IniArray ah_iniModes; struct ar5416IniArray ah_iniCommon; struct ar5416IniArray ah_iniBank0; @@ -820,10 +797,6 @@ struct ath_hal_5416 { #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) -#define IS_5416_EMU(ah) \ - ((ah->ah_devid == AR5416_DEVID_EMU) || \ - (ah->ah_devid == AR5416_DEVID_EMU_PCIE)) - #define ar5416RfDetach(ah) do { \ if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \ AH5416(ah)->ah_rfHal.rfDetach(ah); \ @@ -841,8 +814,8 @@ struct ath_hal_5416 { #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ int r; \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ - REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ - INI_RA((iniarray), r, (column))); \ + REG_WRITE(ah, INI_RA((iniarray), (r), 0), \ + INI_RA((iniarray), r, (column))); \ DO_DELAY(regWr); \ } \ } while (0) @@ -860,22 +833,17 @@ struct ath_hal_5416 { #define AR5416_EEPROM_S 2 #define AR5416_EEPROM_OFFSET 0x2000 -#define AR5416_EEPROM_START_ADDR \ +#define AR5416_EEPROM_START_ADDR \ (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 -#define ar5416_get_eep_ver(_ahp) \ +#define ar5416_get_eep_ver(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) -#define ar5416_get_eep_rev(_ahp) \ +#define ar5416_get_eep_rev(_ahp) \ (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) -#define ar5416_get_ntxchains(_txchainmask) \ +#define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) -#define IS_EEP_MINOR_V3(_ahp) \ - (ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_3) - -#define FIXED_CCA_THRESHOLD 15 - #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -910,8 +878,6 @@ struct ath_hal_5416 { #define AR_GPIOD_MASK 0x00001FFF #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) -#define MAX_ANALOG_START 319 - #define HAL_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) #define BEACON_RSSI(ahp) \ @@ -923,8 +889,6 @@ struct ath_hal_5416 { #define AH_TIMEOUT 100000 #define AH_TIME_QUANTUM 10 -#define IS(_c, _f) (((_c)->channelFlags & _f) || 0) - #define AR_KEYTABLE_SIZE 128 #define POWER_UP_TIME 200000 @@ -964,6 +928,6 @@ struct ath_hal_5416 { #define OFDM_SYMBOL_TIME_QUARTER 16 u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param); + enum eeprom_param param); #endif -- cgit v0.10.2 From b4696c8b9233bea812b972a5e79c5db7ecf13867 Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:04:52 +0530 Subject: ath9k: Use a single opmode variable ah_opmode and sc_opmode are redundant. This patch removes sc_opmode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 3e7072d..682d3bb 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -855,7 +855,7 @@ bool ath9k_regd_init_channels(struct ath_hal *ah, u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 67a8046..2736a4b 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -33,7 +33,7 @@ static int ath_beaconq_config(struct ath_softc *sc) struct ath9k_tx_queue_info qi; ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; @@ -85,7 +85,7 @@ static void ath_beacon_setup(struct ath_softc *sc, flags = ATH9K_TXDESC_NOACK; - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -375,7 +375,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -750,7 +750,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (if_id != ATH_IF_ID_ANY) av_opmode = sc->sc_vaps[if_id]->av_opmode; else - av_opmode = sc->sc_opmode; + av_opmode = sc->sc_ah->ah_opmode; memzero(&conf, sizeof(struct ath_beacon_config)); @@ -770,7 +770,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4), get_unaligned_le32(conf.u.last_tstamp)); /* XXX conditionalize multi-bss support? */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -791,7 +791,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", __func__, nexttbtt, intval, conf.beacon_interval); /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -911,7 +911,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath9k_hw_set_interrupts(ah, 0); if (nexttbtt == intval) intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { /* * Pull nexttbtt forward to reflect the current * TSF . @@ -943,7 +943,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) sc->sc_imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); - } else if (sc->sc_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -959,7 +959,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * When using a self-linked beacon descriptor in * ibss mode load it once here. */ - if (sc->sc_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 7f92d469..8359356 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -355,7 +355,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) fastcc = false; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan, + if (!ath9k_hw_reset(ah, hchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, @@ -533,7 +533,8 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(ah, rfilt); - if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN); ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); } else @@ -603,7 +604,7 @@ int ath_vap_attach(struct ath_softc *sc, sc->sc_vaps[if_id] = avp; sc->sc_nvaps++; /* Set the device opmode */ - sc->sc_opmode = opmode; + sc->sc_ah->ah_opmode = opmode; /* default VAP configuration */ avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; @@ -677,7 +678,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) int error = 0; enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", + __func__, sc->sc_ah->ah_opmode); /* * Stop anything previously setup. This is safe @@ -702,7 +704,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) sc->sc_curchan = *initial_chan; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, @@ -749,7 +751,8 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * Note we only do this (at the moment) for station mode. */ if (ath9k_hw_phycounters(ah) && - ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS))) + ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) sc->sc_imask |= ATH9K_INT_MIB; /* * Some hardware processes the TIM IE and fires an @@ -758,7 +761,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * enable the TIM interrupt when operating as station. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_opmode == ATH9K_M_STA) && + (sc->sc_ah->ah_opmode == ATH9K_M_STA) && !sc->sc_config.swBeaconProcess) sc->sc_imask |= ATH9K_INT_TIM; /* @@ -789,7 +792,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { @@ -1096,7 +1099,7 @@ int ath_init(u16 devid, struct ath_softc *sc) goto bad; /* default to STA mode */ - sc->sc_opmode = ATH9K_M_MONITOR; + sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; /* Setup rate tables */ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 19399da..bfe1623 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -895,15 +895,15 @@ struct ath_ht_info { struct ath_softc { struct ieee80211_hw *hw; struct pci_dev *pdev; - void __iomem *mem; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; struct ath_config sc_config; /* load-time parameters */ - int sc_debug; struct ath_hal *sc_ah; struct ath_rate_softc *sc_rc; /* tx rate control support */ + void __iomem *mem; + + int sc_debug; u32 sc_intrstatus; - enum ath9k_opmode sc_opmode; /* current operating mode */ unsigned int rx_filter; u8 sc_invalid; /* being detached */ u8 sc_beacons; /* beacons running */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 3d879e7..24b78c2 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -5839,7 +5839,7 @@ static inline bool ath9k_hw_init_cal(struct ath_hal *ah, } -bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, @@ -5953,7 +5953,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, | (ah->ah_config. ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ahp->ah_staId1Defaults); - ath9k_hw_set_operating_mode(ah, opmode); + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); @@ -5983,13 +5983,11 @@ bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode, for (i = 0; i < ah->ah_caps.total_queues; i++) ath9k_hw_resettxqueue(ah, i); - ath9k_hw_init_interrupt_masks(ah, opmode); + ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); ath9k_hw_init_user_settings(ah); - ah->ah_opmode = opmode; - REG_WRITE(ah, AR_STA_ID1, REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 262fd7a..7504b64 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -472,7 +472,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_rate_newstate(sc, avp); /* Reclaim beacon resources */ - if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || + sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); ath_beacon_return(sc, avp); } diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index a125849..6d1d503 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -184,7 +184,7 @@ static int ath_ampdu_input(struct ath_softc *sc, tid = qc[0] & 0xf; } - if (sc->sc_opmode == ATH9K_M_STA) { + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { /* Drop the frame not belonging to me. */ if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { dev_kfree_skb(skb); @@ -605,26 +605,26 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != ATH9K_M_STA) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_opmode != ATH9K_M_HOSTAP) && + if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_opmode == ATH9K_M_MONITOR)) { + (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (((sc->sc_opmode == ATH9K_M_STA) && + if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || - (sc->sc_opmode == ATH9K_M_IBSS)) + (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); return rfilt; @@ -905,7 +905,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * Enable this if you want to see * error frames in Monitor mode. */ - if (sc->sc_opmode != ATH9K_M_MONITOR) + if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) goto rx_next; #endif /* fall thru for monitor mode handling... */ @@ -950,7 +950,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (sc->sc_opmode == ATH9K_M_MONITOR) { + if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { if (ds->ds_rxstat.rs_status & ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | ATH9K_RXERR_CRC)) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index a24a3a5..0b5b2dd 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1047,7 +1047,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ - if (sc->sc_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == ATH9K_M_STA) needreset = 1; } } else { @@ -1454,7 +1454,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_opmode, + if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { -- cgit v0.10.2 From 672840ac04f79f499b60b9f0eb41799c837db4eb Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:08 +0530 Subject: ath9k: Use bitfields for sc operations Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 2736a4b..f1c4201 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -111,7 +111,7 @@ static void ath_beacon_setup(struct ath_softc *sc, rix = 0; rt = sc->sc_currates; rate = rt->info[rix].rateCode; - if (sc->sc_flags & ATH_PREAMBLE_SHORT) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].shortPreamble; ath9k_hw_set11n_txdesc(ah, ds @@ -975,5 +975,5 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id) * beacon frame we just received. */ ath_beacon_config(sc, if_id); - sc->sc_beacons = 1; + sc->sc_flags |= SC_OP_BEACONS; } diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 8359356..9b8258d 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -272,8 +272,8 @@ static int ath_stop(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n", - __func__, sc->sc_invalid); + DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", + __func__, sc->sc_flags & SC_OP_INVALID); /* * Shutdown the hardware and driver: @@ -291,10 +291,10 @@ static int ath_stop(struct ath_softc *sc) * hardware is gone (invalid). */ - if (!sc->sc_invalid) + if (!(sc->sc_flags & SC_OP_INVALID)) ath9k_hw_set_interrupts(ah, 0); ath_draintxq(sc, false); - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else @@ -316,7 +316,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) bool fastcc = true, stopped; enum ath9k_ht_macmode ht_macmode; - if (sc->sc_invalid) /* if the device is invalid or removed */ + if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ return -EIO; DPRINTF(sc, ATH_DBG_CONFIG, @@ -332,7 +332,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) if (hchan->channel != sc->sc_curchan.channel || hchan->channelFlags != sc->sc_curchan.channelFlags || - sc->sc_update_chainmask || sc->sc_full_reset) { + (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || + (sc->sc_flags & SC_OP_FULL_RESET)) { int status; /* * This is only performed if the channel settings have @@ -351,7 +352,7 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) * to flush data frames already in queue because of * changing channel. */ - if (!stopped || sc->sc_full_reset) + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) fastcc = false; spin_lock_bh(&sc->sc_resetlock); @@ -372,8 +373,8 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) spin_unlock_bh(&sc->sc_resetlock); sc->sc_curchan = *hchan; - sc->sc_update_chainmask = 0; - sc->sc_full_reset = 0; + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; /* Re-enable rx framework */ if (ath_startrecv(sc) != 0) { @@ -484,7 +485,7 @@ int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - sc->sc_update_chainmask = 1; + sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; if (is_ht) { sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; @@ -553,7 +554,7 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); /* need to reconfigure the beacons when it moves to RUN */ - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS; return 0; } @@ -773,7 +774,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) /* XXX: we must make sure h/w is ready and clear invalid flag * before turning on interrupt. */ - sc->sc_invalid = 0; + sc->sc_flags &= ~SC_OP_INVALID; done: return error; } @@ -816,7 +817,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_update_txpow(sc); - if (sc->sc_beacons) + if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ ath9k_hw_set_interrupts(ah, sc->sc_imask); @@ -841,7 +842,7 @@ int ath_suspend(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; /* No I/O if device has been surprise removed */ - if (sc->sc_invalid) + if (sc->sc_flags & SC_OP_INVALID) return -EIO; /* Shut off the interrupt before setting sc->sc_invalid to '1' */ @@ -849,7 +850,7 @@ int ath_suspend(struct ath_softc *sc) /* XXX: we must make sure h/w will not generate any interrupt * before setting the invalid flag. */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; /* disable HAL and put h/w to sleep */ ath9k_hw_disable(sc->sc_ah); @@ -870,7 +871,7 @@ irqreturn_t ath_isr(int irq, void *dev) bool sched = false; do { - if (sc->sc_invalid) { + if (sc->sc_flags & SC_OP_INVALID) { /* * The hardware is not ready/present, don't * touch anything. Note this can happen early @@ -1026,7 +1027,7 @@ int ath_init(u16 devid, struct ath_softc *sc) u32 rd; /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_invalid = 1; + sc->sc_flags |= SC_OP_INVALID; sc->sc_debug = DBG_DEFAULT; DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); @@ -1210,8 +1211,8 @@ int ath_init(u16 devid, struct ath_softc *sc) /* 11n Capabilities */ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_txaggr = 1; - sc->sc_rxaggr = 1; + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; } sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; @@ -1267,7 +1268,7 @@ void ath_deinit(struct ath_softc *sc) DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); ath_stop(sc); - if (!sc->sc_invalid) + if (!(sc->sc_flags & SC_OP_INVALID)) ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); ath_rate_detach(sc->sc_rc); /* cleanup tx queues */ @@ -1394,9 +1395,9 @@ void ath_newassoc(struct ath_softc *sc, /* if station reassociates, tear down the aggregation state. */ if (!isnew) { for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_tx_aggr_teardown(sc, an, tidno); - if (sc->sc_rxaggr) + if (sc->sc_flags & SC_OP_RXAGGR) ath_rx_aggr_teardown(sc, an, tidno); } } diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index bfe1623..702f7b8 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -830,8 +830,6 @@ void ath_setdefantenna(void *sc, u32 antenna); #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 #define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ -#define ATH_PREAMBLE_SHORT (1<<0) -#define ATH_PROTECT_ENABLE (1<<1) #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -892,25 +890,30 @@ struct ath_ht_info { u8 ext_chan_offset; }; +#define SC_OP_INVALID BIT(0) +#define SC_OP_BEACONS BIT(1) +#define SC_OP_RXAGGR BIT(2) +#define SC_OP_TXAGGR BIT(3) +#define SC_OP_CHAINMASK_UPDATE BIT(4) +#define SC_OP_FULL_RESET BIT(5) +#define SC_OP_PREAMBLE_SHORT BIT(6) +#define SC_OP_PROTECT_ENABLE BIT(7) + struct ath_softc { struct ieee80211_hw *hw; struct pci_dev *pdev; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; /* load-time parameters */ + struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; /* tx rate control support */ + struct ath_rate_softc *sc_rc; void __iomem *mem; int sc_debug; u32 sc_intrstatus; + u32 sc_flags; /* SC_OP_* */ unsigned int rx_filter; - u8 sc_invalid; /* being detached */ - u8 sc_beacons; /* beacons running */ - u8 sc_txaggr; /* enable 11n tx aggregation */ - u8 sc_rxaggr; /* enable 11n rx aggregation */ - u8 sc_update_chainmask; /* change chain mask */ - u8 sc_full_reset; /* force full reset */ + enum wireless_mode sc_curmode; /* current phy mode */ u16 sc_curtxpow; u16 sc_curaid; @@ -944,7 +947,6 @@ struct ath_softc { u8 sc_rxchaindetect_delta5GHz; u8 sc_rxchaindetect_delta2GHz; u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */ - u32 sc_flags; #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; #endif diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7504b64..7fb57ee 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -481,7 +481,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, /* Set interrupt mask */ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS; error = ath_vap_detach(sc, 0); if (error) @@ -582,7 +582,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, print_mac(mac, sc->sc_curbssid), sc->sc_curaid); /* need to reconfigure the beacon */ - sc->sc_beacons = 0; + sc->sc_flags &= ~SC_OP_BEACONS ; break; default: @@ -833,7 +833,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, /* Configure the beacon */ ath_beacon_config(sc, 0); - sc->sc_beacons = 1; + sc->sc_flags |= SC_OP_BEACONS; /* Reset rssi stats */ sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; @@ -896,9 +896,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, __func__, bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) - sc->sc_flags |= ATH_PREAMBLE_SHORT; + sc->sc_flags |= SC_OP_PREAMBLE_SHORT; else - sc->sc_flags &= ~ATH_PREAMBLE_SHORT; + sc->sc_flags &= ~SC_OP_PREAMBLE_SHORT; } if (changed & BSS_CHANGED_ERP_CTS_PROT) { @@ -907,9 +907,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) - sc->sc_flags |= ATH_PROTECT_ENABLE; + sc->sc_flags |= SC_OP_PROTECT_ENABLE; else - sc->sc_flags &= ~ATH_PROTECT_ENABLE; + sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } if (changed & BSS_CHANGED_HT) { diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 73c460a..20e1084 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1903,7 +1903,7 @@ static void ath_tx_aggr_resp(struct ath_softc *sc, int state; DECLARE_MAC_BUF(mac); - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return; txtid = ATH_AN_2_TID(an, tidno); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 6d1d503..9c75832 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -724,7 +724,7 @@ int ath_rx_input(struct ath_softc *sc, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status) { - if (is_ampdu && sc->sc_rxaggr) { + if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { *status = ATH_RX_CONSUMED; return ath_ampdu_input(sc, an, skb, rx_status); } else { @@ -1132,7 +1132,7 @@ int ath_rx_aggr_start(struct ath_softc *sc, rxtid = &an->an_aggr.rx.tid[tid]; spin_lock_bh(&rxtid->tidlock); - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { /* Allow aggregation reception * Adjust rx BA window size. Peer might indicate a * zero buffer size for a _dont_care_ condition. @@ -1232,7 +1232,7 @@ void ath_rx_aggr_teardown(struct ath_softc *sc, void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno; @@ -1264,7 +1264,7 @@ void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_rxaggr) { + if (sc->sc_flags & SC_OP_RXAGGR) { struct ath_arx_tid *rxtid; int tidno, i; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 0b5b2dd..75a8492 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -392,7 +392,7 @@ static int ath_tx_prepare(struct ath_softc *sc, * incremented by the fragmentation routine. */ if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && sc->sc_txaggr) { + txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(txctl->an, txctl->tidno); @@ -422,7 +422,7 @@ static int ath_tx_prepare(struct ath_softc *sc, /* * XXX not right with fragmentation. */ - if (sc->sc_flags & ATH_PREAMBLE_SHORT) + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) dur = rt->info[rix].spAckDuration; else dur = rt->info[rix].lpAckDuration; @@ -438,8 +438,9 @@ static int ath_tx_prepare(struct ath_softc *sc, ** Add time for next fragment. */ dur += ath9k_hw_computetxtime(sc->sc_ah, rt, - txctl->nextfraglen, - rix, sc->sc_flags & ATH_PREAMBLE_SHORT); + txctl->nextfraglen, + rix, + (sc->sc_flags & SC_OP_PREAMBLE_SHORT)); } if (ieee80211_has_morefrags(fc) || @@ -1406,7 +1407,7 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) /* * schedule any pending packets if aggregation is enabled */ - if (sc->sc_txaggr) + if (sc->sc_flags & SC_OP_TXAGGR) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } @@ -1433,7 +1434,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); /* XXX return value */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { ath_tx_stopdma(sc, &sc->sc_txq[i]); @@ -2024,7 +2025,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, ieee80211_is_pspoll(fc) ? (bf->bf_state.bf_type |= BUF_PSPOLL) : (bf->bf_state.bf_type &= ~BUF_PSPOLL); - (sc->sc_flags & ATH_PREAMBLE_SHORT) ? + (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); @@ -2076,7 +2077,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, spin_lock_bh(&txq->axq_lock); - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno); if (ath_aggr_query(sc, an, txctl->tidno)) { /* @@ -2153,7 +2154,7 @@ static void xmit_map_sg(struct ath_softc *sc, tx_status.retries = 0; tx_status.flags = ATH_TX_ERROR; - if (txctl->ht && sc->sc_txaggr) { + if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { /* Reclaim the seqno. */ tid = ATH_AN_2_TID((struct ath_node *) txctl->an, txctl->tidno); @@ -2505,7 +2506,7 @@ void ath_tx_draintxq(struct ath_softc *sc, } /* flush any pending frames if aggregation is enabled */ - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); ath_txq_drain_pending_buffers(sc, txq, @@ -2521,7 +2522,7 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) { /* stop beacon queue. The beacon will be freed when * we go to INIT state */ - if (!sc->sc_invalid) { + if (!(sc->sc_flags & SC_OP_INVALID)) { (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); @@ -2548,7 +2549,7 @@ enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, struct ath_atx_tid *txtid; DECLARE_MAC_BUF(mac); - if (!sc->sc_txaggr) + if (!(sc->sc_flags & SC_OP_TXAGGR)) return AGGR_NOT_REQUIRED; /* ADDBA exchange must be completed before sending aggregates */ @@ -2595,7 +2596,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, return -1; } - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); txtid->addba_exchangeinprogress = 1; ath_tx_pause_tid(sc, txtid); @@ -2755,7 +2756,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; struct ath_atx_ac *ac; int tidno, acno; @@ -2867,7 +2868,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_txaggr) { + if (sc->sc_flags & SC_OP_TXAGGR) { struct ath_atx_tid *tid; int tidno, i; -- cgit v0.10.2 From 7c56d24bc80112daadc7ef54247a5fc8397dbc5c Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:26 +0530 Subject: ath9k: Use ah_curchan and remove sc_curchan which is redundant Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 9b8258d..87b4ca5 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -322,16 +322,16 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) DPRINTF(sc, ATH_DBG_CONFIG, "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", __func__, - ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel, - sc->sc_curchan.channelFlags), - sc->sc_curchan.channel, + ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel, + sc->sc_ah->ah_curchan->channelFlags), + sc->sc_ah->ah_curchan->channel, ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags); ht_macmode = ath_cwm_macmode(sc); - if (hchan->channel != sc->sc_curchan.channel || - hchan->channelFlags != sc->sc_curchan.channelFlags || + if (hchan->channel != sc->sc_ah->ah_curchan->channel || + hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || (sc->sc_flags & SC_OP_FULL_RESET)) { int status; @@ -372,7 +372,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) } spin_unlock_bh(&sc->sc_resetlock); - sc->sc_curchan = *hchan; sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; sc->sc_flags &= ~SC_OP_FULL_RESET; @@ -702,16 +701,15 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - sc->sc_curchan = *initial_chan; spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, &sc->sc_curchan, ht_macmode, + if (!ath9k_hw_reset(ah, initial_chan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u " "(freq %u flags 0x%x)\n", __func__, status, - sc->sc_curchan.channel, sc->sc_curchan.channelFlags); + initial_chan->channel, initial_chan->channelFlags); error = -EIO; spin_unlock_bh(&sc->sc_resetlock); goto done; @@ -793,7 +791,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, &sc->sc_curchan, + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { @@ -813,7 +811,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) * that changes the channel so update any state that * might change as a result. */ - ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan)); + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); ath_update_txpow(sc); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 702f7b8..7f4bd15 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1001,7 +1001,6 @@ struct ath_softc { /* Channel, Band */ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - struct ath9k_channel sc_curchan; /* Locks */ spinlock_t sc_rxflushlock; diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 20e1084..1392361 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -847,9 +847,9 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) /* For half and quarter rate channles use different * rate tables */ - if (sc->sc_curchan.channelFlags & CHANNEL_HALF) + if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) ar5416_sethalf_ratetable(asc); - else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER) + else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) ar5416_setquarter_ratetable(asc); else /* full rate */ ar5416_setfull_ratetable(asc); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 75a8492..9ea5d93 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1456,7 +1456,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, - &sc->sc_curchan, ht_macmode, + sc->sc_ah->ah_curchan, ht_macmode, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { -- cgit v0.10.2 From 98deeea0b3464955ec416c30cbd0c3d21cacfa9a Mon Sep 17 00:00:00 2001 From: Sujith Date: Mon, 11 Aug 2008 14:05:46 +0530 Subject: ath9k: Trim struct ath_softc Add sc_rxflush and sc_noreset as bitfields to sc_flags. Remove a few variables and function prototypes that are unused. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index f1c4201..e0ca017 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -555,7 +555,7 @@ void ath9k_beacon_tasklet(unsigned long data) u32 tsftu; u16 intval; - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, &rx_clear, &rx_frame, @@ -577,7 +577,7 @@ void ath9k_beacon_tasklet(unsigned long data) * (in that layer). */ if (sc->sc_bmisscount < BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "%s: missed %u consecutive beacons\n", __func__, sc->sc_bmisscount); @@ -605,7 +605,7 @@ void ath9k_beacon_tasklet(unsigned long data) __func__, sc->sc_bmisscount); } } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { if (sc->sc_bmisscount == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, @@ -624,7 +624,7 @@ void ath9k_beacon_tasklet(unsigned long data) return; } if (sc->sc_bmisscount != 0) { - if (sc->sc_noreset) { + if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, "%s: resume beacon xmit after %u misses\n", diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 87b4ca5..0d953f9f 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1055,9 +1055,6 @@ int ath_init(u16 devid, struct ath_softc *sc) } sc->sc_ah = ah; - /* Get the chipset-specific aggr limit. */ - sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit; - /* Get the hardware key cache size. */ sc->sc_keymax = ah->ah_caps.keycache_size; if (sc->sc_keymax > ATH_KEYMAX) { @@ -1216,13 +1213,6 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - /* Configuration for rx chain detection */ - sc->sc_rxchaindetect_ref = 0; - sc->sc_rxchaindetect_thresh5GHz = 35; - sc->sc_rxchaindetect_thresh2GHz = 35; - sc->sc_rxchaindetect_delta5GHz = 30; - sc->sc_rxchaindetect_delta2GHz = 30; - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); sc->sc_defant = ath9k_hw_getdefantenna(ah); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 7f4bd15..8243ff0 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -724,11 +724,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); void ath_bstuck_process(struct ath_softc *sc); -void ath_beacon_tasklet(struct ath_softc *sc, int *needmark); -void ath_beacon_free(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi); void ath_get_beaconconfig(struct ath_softc *sc, int if_id, struct ath_beacon_config *conf); @@ -896,8 +893,10 @@ struct ath_ht_info { #define SC_OP_TXAGGR BIT(3) #define SC_OP_CHAINMASK_UPDATE BIT(4) #define SC_OP_FULL_RESET BIT(5) -#define SC_OP_PREAMBLE_SHORT BIT(6) -#define SC_OP_PROTECT_ENABLE BIT(7) +#define SC_OP_NO_RESET BIT(6) +#define SC_OP_PREAMBLE_SHORT BIT(7) +#define SC_OP_PROTECT_ENABLE BIT(8) +#define SC_OP_RXFLUSH BIT(9) struct ath_softc { struct ieee80211_hw *hw; @@ -909,44 +908,39 @@ struct ath_softc { struct ath_rate_softc *sc_rc; void __iomem *mem; + u8 sc_curbssid[ETH_ALEN]; + u8 sc_myaddr[ETH_ALEN]; + u8 sc_bssidmask[ETH_ALEN]; + int sc_debug; u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ unsigned int rx_filter; - - enum wireless_mode sc_curmode; /* current phy mode */ u16 sc_curtxpow; u16 sc_curaid; - u8 sc_curbssid[ETH_ALEN]; - u8 sc_myaddr[ETH_ALEN]; + u16 sc_cachelsz; + int sc_slotupdate; /* slot to next advance fsm */ + int sc_slottime; + int sc_bslot[ATH_BCBUF]; + u8 sc_tx_chainmask; + u8 sc_rx_chainmask; + enum ath9k_int sc_imask; + enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - u8 sc_mcastantenna; - u8 sc_txantenna; /* data tx antenna (fixed or auto) */ + u8 sc_nbcnvaps; /* # of vaps sending beacons */ u16 sc_nvaps; /* # of active virtual ap's */ struct ath_vap *sc_vaps[ATH_BCBUF]; - enum ath9k_int sc_imask; - u8 sc_bssidmask[ETH_ALEN]; + + u8 sc_mcastantenna; u8 sc_defant; /* current default antenna */ u8 sc_rxotherant; /* rx's on non-default antenna */ - u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - u8 sc_noreset; - int sc_bslot[ATH_BCBUF]; + struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ struct list_head node_list; struct ath_ht_info sc_ht_info; - int16_t sc_noise_floor; /* signal noise floor in dBm */ enum ath9k_ht_extprotspacing sc_ht_extprotspacing; - u8 sc_tx_chainmask; - u8 sc_rx_chainmask; - u8 sc_rxchaindetect_ref; - u8 sc_rxchaindetect_thresh5GHz; - u8 sc_rxchaindetect_thresh2GHz; - u8 sc_rxchaindetect_delta5GHz; - u8 sc_rxchaindetect_delta2GHz; - u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */ + #ifdef CONFIG_SLOW_ANT_DIV struct ath_antdiv sc_antdiv; #endif @@ -967,7 +961,6 @@ struct ath_softc { struct ath_descdma sc_rxdma; int sc_rxbufsize; /* rx size based on mtu */ u32 *sc_rxlink; /* link ptr in last RX desc */ - u32 sc_rxflush; /* rx flush in progress */ u64 sc_lastrx; /* tsf of last rx'd frame */ /* TX */ @@ -977,7 +970,6 @@ struct ath_softc { u32 sc_txqsetup; u32 sc_txintrperiod; /* tx interrupt batching */ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ - u32 sc_ant_tx[8]; /* recent tx frames/antenna */ /* Beacon */ struct ath9k_tx_queue_info sc_beacon_qi; @@ -1016,13 +1008,7 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); int ath_suspend(struct ath_softc *sc); irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); -void ath_scan_start(struct ath_softc *sc); -void ath_scan_end(struct ath_softc *sc); int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); -void ath_setup_rate(struct ath_softc *sc, - enum wireless_mode wMode, - enum RATE_TYPE type, - const struct ath9k_rate_table *rt); /*********************/ /* Utility Functions */ @@ -1041,7 +1027,6 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc); dma_addr_t ath_skb_map_single(struct ath_softc *sc, struct sk_buff *skb, int direction, @@ -1050,7 +1035,6 @@ void ath_skb_unmap_single(struct ath_softc *sc, struct sk_buff *skb, int direction, dma_addr_t *pa); -void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]); enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 9c75832..af2011f 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -504,7 +504,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) do { spin_lock_init(&sc->sc_rxflushlock); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->sc_rxbuflock); /* @@ -707,11 +707,11 @@ void ath_flushrecv(struct ath_softc *sc) * progress (see references to sc_rxflush) */ spin_lock_bh(&sc->sc_rxflushlock); - sc->sc_rxflush = 1; + sc->sc_flags |= SC_OP_RXFLUSH; ath_rx_tasklet(sc, 1); - sc->sc_rxflush = 0; + sc->sc_flags &= ~SC_OP_RXFLUSH; spin_unlock_bh(&sc->sc_rxflushlock); } @@ -755,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) do { /* If handling rx interrupt and flush is in progress => exit */ - if (sc->sc_rxflush && (flush == 0)) + if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; spin_lock_bh(&sc->sc_rxbuflock); diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 9ea5d93..e2ffa1cd 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -485,12 +485,8 @@ static int ath_tx_prepare(struct ath_softc *sc, if (is_multicast_ether_addr(hdr->addr1)) { antenna = sc->sc_mcastantenna + 1; sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; - } else - antenna = sc->sc_txantenna; + } -#ifdef USE_LEGACY_HAL - txctl->antenna = antenna; -#endif return 0; } @@ -743,7 +739,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) int i, flags, rtsctsena = 0, dynamic_mimops = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit; + u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; struct ath_node *an = (struct ath_node *) bf->bf_node; /* -- cgit v0.10.2 From 2ad67de3c8a21354b8b2721d5d2baabb7c5013c9 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:47 +0300 Subject: ath9k: Allow AP mode to be enabled Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 0d953f9f..9737775 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -549,9 +549,15 @@ int ath_vap_listen(struct ath_softc *sc, int if_id) * XXXX * Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(ah, - sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + ath9k_hw_set_interrupts(ah, sc->sc_imask & ~ATH9K_INT_BMISS); + sc->sc_imask &= ~ATH9K_INT_BMISS; + } else { + ath9k_hw_set_interrupts( + ah, + sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + } /* need to reconfigure the beacons when it moves to RUN */ sc->sc_flags &= ~SC_OP_BEACONS; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7fb57ee..183c76e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -426,10 +426,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, case IEEE80211_IF_TYPE_IBSS: ic_opmode = ATH9K_M_IBSS; break; + case IEEE80211_IF_TYPE_AP: + ic_opmode = ATH9K_M_HOSTAP; + break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Only STA and IBSS are supported currently\n", - __func__); + "%s: Interface type %d not yet supported\n", + __func__, conf->type); return -EOPNOTSUPP; } @@ -530,6 +533,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, struct ieee80211_if_conf *conf) { struct ath_softc *sc = hw->priv; + struct ath_hal *ah = sc->sc_ah; struct ath_vap *avp; u32 rfilt = 0; int error, i; @@ -542,6 +546,17 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, return -EINVAL; } + /* TODO: Need to decide which hw opmode to use for multi-interface + * cases */ + if (vif->type == IEEE80211_IF_TYPE_AP && + ah->ah_opmode != ATH9K_M_HOSTAP) { + ah->ah_opmode = ATH9K_M_HOSTAP; + ath9k_hw_setopmode(ah); + ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); + /* Request full reset to get hw opmode changed properly */ + sc->sc_flags |= SC_OP_FULL_RESET; + } + if ((conf->changed & IEEE80211_IFCC_BSSID) && !is_zero_ether_addr(conf->bssid)) { switch (vif->type) { -- cgit v0.10.2 From a8fff50e4d6aad520b261b3c32e2c67a7dfb7228 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:48 +0300 Subject: ath9k: Updated Beacon generation to use mac80211-style This change moves ath9k to use mac80211-generated Beacon frames instead of trying to allocate a single Beacon frame and then update it. In addition, the remaining ath_skb_{map,unmap}_single() wrapper calls are replaced with direct pci_{map,unmap}_single() calls in beacon.c. Power save buffering for multicast/broadcast frames is not yet converted to use mac80211-style (frames to be buffered inside mac80211, not in driver). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index e0ca017..8abcd3e 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -172,6 +172,7 @@ static void empty_mcastq_into_cabq(struct ath_hal *ah, mcastq->axq_link = NULL; } +/* TODO: use ieee80211_get_buffered_bc() to fetch power saved mcast frames */ /* This is only run at DTIM. We move everything from the vap's mcast queue * to the hardware cab queue. Caller must hold the mcastq lock. */ static void trigger_mcastq(struct ath_hal *ah, @@ -206,7 +207,6 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) int cabq_depth; int mcastq_depth; int is_beacon_dtim = 0; - unsigned int curlen; struct ath_txq *cabq; struct ath_txq *mcastq; avp = sc->sc_vaps[if_id]; @@ -223,33 +223,27 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) } bf = avp->av_bcbuf; skb = (struct sk_buff *) bf->bf_mpdu; + if (skb) { + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + } - /* - * Update dynamic beacon contents. If this returns - * non-zero then we need to remap the memory because - * the beacon frame changed size (probably because - * of the TIM bitmap). - */ - curlen = skb->len; + skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + bf->bf_mpdu = skb; + if (skb == NULL) + return NULL; + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); + /* TODO: convert to use ieee80211_get_buffered_bc() */ /* XXX: spin_lock_bh should not be used here, but sparse bitches * otherwise. We should fix sparse :) */ spin_lock_bh(&mcastq->axq_lock); mcastq_depth = avp->av_mcastq.axq_depth; - if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) == - 1) { - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); - } else { - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - skb_tailroom(skb), - PCI_DMA_TODEVICE); - } - /* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. @@ -262,7 +256,8 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); - is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; + if (avp->av_boff.bo_tim) + is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; if (mcastq_depth && is_beacon_dtim && cabq_depth) { /* @@ -408,8 +403,9 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -439,9 +435,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) __le64 val; int intval; - /* FIXME: Use default value for now: Sujith */ - - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; /* * The beacon interval is in TU's; the TSF in usecs. @@ -466,8 +461,10 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) memcpy(&wh[1], &val, sizeof(val)); } - bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = bf->bf_dmacontext = + pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); bf->bf_mpdu = skb; return 0; @@ -493,8 +490,9 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) bf = avp->av_bcbuf; if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -520,8 +518,9 @@ void ath_beacon_free(struct ath_softc *sc) list_for_each_entry(bf, &sc->sc_bbuf, list) { if (bf->bf_mpdu != NULL) { struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu; - ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + pci_unmap_single(sc->pdev, bf->bf_dmacontext, + skb_end_pointer(skb) - skb->head, + PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } @@ -643,8 +642,8 @@ void ath9k_beacon_tasklet(unsigned long data) * on the tsf to safeguard against missing an swba. */ - /* FIXME: Use default value for now - Sujith */ - intval = ATH_DEFAULT_BINTVAL; + intval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); @@ -760,7 +759,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) * Protocol stack doesn't support dynamic beacon configuration, * use default configurations. */ - conf.beacon_interval = ATH_DEFAULT_BINTVAL; + conf.beacon_interval = sc->hw->conf.beacon_int ? + sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL; conf.listen_interval = 1; conf.dtim_period = conf.beacon_interval; conf.dtim_count = 1; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 8243ff0..bf73194 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -729,11 +729,6 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id); void ath_get_beaconconfig(struct ath_softc *sc, int if_id, struct ath_beacon_config *conf); -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast); /********/ /* VAPs */ /********/ diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 183c76e..f904cf6 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -624,6 +624,18 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, ath_beacon_sync(sc, 0); } + if ((conf->changed & IEEE80211_IFCC_BEACON) && + (vif->type == IEEE80211_IF_TYPE_AP)) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + + error = ath_beacon_alloc(sc, 0); + if (error != 0) + return error; + + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; + } + /* Check for WLAN_CAPABILITY_PRIVACY ? */ if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) @@ -1052,15 +1064,6 @@ void ath_get_beaconconfig(struct ath_softc *sc, conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; } -int ath_update_beacon(struct ath_softc *sc, - int if_id, - struct ath_beacon_offset *bo, - struct sk_buff *skb, - int mcast) -{ - return 0; -} - void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ath_xmit_status *tx_status, struct ath_node *an) { -- cgit v0.10.2 From 580f0b8a6dc1cb4d32c351a507d1c1d319bdc1eb Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:49 +0300 Subject: ath9k: Fix TX status reporting Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f904cf6..4b61666 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1085,8 +1085,16 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; tx_status->flags &= ~ATH_TX_BAR; } - if (tx_status->flags) - tx_info->status.excessive_retries = 1; + + if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { + if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { + /* Frame was not ACKed, but an ACK was expected */ + tx_info->status.excessive_retries = 1; + } + } else { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } tx_info->status.retry_count = tx_status->retries; -- cgit v0.10.2 From 147583c057c43095925b5f331fe304f2d5b997ba Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:50 +0300 Subject: ath9k: Assign seq# when mac80211 requests this Use TX control flag IEEE80211_TX_CTL_ASSIGN_SEQ as a request to update the seq# for the frames. This will likely require some further cleanup to get seq# correctly for Beacons vs. other frames and also potentially for multiple BSSes. Anyway, this is better than ending up sending out most frames with seq# 0. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 8abcd3e..a020f9a 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -209,6 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) int is_beacon_dtim = 0; struct ath_txq *cabq; struct ath_txq *mcastq; + struct ieee80211_tx_info *info; avp = sc->sc_vaps[if_id]; mcastq = &avp->av_mcastq; @@ -233,6 +234,17 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) bf->bf_mpdu = skb; if (skb == NULL) return NULL; + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + /* + * TODO: make sure the seq# gets assigned properly (vs. other + * TX frames) + */ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb_end_pointer(skb) - skb->head, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index bf73194..c242942 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -965,6 +965,7 @@ struct ath_softc { u32 sc_txqsetup; u32 sc_txintrperiod; /* tx interrupt batching */ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ + u16 seq_no; /* TX sequence number */ /* Beacon */ struct ath9k_tx_queue_info sc_beacon_qi; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 4b61666..8fbde89 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -368,6 +368,20 @@ static int ath9k_tx(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } /* Add the padding after the header if this is not already done */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); -- cgit v0.10.2 From b14ecdd0afa4f616fcd1fcff4b902e15334256c7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Aug 2008 14:01:51 +0300 Subject: ath9k: Fix TX control flag use for no ACK and RTS/CTS Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index e2ffa1cd..55f3c8e 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -357,9 +357,9 @@ static int ath_tx_prepare(struct ath_softc *sc, txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - tx_info->flags |= ATH9K_TXDESC_NOACK; + txctl->flags |= ATH9K_TXDESC_NOACK; if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - tx_info->flags |= ATH9K_TXDESC_RTSENA; + txctl->flags |= ATH9K_TXDESC_RTSENA; /* * Setup for rate calculations. -- cgit v0.10.2 From 927e70e9244e6ecdc7c28bc5424b0b8c11dee314 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:26:34 +0530 Subject: ath9k: Remove remaining occurences of ath_skb_map functions Use direct pci functions instead. Also, use sc_ht_info.tx_chan_width directly and remove ath_cwm_macmode. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 9737775..a9e8ad0 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -314,7 +314,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) { struct ath_hal *ah = sc->sc_ah; bool fastcc = true, stopped; - enum ath9k_ht_macmode ht_macmode; if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ return -EIO; @@ -328,8 +327,6 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), hchan->channel, hchan->channelFlags); - ht_macmode = ath_cwm_macmode(sc); - if (hchan->channel != sc->sc_ah->ah_curchan->channel || hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || @@ -357,10 +354,11 @@ int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, hchan, - ht_macmode, sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - fastcc, &status)) { + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, + sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, + fastcc, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset channel %u (%uMhz) " "flags 0x%x hal status %u\n", __func__, @@ -682,7 +680,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_ah->ah_opmode); @@ -709,9 +706,10 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) */ spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, initial_chan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + if (!ath9k_hw_reset(ah, initial_chan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u " "(freq %u flags 0x%x)\n", __func__, status, @@ -788,7 +786,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) struct ath_hal *ah = sc->sc_ah; int status; int error = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ ath_draintxq(sc, retry_tx); /* stop xmit */ @@ -798,9 +795,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Reset chip */ spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u\n", __func__, status); diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index c242942..51bf528 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -1023,14 +1023,5 @@ int ath_cabq_update(struct ath_softc *); void ath_get_currentCountry(struct ath_softc *sc, struct ath9k_country_entry *ctry); u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa); -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index af2011f..91f6354 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -454,11 +454,10 @@ static int ath_rx_indicate(struct ath_softc *sc, nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); if (nskb != NULL) { bf->bf_mpdu = nskb; - bf->bf_buf_addr = ath_skb_map_single(sc, - nskb, - PCI_DMA_FROMDEVICE, - /* XXX: Remove get_dma_mem_context() */ - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, + skb_end_pointer(nskb) - nskb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; /* queue the new wbuf to H/W */ @@ -541,9 +540,10 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) } bf->bf_mpdu = skb; - bf->bf_buf_addr = - ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE, - get_dma_mem_context(bf, bf_dmacontext)); + bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, + skb_end_pointer(skb) - skb->head, + PCI_DMA_FROMDEVICE); + bf->bf_dmacontext = bf->bf_buf_addr; ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } sc->sc_rxlink = NULL; @@ -1297,27 +1297,3 @@ void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) { ath_rx_node_cleanup(sc, an); } - -dma_addr_t ath_skb_map_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* - * NB: do NOT use skb->len, which is 0 on initialization. - * Use skb's entire data area instead. - */ - *pa = pci_map_single(sc->pdev, skb->data, - skb_end_pointer(skb) - skb->head, direction); - return *pa; -} - -void ath_skb_unmap_single(struct ath_softc *sc, - struct sk_buff *skb, - int direction, - dma_addr_t *pa) -{ - /* Unmap skb's entire data area */ - pci_unmap_single(sc->pdev, *pa, - skb_end_pointer(skb) - skb->head, direction); -} diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 55f3c8e..8d31ad7 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -1427,7 +1427,6 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) struct ath_hal *ah = sc->sc_ah; int i; int npend = 0; - enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc); /* XXX return value */ if (!(sc->sc_flags & SC_OP_INVALID)) { @@ -1452,9 +1451,10 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, - sc->sc_ah->ah_curchan, ht_macmode, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, true, &status)) { + sc->sc_ah->ah_curchan, + sc->sc_ht_info.tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: unable to reset hardware; hal status %u\n", -- cgit v0.10.2 From dc2222a85fd63103b9aad0d4b77c4d87b78c58a2 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:26:55 +0530 Subject: ath9k: Random cleanup Remove dead code, add newlines, fix indentation. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index a9e8ad0..e3682b6 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -1025,7 +1025,6 @@ int ath_init(u16 devid, struct ath_softc *sc) int status; int error = 0, i; int csz = 0; - u32 rd; /* XXX: hardware will not be ready until ath_open() being called */ sc->sc_flags |= SC_OP_INVALID; @@ -1091,8 +1090,6 @@ int ath_init(u16 devid, struct ath_softc *sc) * is resposible for filtering this list based on settings * like the phy mode. */ - rd = ah->ah_currentRD; - error = ath_setup_channels(sc); if (error) goto bad; @@ -1169,7 +1166,7 @@ int ath_init(u16 devid, struct ath_softc *sc) sc->sc_rc = ath_rate_attach(ah); if (sc->sc_rc == NULL) { - error = EIO; + error = -EIO; goto bad2; } diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 24b78c2..7d8c908 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -7654,8 +7654,7 @@ bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) REG_WRITE(ah, AR_DRETRY_LIMIT(q), SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) - | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH) - ); + | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); REG_WRITE(ah, AR_DMISC(q), @@ -8300,15 +8299,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, *error = -ENXIO; break; } - if (ah != NULL) { - ah->ah_devid = ah->ah_devid; - ah->ah_subvendorid = ah->ah_subvendorid; - ah->ah_macVersion = ah->ah_macVersion; - ah->ah_macRev = ah->ah_macRev; - ah->ah_phyRev = ah->ah_phyRev; - ah->ah_analog5GhzRev = ah->ah_analog5GhzRev; - ah->ah_analog2GhzRev = ah->ah_analog2GhzRev; - } + return ah; } diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1392361..1dd7c71 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -653,8 +653,8 @@ ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); for (i = 0; i < rate_table->rate_cnt; i++) { valid = (ath_rc_priv->single_stream ? - rate_table->info[i].valid_single_stream : - rate_table->info[i].valid); + rate_table->info[i].valid_single_stream : + rate_table->info[i].valid); if (valid == TRUE) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; @@ -740,14 +740,14 @@ ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; u32 valid = (ath_rc_priv->single_stream ? - rate_table->info[j].valid_single_stream : - rate_table->info[j].valid); + rate_table->info[j].valid_single_stream : + rate_table->info[j].valid); if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || - !WLAN_RC_PHY_HT(phy) || - !WLAN_RC_PHY_HT_VALID(valid, capflag)) + mcs_set)->rs_rates[i] & 0x7F) != + (rate_table->info[j].dot11rate & 0x7F)) || + !WLAN_RC_PHY_HT(phy) || + !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) @@ -866,10 +866,10 @@ void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - int probe_allowed, int *is_probing, - int is_retry) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + int probe_allowed, int *is_probing, + int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -997,8 +997,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, rate = rate_ctrl->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || - (rate_table->info[rate].valid_single_stream && - ath_rc_priv->single_stream)); + (rate_table->info[rate].valid_single_stream && + ath_rc_priv->single_stream)); return rate; } @@ -1023,10 +1023,10 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 rix, u16 stepdown, - u16 min_rate) + struct ath_rate_node *ath_rc_priv, + const struct ath_rate_table *rate_table, + u8 rix, u16 stepdown, + u16 min_rate) { u32 j; u8 nextindex; @@ -1066,8 +1066,8 @@ static void ath_rc_ratefind(struct ath_softc *sc, rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, - is_probe, is_retry); + (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + is_probe, is_retry); nrix = rix; if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { @@ -1099,13 +1099,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_num = ((i + 1) == num_rates) ? num_tries - (try_per_rate * i) : try_per_rate ; min_rate = (((i + 1) == num_rates) && - (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; + (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; nrix = ath_rc_rate_getidx(sc, ath_rc_priv, - rate_table, nrix, 1, min_rate); + rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &series[i], try_num, nrix, TRUE); + &series[i], try_num, nrix, TRUE); } /* @@ -1124,13 +1124,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, * above conditions. */ if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { + (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || + (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || - (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { + (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { series[3].rix = series[2].rix; series[3].flags = series[2].flags; series[3].max_4ms_framelen = series[2].max_4ms_framelen; @@ -1152,7 +1152,8 @@ void ath_rate_findrate(struct ath_softc *sc, { struct ath_vap *avp = ath_rc_priv->avp; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + if (!num_rates || !num_tries) return; @@ -1174,9 +1175,8 @@ void ath_rate_findrate(struct ath_softc *sc, unsigned int mcs; u8 series_rix = 0; - series[idx].tries = - IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_retryset, idx); + series[idx].tries = IEEE80211_RATE_IDX_ENTRY( + avp->av_config.av_fixed_retryset, idx); mcs = IEEE80211_RATE_IDX_ENTRY( avp->av_config.av_fixed_rateset, idx); @@ -1228,7 +1228,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int state_change = FALSE, rate, count; u8 last_per; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table = (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; @@ -1272,14 +1272,14 @@ static void ath_rc_update_ht(struct ath_softc *sc, } else { /* xretries == 2 */ count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + sizeof(nretry_to_per_lookup[0]); if (retries >= count) retries = count - 1; /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ rate_ctrl->state[tx_rate].per = (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + (rate_ctrl->state[tx_rate].per >> 3) + + ((100) >> 3)); } /* xretries == 1 or 2 */ @@ -1295,8 +1295,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (retries >= count) retries = count - 1; if (info_priv->n_bad_frames) { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - /* + /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), * since the first retries attempts failed, and the @@ -1386,7 +1385,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, * rssi_ack values. */ if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { + rate_ctrl->hw_maxretry_pktcnt < 255) { rate_ctrl->hw_maxretry_pktcnt++; } @@ -1418,7 +1417,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Now reduce the current * rssi threshold. */ if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { + (rssi_thres > rssi_ack_vmin)) { rate_ctrl->state[tx_rate]. rssi_thres--; } @@ -1436,10 +1435,10 @@ static void ath_rc_update_ht(struct ath_softc *sc, * a while (except if we are probing). */ if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && - rate_table->info[tx_rate].ratekbps <= - rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { + rate_table->info[tx_rate].ratekbps <= + rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl, - (u8) tx_rate, &rate_ctrl->rate_max_phy); + (u8) tx_rate, &rate_ctrl->rate_max_phy); /* Don't probe for a little while. */ rate_ctrl->probe_time = now_msec; @@ -1460,43 +1459,43 @@ static void ath_rc_update_ht(struct ath_softc *sc, break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { rate_ctrl->state[rate+1].rssi_thres = rate_ctrl->state[rate]. - rssi_thres + + rssi_thres + rate_table->info[rate]. - rssi_ack_deltamin; + rssi_ack_deltamin; } } /* Make sure the rates below this have lower rssi thresholds. */ for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { + rate_table->info[rate].rssi_ack_deltamin > + rate_ctrl->state[rate+1].rssi_thres) { if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) + rate_table->info[rate]. + rssi_ack_deltamin) rate_ctrl->state[rate].rssi_thres = 0; else { rate_ctrl->state[rate].rssi_thres = rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + rssi_thres - + rate_table->info[rate]. + rssi_ack_deltamin; } if (rate_ctrl->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { + rate_table->info[rate]. + rssi_ack_validmin) { rate_ctrl->state[rate].rssi_thres = rate_table->info[rate]. - rssi_ack_validmin; + rssi_ack_validmin; } } } @@ -1507,11 +1506,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, if (rate_ctrl->state[tx_rate].per < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { + rate_ctrl->state[rate+1].per) { rate_ctrl->state[rate].per = rate_ctrl->state[rate+1].per; } @@ -1528,11 +1527,11 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->rssi_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { if (rate_ctrl->state[rate].rssi_thres > - rate_table->info[rate].rssi_ack_validmin) + rate_table->info[rate].rssi_ack_validmin) rate_ctrl->state[rate].rssi_thres -= 1; } rate_ctrl->rssi_down_time = now_msec; @@ -1541,7 +1540,7 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ if (now_msec - rate_ctrl->per_down_time >= - rate_table->rssi_reduce_interval) { + rate_table->rssi_reduce_interval) { for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { rate_ctrl->state[rate].per = 7 * rate_ctrl->state[rate].per / 8; @@ -1560,7 +1559,7 @@ static void ath_rc_update(struct ath_softc *sc, struct ath_tx_info_priv *info_priv, int final_ts_idx, int xretries, int long_retry) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; struct ath_tx_ratectrl *rate_ctrl; struct ath_rc_series rcs[4]; @@ -1637,7 +1636,6 @@ static void ath_rc_update(struct ath_softc *sc, xretries, long_retry); } - /* * Process a tx descriptor for a completed transmit (success or failure). */ @@ -1651,13 +1649,13 @@ static void ath_rate_tx_complete(struct ath_softc *sc, struct ath_vap *avp; avp = rc_priv->avp; - if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) - || info_priv->tx.ts_status & ATH9K_TXERR_FILT) + if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || + (info_priv->tx.ts_status & ATH9K_TXERR_FILT)) return; if (info_priv->tx.ts_rssi > 0) { ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - info_priv->tx.ts_rssi); + info_priv->tx.ts_rssi); } /* @@ -1682,7 +1680,6 @@ static void ath_rate_tx_complete(struct ath_softc *sc, info_priv->tx.ts_longretry); } - /* * Update the SIB's rate control information * @@ -1701,8 +1698,8 @@ static void ath_rc_sib_update(struct ath_softc *sc, struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rateset *rateset = negotiated_rates; u8 *ht_mcs = (u8 *)negotiated_htrates; - struct ath_tx_ratectrl *rate_ctrl = (struct ath_tx_ratectrl *) - (ath_rc_priv); + struct ath_tx_ratectrl *rate_ctrl = + (struct ath_tx_ratectrl *)ath_rc_priv; u8 i, j, k, hi = 0, hthi = 0; rate_table = (struct ath_rate_table *) @@ -1824,7 +1821,8 @@ static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta) struct ath_rate_node *rc_priv = sta->rate_ctrl_priv; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < sband->n_bitrates; i++) { if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) { @@ -1962,7 +1960,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ if (!ieee80211_is_data(fc) || - is_multicast_ether_addr(hdr->addr1) || !sta) { + is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate_idx = lowest_idx; return; } @@ -1978,7 +1976,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, false); if (is_probe) sel->probe_idx = ((struct ath_tx_ratectrl *) - sta->rate_ctrl_priv)->probe_rate; + sta->rate_ctrl_priv)->probe_rate; /* Ratecontrol sometimes returns invalid rate index */ if (tx_info_priv->rcs[0].rix != 0xff) @@ -2035,6 +2033,7 @@ static void ath_rate_init(void *priv, void *priv_sta, struct ieee80211_hw *hw = local_to_hw(local); struct ieee80211_conf *conf = &local->hw.conf; struct ath_softc *sc = hw->priv; + struct ath_rate_node *ath_rc_priv = priv_sta; int i, j = 0; DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); @@ -2046,12 +2045,11 @@ static void ath_rate_init(void *priv, void *priv_sta, if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { for (i = 0; i < MCS_SET_SIZE; i++) { if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) - ((struct ath_rate_node *) - priv_sta)->neg_ht_rates.rs_rates[j++] = i; + ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; } - ((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j; + ath_rc_priv->neg_ht_rates.rs_nrates = j; } ath_rc_node_update(hw, priv_sta); } @@ -2066,7 +2064,7 @@ static void *ath_rate_alloc(struct ieee80211_local *local) struct ieee80211_hw *hw = local_to_hw(local); struct ath_softc *sc = hw->priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); return local->hw.priv; } @@ -2081,14 +2079,17 @@ static void *ath_rate_alloc_sta(void *priv, gfp_t gfp) struct ath_vap *avp = sc->sc_vaps[0]; struct ath_rate_node *rate_priv; - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); + DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); if (!rate_priv) { - DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate" - "private rate control structure", __func__); + DPRINTF(sc, ATH_DBG_FATAL, + "%s: Unable to allocate private rc structure\n", + __func__); return NULL; } ath_rc_sib_init(rate_priv); + return rate_priv; } -- cgit v0.10.2 From ff9b662dab1fcd885fb728de3a8c13ebb5455117 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:27:16 +0530 Subject: ath9k: Miscellaneous fixes This patch removes ath_vap_listen() and dma wrapper macros. Also, Inline abuse is cleaned up and a few typos are fixed. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index a020f9a..89e5c65 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -114,21 +114,21 @@ static void ath_beacon_setup(struct ath_softc *sc, if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= rt->info[rix].shortPreamble; - ath9k_hw_set11n_txdesc(ah, ds - , skb->len + FCS_LEN /* frame length */ - , ATH9K_PKT_TYPE_BEACON /* Atheros packet type */ - , avp->av_btxctl.txpower /* txpower XXX */ - , ATH9K_TXKEYIX_INVALID /* no encryption */ - , ATH9K_KEY_TYPE_CLEAR /* no encryption */ - , flags /* no ack, veol for beacons */ + ath9k_hw_set11n_txdesc(ah, ds, + skb->len + FCS_LEN, /* frame length */ + ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ + avp->av_btxctl.txpower, /* txpower XXX */ + ATH9K_TXKEYIX_INVALID, /* no encryption */ + ATH9K_KEY_TYPE_CLEAR, /* no encryption */ + flags /* no ack, veol for beacons */ ); /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds - , roundup(skb->len, 4) /* buffer length */ - , true /* first segment */ - , true /* last segment */ - , ds /* first descriptor */ + ath9k_hw_filltxdesc(ah, ds, + roundup(skb->len, 4), /* buffer length */ + true, /* first segment */ + true, /* last segment */ + ds /* first descriptor */ ); memzero(series, sizeof(struct ath9k_11n_rate_series) * 4); @@ -551,7 +551,7 @@ void ath_beacon_free(struct ath_softc *sc) void ath9k_beacon_tasklet(unsigned long data) { -#define TSF_TO_TU(_h,_l) \ +#define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_softc *sc = (struct ath_softc *)data; @@ -898,19 +898,19 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "cfp:period %u " "maxdur %u " "next %u " - "timoffset %u\n" - , __func__ - , (unsigned long long)tsf, tsftu - , bs.bs_intval - , bs.bs_nexttbtt - , bs.bs_dtimperiod - , bs.bs_nextdtim - , bs.bs_bmissthreshold - , bs.bs_sleepduration - , bs.bs_cfpperiod - , bs.bs_cfpmaxduration - , bs.bs_cfpnext - , bs.bs_timoffset + "timoffset %u\n", + __func__, + (unsigned long long)tsf, tsftu, + bs.bs_intval, + bs.bs_nexttbtt, + bs.bs_dtimperiod, + bs.bs_nextdtim, + bs.bs_bmissthreshold, + bs.bs_sleepduration, + bs.bs_cfpperiod, + bs.bs_cfpmaxduration, + bs.bs_cfpnext, + bs.bs_timoffset ); ath9k_hw_set_interrupts(ah, 0); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index e3682b6..57645ee 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -51,10 +51,8 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz) * Set current operating mode * * This function initializes and fills the rate table in the ATH object based - * on the operating mode. The blink rates are also set up here, although - * they have been superceeded by the ath_led module. + * on the operating mode. */ - static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { const struct ath9k_rate_table *rt; @@ -232,7 +230,7 @@ static int ath_setup_channels(struct ath_softc *sc) * Determine mode from channel flags * * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If ho valid set of flags + * on the settings of the channel flags. If no valid set of flags * exist, the lowest mode (11b) is selected. */ @@ -257,7 +255,8 @@ static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) else if (chan->chanmode == CHANNEL_G_HT40MINUS) return ATH9K_MODE_11NG_HT40MINUS; - /* NB: should not get here */ + WARN_ON(1); /* should not get here */ + return ATH9K_MODE_11B; } @@ -278,8 +277,6 @@ static int ath_stop(struct ath_softc *sc) /* * Shutdown the hardware and driver: * stop output from above - * reset 802.11 state machine - * (sends station deassoc/deauth frames) * turn off timers * disable interrupts * clear transmit machinery @@ -499,69 +496,6 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) /* VAP management */ /******************/ -/* - * VAP in Listen mode - * - * This routine brings the VAP out of the down state into a "listen" state - * where it waits for association requests. This is used in AP and AdHoc - * modes. -*/ - -int ath_vap_listen(struct ath_softc *sc, int if_id) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - u32 rfilt = 0; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[if_id]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n", - __func__, if_id); - return -EINVAL; - } - -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif - - /* update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - - rfilt = ath_calcrxfilter(sc); - ath9k_hw_setrxfilter(ah, rfilt); - - if (sc->sc_ah->ah_opmode == ATH9K_M_STA || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { - memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN); - ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid); - } else - sc->sc_curaid = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, print_mac(mac, - sc->sc_curbssid), sc->sc_curaid); - - /* - * XXXX - * Disable BMISS interrupt when we're not associated - */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { - ath9k_hw_set_interrupts(ah, sc->sc_imask & ~ATH9K_INT_BMISS); - sc->sc_imask &= ~ATH9K_INT_BMISS; - } else { - ath9k_hw_set_interrupts( - ah, - sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - } - /* need to reconfigure the beacons when it moves to RUN */ - sc->sc_flags &= ~SC_OP_BEACONS; - - return 0; -} - int ath_vap_attach(struct ath_softc *sc, int if_id, struct ieee80211_vif *if_data, diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 51bf528..406225b 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -82,9 +82,6 @@ struct ath_node; /* XXX: remove */ #define memzero(_buf, _len) memset(_buf, 0, _len) -#define get_dma_mem_context(var, field) (&((var)->field)) -#define copy_dma_mem_context(dst, src) (*dst = *src) - #define ATH9K_BH_STATUS_INTACT 0 #define ATH9K_BH_STATUS_CHANGE 1 @@ -769,8 +766,7 @@ int ath_vap_attach(struct ath_softc *sc, enum ath9k_opmode opmode); int ath_vap_detach(struct ath_softc *sc, int if_id); int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config); -int ath_vap_listen(struct ath_softc *sc, int if_id); + int if_id, struct ath_vap_config *if_config); /*********************/ /* Antenna diversity */ diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 7d8c908..47c60ac 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -348,7 +348,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah) ah->ah_config.intr_mitigation = 0; } -static inline void ath9k_hw_override_ini(struct ath_hal *ah, +static void ath9k_hw_override_ini(struct ath_hal *ah, struct ath9k_channel *chan) { if (!AR_SREV_5416_V20_OR_LATER(ah) @@ -358,8 +358,8 @@ static inline void ath9k_hw_override_ini(struct ath_hal *ah, REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); } -static inline void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 synthDelay; @@ -374,8 +374,8 @@ static inline void ath9k_hw_init_bb(struct ath_hal *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum ath9k_opmode opmode) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -405,7 +405,7 @@ static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, } } -static inline void ath9k_hw_init_qos(struct ath_hal *ah) +static void ath9k_hw_init_qos(struct ath_hal *ah) { REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); @@ -500,7 +500,7 @@ static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, return ath9k_hw_eeprom_read(ah, off, data); } -static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); struct ar5416_eeprom *eep = &ahp->ah_eeprom; @@ -767,7 +767,7 @@ ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, return true; } -static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +static int ath9k_hw_check_eeprom(struct ath_hal *ah) { u32 sum = 0, el; u16 *eepdata; @@ -1272,7 +1272,7 @@ u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, } } -static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { u32 val; int i; @@ -1285,7 +1285,7 @@ static inline int ath9k_hw_get_radiorev(struct ath_hal *ah) return ath9k_hw_reverse_bits(val, 8); } -static inline int ath9k_hw_init_macaddr(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { u32 sum; int i; @@ -1367,7 +1367,7 @@ static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, return spur_val; } -static inline int ath9k_hw_rfattach(struct ath_hal *ah) +static int ath9k_hw_rfattach(struct ath_hal *ah) { bool rfStatus = false; int ecode = 0; @@ -1412,8 +1412,8 @@ static int ath9k_hw_rf_claim(struct ath_hal *ah) return 0; } -static inline void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { u32 pll; @@ -1531,7 +1531,7 @@ static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) } } -static inline void +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { u32 rfMode = 0; @@ -1601,7 +1601,7 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) return true; } -static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) { REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); @@ -1642,7 +1642,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, } } -static inline +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, struct ath9k_channel *chan) { @@ -2076,7 +2076,7 @@ static void ath9k_hw_ani_attach(struct ath_hal *ah) ahp->ah_procPhyErr |= HAL_PROCESS_ANI; } -static inline void ath9k_hw_ani_setup(struct ath_hal *ah) +static void ath9k_hw_ani_setup(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -2861,7 +2861,7 @@ static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) } } -static inline int ath9k_hw_post_attach(struct ath_hal *ah) +static int ath9k_hw_post_attach(struct ath_hal *ah) { int ecode; @@ -3573,7 +3573,7 @@ static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, return true; } -static inline void +static void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_data_per_freq *pRawDataSet, @@ -3755,7 +3755,7 @@ ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, return; } -static inline bool +static bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -3958,7 +3958,7 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) } } -static inline void +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_leg *powInfo, @@ -4024,7 +4024,7 @@ ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, } } -static inline void +static void ath9k_hw_get_target_powers(struct ath_hal *ah, struct ath9k_channel *chan, struct cal_target_power_ht *powInfo, @@ -4091,7 +4091,7 @@ ath9k_hw_get_target_powers(struct ath_hal *ah, } } -static inline u16 +static u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, bool is2GHz) @@ -4121,7 +4121,7 @@ ath9k_hw_get_max_edge_power(u16 freq, return twiceMaxEdgePower; } -static inline bool +static bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, struct ar5416_eeprom *pEepData, struct ath9k_channel *chan, @@ -5100,7 +5100,7 @@ static void ath9k_hw_spur_mitigate(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah) +static void ath9k_hw_init_chain_masks(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); int rx_chainmask, tx_chainmask; @@ -5304,7 +5304,7 @@ bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) } } -static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) +static void ath9k_hw_init_user_settings(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); @@ -5323,7 +5323,7 @@ static inline void ath9k_hw_init_user_settings(struct ath_hal *ah) ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); } -static inline int +static int ath9k_hw_process_ini(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5454,7 +5454,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, return 0; } -static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, +static void ath9k_hw_setup_calibration(struct ath_hal *ah, struct hal_cal_list *currCal) { REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), @@ -5490,8 +5490,8 @@ static inline void ath9k_hw_setup_calibration(struct ath_hal *ah, AR_PHY_TIMING_CTRL4_DO_CAL); } -static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) { struct ath_hal_5416 *ahp = AH5416(ah); int i; @@ -5510,7 +5510,7 @@ static inline void ath9k_hw_reset_calibration(struct ath_hal *ah, ahp->ah_CalSamples = 0; } -static inline void +static void ath9k_hw_per_calibration(struct ath_hal *ah, struct ath9k_channel *ichan, u8 rxchainmask, @@ -5600,7 +5600,7 @@ static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, return true; } -static inline bool +static bool ath9k_hw_channel_change(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode) @@ -5777,8 +5777,8 @@ static bool ath9k_hw_iscal_supported(struct ath_hal *ah, return retval; } -static inline bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); struct ath9k_channel *ichan = diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 8fbde89..605599e 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -212,12 +212,10 @@ static int ath_key_config(struct ath_softc *sc, static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) { -#define ATH_MAX_NUM_KEYS 4 int freeslot; - freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0; + freeslot = (key->keyidx >= 4) ? 1 : 0; ath_key_reset(sc, key->keyidx, freeslot); -#undef ATH_MAX_NUM_KEYS } static void setup_ht_cap(struct ieee80211_ht_info *ht_info) @@ -620,7 +618,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, } if ((conf->changed & IEEE80211_IFCC_BEACON) && - (vif->type == IEEE80211_IF_TYPE_IBSS)) { + ((vif->type == IEEE80211_IF_TYPE_IBSS) || + (vif->type == IEEE80211_IF_TYPE_AP))) { /* * Allocate and setup the beacon frame. * @@ -638,18 +637,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, ath_beacon_sync(sc, 0); } - if ((conf->changed & IEEE80211_IFCC_BEACON) && - (vif->type == IEEE80211_IF_TYPE_AP)) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); - - error = ath_beacon_alloc(sc, 0); - if (error != 0) - return error; - - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; - } - /* Check for WLAN_CAPABILITY_PRIVACY ? */ if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) { for (i = 0; i < IEEE80211_WEP_NKID; i++) diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 8d31ad7..04f94d2 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -499,7 +499,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; - dma_addr_t *pa; /* * Set retry information. @@ -519,9 +518,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, tx_status.flags |= ATH_TX_XRETRY; } /* Unmap this frame */ - pa = get_dma_mem_context(bf, bf_dmacontext); pci_unmap_single(sc->pdev, - *pa, + bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ @@ -1172,11 +1170,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, tbf->bf_lastfrm->bf_desc); /* copy the DMA context */ - copy_dma_mem_context( - get_dma_mem_context(tbf, - bf_dmacontext), - get_dma_mem_context(bf_last, - bf_dmacontext)); + tbf->bf_dmacontext = + bf_last->bf_dmacontext; } list_add_tail(&tbf->list, &bf_head); } else { @@ -1185,7 +1180,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * software retry */ ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_lastfrm->bf_desc); + bf->bf_lastfrm->bf_desc); } /* @@ -2045,8 +2040,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, /* * Save the DMA context in the first ath_buf */ - copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext), - get_dma_mem_context(txctl, dmacontext)); + bf->bf_dmacontext = txctl->dmacontext; /* * Formulate first tx descriptor with tx controls. @@ -2127,25 +2121,26 @@ static int ath_tx_start_dma(struct ath_softc *sc, static void xmit_map_sg(struct ath_softc *sc, struct sk_buff *skb, - dma_addr_t *pa, struct ath_tx_control *txctl) { struct ath_xmit_status tx_status; struct ath_atx_tid *tid; struct scatterlist sg; - *pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + txctl->dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); /* setup S/G list */ memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = *pa; + sg_dma_address(&sg) = txctl->dmacontext; sg_dma_len(&sg) = skb->len; if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) { /* * We have to do drop frame here. */ - pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE); + pci_unmap_single(sc->pdev, txctl->dmacontext, + skb->len, PCI_DMA_TODEVICE); tx_status.retries = 0; tx_status.flags = ATH_TX_ERROR; @@ -2419,9 +2414,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) * ath_tx_start_dma() will be called either synchronously * or asynchrounsly once DMA is complete. */ - xmit_map_sg(sc, skb, - get_dma_mem_context(&txctl, dmacontext), - &txctl); + xmit_map_sg(sc, skb, &txctl); else ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); -- cgit v0.10.2 From 18d7c65ba6628d2759bd650e7039d6307f2c99e9 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:27:41 +0530 Subject: mac80211: Add an 802.11n definition This patch adds a HT Capability (DSSS/CCK Mode in 40MHz BSS) definition to ieee80211.h Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 7f4df7c..be45645 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -714,6 +714,7 @@ struct ieee80211_ht_addt_info { #define IEEE80211_HT_CAP_SGI_40 0x0040 #define IEEE80211_HT_CAP_DELAY_BA 0x0400 #define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 /* 802.11n HT capability AMPDU settings */ #define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 #define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C -- cgit v0.10.2 From 60653678939dcbba3aa936250b58179aa3451eee Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:28:02 +0530 Subject: ath9k: Use definition from ieee80211.h Also, Max RX-ampdu and mpdu-density are ath9k specific. Rename appropriately. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 605599e..2b3b11b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -22,8 +22,6 @@ #define ATH_PCI_VERSION "0.1" #define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 -#define IEEE80211_ACTION_CAT_HT 7 -#define IEEE80211_ACTION_HT_TXCHWIDTH 0 static char *dev_info = "ath9k"; @@ -220,11 +218,8 @@ static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) static void setup_ht_cap(struct ieee80211_ht_info *ht_info) { -/* Until mac80211 includes these fields */ - -#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 -#define IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define IEEE80211_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ ht_info->ht_supported = 1; ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH @@ -232,8 +227,8 @@ static void setup_ht_cap(struct ieee80211_ht_info *ht_info) |(u16)IEEE80211_HT_CAP_SGI_40 |(u16)IEEE80211_HT_CAP_DSSSCCK40; - ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8; + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; /* setup supported mcs set */ memset(ht_info->supp_mcs_set, 0, 16); ht_info->supp_mcs_set[0] = 0xff; -- cgit v0.10.2 From 19b73c7f68fb2eeb180eafa70f9859409ec9aa08 Mon Sep 17 00:00:00 2001 From: Sujith Date: Thu, 14 Aug 2008 13:28:20 +0530 Subject: ath9k: Add IEEE80211_HW_RX_INCLUDES_FCS to hw flags Don't trim the FCS before passing the frame to mac80211, move TSF_TO_TU to core.h and delete more unused macros. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 682d3bb..18028a3 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -564,8 +564,6 @@ enum ath9k_cipher { #define CTL_5GHT40 8 #define AR_EEPROM_MAC(i) (0x1d+(i)) -#define EEP_SCALE 100 -#define EEP_DELTA 10 #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 @@ -606,9 +604,6 @@ struct ath9k_country_entry { #define REG_CLR_BIT(_a, _r, _f) \ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f) -#define ATH9K_COMP_BUF_MAX_SIZE 9216 -#define ATH9K_COMP_BUF_ALIGN_SIZE 512 - #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001 #define INIT_AIFS 2 @@ -637,7 +632,6 @@ struct ath9k_country_entry { IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN)) -#define MAX_REG_ADD_COUNT 129 #define MAX_RATE_POWER 63 enum ath9k_power_mode { @@ -707,13 +701,6 @@ enum phytype { }; #define PHY_CCK PHY_DS -enum start_adhoc_option { - START_ADHOC_NO_11A, - START_ADHOC_PER_11D, - START_ADHOC_IN_11A, - START_ADHOC_IN_11B, -}; - enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, ATH9K_TP_SCALE_50, diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 89e5c65..ee118562 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -551,9 +551,6 @@ void ath_beacon_free(struct ath_softc *sc) void ath9k_beacon_tasklet(unsigned long data) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) - struct ath_softc *sc = (struct ath_softc *)data; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf = NULL; @@ -715,7 +712,6 @@ void ath9k_beacon_tasklet(unsigned long data) sc->ast_be_xmit += bc; /* XXX per-vap? */ } -#undef TSF_TO_TU } /* @@ -751,8 +747,6 @@ void ath_bstuck_process(struct ath_softc *sc) void ath_beacon_config(struct ath_softc *sc, int if_id) { -#define TSF_TO_TU(_h,_l) \ - ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) struct ath_hal *ah = sc->sc_ah; u32 nexttbtt, intval; struct ath_beacon_config conf; @@ -975,7 +969,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } -#undef TSF_TO_TU } /* Function to collect beacon rssi data and resync beacon if necessary */ diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 406225b..ca7e613 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -79,6 +79,9 @@ struct ath_node; } \ } while (0) +#define TSF_TO_TU(_h,_l) \ + ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) + /* XXX: remove */ #define memzero(_buf, _len) memset(_buf, 0, _len) @@ -382,10 +385,10 @@ int ath_rx_input(struct ath_softc *sc, struct sk_buff *skb, struct ath_recv_status *rx_status, enum ATH_RX_TYPE *status); -int ath__rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); +int _ath_rx_indicate(struct ath_softc *sc, + struct sk_buff *skb, + struct ath_recv_status *status, + u16 keyix); int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, struct ath_recv_status *status); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 2b3b11b..55f4868 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1099,7 +1099,7 @@ void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); } -int ath__rx_indicate(struct ath_softc *sc, +int _ath_rx_indicate(struct ath_softc *sc, struct sk_buff *skb, struct ath_recv_status *status, u16 keyix) @@ -1119,9 +1119,6 @@ int ath__rx_indicate(struct ath_softc *sc, skb_pull(skb, padsize); } - /* remove FCS before passing up to protocol stack */ - skb_trim(skb, (skb->len - FCS_LEN)); - /* Prepare rx status */ ath9k_rx_prepare(sc, skb, status, &rx_status); @@ -1364,7 +1361,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad2; } - hw->flags = IEEE80211_HW_SIGNAL_DBM | + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; SET_IEEE80211_DEV(hw, &pdev->dev); diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 0cd399a..1470234 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -18,19 +18,19 @@ #define PHY_H bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah, - struct ath9k_channel - *chan); + struct ath9k_channel + *chan); bool ath9k_hw_set_channel(struct ath_hal *ah, - struct ath9k_channel *chan); + struct ath9k_channel *chan); void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex, int regWrites); bool ath9k_hw_set_rf_regs(struct ath_hal *ah, - struct ath9k_channel *chan, - u16 modesIndex); + struct ath9k_channel *chan, + u16 modesIndex); void ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan); bool ath9k_hw_init_rf(struct ath_hal *ah, - int *status); + int *status); #define AR_PHY_BASE 0x9800 #define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2)) diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 91f6354..6e13c63 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -448,7 +448,7 @@ static int ath_rx_indicate(struct ath_softc *sc, int type; /* indicate frame to the stack, which will free the old skb. */ - type = ath__rx_indicate(sc, skb, status, keyix); + type = _ath_rx_indicate(sc, skb, status, keyix); /* allocate a new skb and queue it to for H/W processing */ nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); -- cgit v0.10.2 From 43ac2ca3840f64f699a239535c590fa7ebaaac27 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 15 Aug 2008 22:21:27 +0300 Subject: mac80211: Handle scan result IEs in one block Clean up and extend scan result processing by storing all the IEs from Beacon/Probe Response frames in a single block instead of allocating memory for each specific IE separately. This removes lot of unnecessary code and automatically supports reporting of new IEs (e.g., IEEE 802.11r) into user space without need to manually extend mac80211 scanning code whenever a new protocol adds IE(s). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8361054..2bb5467 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -79,16 +79,11 @@ struct ieee80211_sta_bss { enum ieee80211_band band; int freq; int signal, noise, qual; - u8 *wpa_ie; - size_t wpa_ie_len; - u8 *rsn_ie; - size_t rsn_ie_len; - u8 *wmm_ie; - size_t wmm_ie_len; - u8 *ht_ie; - size_t ht_ie_len; - u8 *ht_add_ie; - size_t ht_add_ie_len; + u8 *ies; /* all information elements from the last Beacon or Probe + * Response frames; note Beacon frame is not allowed to + * override values from Probe Response */ + size_t ies_len; + bool wmm_used; #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; @@ -773,6 +768,9 @@ struct ieee80211_ra_tid { /* Parsed Information Elements */ struct ieee802_11_elems { + u8 *ie_start; + size_t total_len; + /* pointers to IEs */ u8 *ssid; u8 *supp_rates; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8499979..e088b44 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -98,6 +98,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, u8 *pos = start; memset(elems, 0, sizeof(*elems)); + elems->ie_start = start; + elems->total_len = len; while (left >= 2) { u8 id, elen; @@ -234,6 +236,27 @@ void ieee802_11_parse_elems(u8 *start, size_t len, } +static u8 * ieee80211_bss_get_ie(struct ieee80211_sta_bss *bss, u8 ie) +{ + u8 *end, *pos; + + pos = bss->ies; + if (pos == NULL) + return NULL; + end = pos + bss->ies_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == ie) + return pos; + pos += 2 + pos[1]; + } + + return NULL; +} + + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -737,7 +760,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *ies; + u8 *pos, *ies, *ht_add_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_sta_bss *bss; @@ -772,7 +795,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_ie) + if (bss->wmm_used) wmm = 1; /* get all rates supported by the device and the AP as @@ -894,9 +917,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, /* wmm support is a must to HT */ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && - sband->ht_info.ht_supported && bss->ht_add_ie) { + sband->ht_info.ht_supported && + (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { struct ieee80211_ht_addt_info *ht_add_info = - (struct ieee80211_ht_addt_info *)bss->ht_add_ie; + (struct ieee80211_ht_addt_info *)ht_add_ie; u16 cap = sband->ht_info.cap; __le16 tmp; u32 flags = local->hw.conf.channel->flags; @@ -2372,11 +2396,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) { - kfree(bss->wpa_ie); - kfree(bss->rsn_ie); - kfree(bss->wmm_ie); - kfree(bss->ht_ie); - kfree(bss->ht_add_ie); + kfree(bss->ies); kfree(bss_mesh_id(bss)); kfree(bss_mesh_cfg(bss)); kfree(bss); @@ -2662,43 +2682,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, bss->has_erp_value = 1; } - if (elems->ht_cap_elem && - (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len || - memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) { - kfree(bss->ht_ie); - bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC); - if (bss->ht_ie) { - memcpy(bss->ht_ie, elems->ht_cap_elem - 2, - elems->ht_cap_elem_len + 2); - bss->ht_ie_len = elems->ht_cap_elem_len + 2; - } else - bss->ht_ie_len = 0; - } else if (!elems->ht_cap_elem && bss->ht_ie) { - kfree(bss->ht_ie); - bss->ht_ie = NULL; - bss->ht_ie_len = 0; - } - - if (elems->ht_info_elem && - (!bss->ht_add_ie || - bss->ht_add_ie_len != elems->ht_info_elem_len || - memcmp(bss->ht_add_ie, elems->ht_info_elem, - elems->ht_info_elem_len))) { - kfree(bss->ht_add_ie); - bss->ht_add_ie = - kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC); - if (bss->ht_add_ie) { - memcpy(bss->ht_add_ie, elems->ht_info_elem - 2, - elems->ht_info_elem_len + 2); - bss->ht_add_ie_len = elems->ht_info_elem_len + 2; - } else - bss->ht_add_ie_len = 0; - } else if (!elems->ht_info_elem && bss->ht_add_ie) { - kfree(bss->ht_add_ie); - bss->ht_add_ie = NULL; - bss->ht_add_ie_len = 0; - } - bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); @@ -2749,88 +2732,17 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, return; } - if (elems->wpa && - (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len || - memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) { - kfree(bss->wpa_ie); - bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC); - if (bss->wpa_ie) { - memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2); - bss->wpa_ie_len = elems->wpa_len + 2; - } else - bss->wpa_ie_len = 0; - } else if (!elems->wpa && bss->wpa_ie) { - kfree(bss->wpa_ie); - bss->wpa_ie = NULL; - bss->wpa_ie_len = 0; - } - - if (elems->rsn && - (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len || - memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) { - kfree(bss->rsn_ie); - bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC); - if (bss->rsn_ie) { - memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2); - bss->rsn_ie_len = elems->rsn_len + 2; - } else - bss->rsn_ie_len = 0; - } else if (!elems->rsn && bss->rsn_ie) { - kfree(bss->rsn_ie); - bss->rsn_ie = NULL; - bss->rsn_ie_len = 0; + if (bss->ies == NULL || bss->ies_len < elems->total_len) { + kfree(bss->ies); + bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); } + if (bss->ies) { + memcpy(bss->ies, elems->ie_start, elems->total_len); + bss->ies_len = elems->total_len; + } else + bss->ies_len = 0; - /* - * Cf. - * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC - * - * quoting: - * - * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia - * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi - * Alliance (September 1, 2004) is incorporated by reference herein. - * The inclusion of the WMM Parameters in probe responses and - * association responses is mandatory for WMM enabled networks. The - * inclusion of the WMM Parameters in beacons, however, is optional. - */ - - if (elems->wmm_param && - (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len || - memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) { - kfree(bss->wmm_ie); - bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC); - if (bss->wmm_ie) { - memcpy(bss->wmm_ie, elems->wmm_param - 2, - elems->wmm_param_len + 2); - bss->wmm_ie_len = elems->wmm_param_len + 2; - } else - bss->wmm_ie_len = 0; - } else if (elems->wmm_info && - (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len || - memcmp(bss->wmm_ie, elems->wmm_info, - elems->wmm_info_len))) { - /* As for certain AP's Fifth bit is not set in WMM IE in - * beacon frames.So while parsing the beacon frame the - * wmm_info structure is used instead of wmm_param. - * wmm_info structure was never used to set bss->wmm_ie. - * This code fixes this problem by copying the WME - * information from wmm_info to bss->wmm_ie and enabling - * n-band association. - */ - kfree(bss->wmm_ie); - bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC); - if (bss->wmm_ie) { - memcpy(bss->wmm_ie, elems->wmm_info - 2, - elems->wmm_info_len + 2); - bss->wmm_ie_len = elems->wmm_info_len + 2; - } else - bss->wmm_ie_len = 0; - } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) { - kfree(bss->wmm_ie); - bss->wmm_ie = NULL; - bss->wmm_ie_len = 0; - } + bss->wmm_used = elems->wmm_param || elems->wmm_info; /* check if we need to merge IBSS */ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && @@ -4146,6 +4058,48 @@ int ieee80211_sta_req_scan(struct ieee80211_sub_if_data *sdata, u8 *ssid, size_t return 0; } + +static void ieee80211_sta_add_scan_ies(struct iw_request_info *info, + struct ieee80211_sta_bss *bss, + char **current_ev, char *end_buf) +{ + u8 *pos, *end, *next; + struct iw_event iwe; + + if (bss == NULL || bss->ies == NULL) + return; + + /* + * If needed, fragment the IEs buffer (at IE boundaries) into short + * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. + */ + pos = bss->ies; + end = pos + bss->ies_len; + + while (end - pos > IW_GENERIC_IE_MAX) { + next = pos + 2 + pos[1]; + while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) + next = next + 2 + next[1]; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = next - pos; + *current_ev = iwe_stream_add_point(info, *current_ev, + end_buf, &iwe, pos); + + pos = next; + } + + if (end > pos) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = end - pos; + *current_ev = iwe_stream_add_point(info, *current_ev, + end_buf, &iwe, pos); + } +} + + static char * ieee80211_sta_scan_result(struct ieee80211_local *local, struct iw_request_info *info, @@ -4225,29 +4179,7 @@ ieee80211_sta_scan_result(struct ieee80211_local *local, current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); - if (bss && bss->wpa_ie) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->wpa_ie); - } - - if (bss && bss->rsn_ie) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->rsn_ie); - } - - if (bss && bss->ht_ie) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->ht_ie_len; - current_ev = iwe_stream_add_point(info, current_ev, end_buf, - &iwe, bss->ht_ie); - } + ieee80211_sta_add_scan_ies(info, bss, ¤t_ev, end_buf); if (bss && bss->supp_rates_len > 0) { /* display all supported rates in readable format */ -- cgit v0.10.2 From 2f58bbf27fe5321a7a208be9071efc54e8a8a3bd Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 19 Aug 2008 15:44:35 +0200 Subject: mac80211: Use only precedence level of DSCP field for frame classification Bit 4-5 of DSCP should not be considered by classify_d1. The 802.11 QoS Priority field is only depending on the precedence level. Signed-off-by: Daniel Wagner Signed-off-by: John W. Linville diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 4310e2f..7229e95 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -47,8 +47,6 @@ static unsigned int classify_1d(struct sk_buff *skb) return 0; } - if (dscp & 0x1c) - return 0; return dscp >> 5; } -- cgit v0.10.2 From 095f695cbb07281682462da0618fffabb499d0be Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 19 Aug 2008 12:50:31 -0500 Subject: ssb: Update for Rev. 5 SPROM Although a revision 5 SPROM has not been seen in the wild, the open-source portion of the MIPS driver 4.150.10.5 describes its layout, which is mostly inherited from revision 4. This patch implements the differences. Signed-off-by: Larry Finger Acked-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index f883dcf..0de4b5e 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -399,14 +399,19 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) out->antenna_gain.ghz5.a3 = gain; } -static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in) +static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) { int i; u16 v; + u16 il0mac_offset; + if (out->revision == 4) + il0mac_offset = SSB_SPROM4_IL0MAC; + else + il0mac_offset = SSB_SPROM5_IL0MAC; /* extract the equivalent of the r1 variables */ for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM4_IL0MAC) + i]; + v = in[SPOFF(il0mac_offset) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { @@ -420,9 +425,15 @@ static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in) SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); - SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); - SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); - SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); + if (out->revision == 4) { + SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); + SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); + } else { + SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); + SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); + } SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, SSB_SPROM4_ANTAVAIL_A_SHIFT); SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, @@ -433,12 +444,21 @@ static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in) SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, SSB_SPROM4_ITSSI_A_SHIFT); - SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); - SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, - SSB_SPROM4_GPIOA_P1_SHIFT); - SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); - SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, - SSB_SPROM4_GPIOB_P3_SHIFT); + if (out->revision == 4) { + SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, + SSB_SPROM4_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, + SSB_SPROM4_GPIOB_P3_SHIFT); + } else { + SPEX(gpio0, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM5_GPIOA, SSB_SPROM5_GPIOA_P1, + SSB_SPROM5_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM5_GPIOB, SSB_SPROM5_GPIOB_P3, + SSB_SPROM5_GPIOB_P3_SHIFT); + } /* Extract the antenna gain values. */ SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01, @@ -471,16 +491,16 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, } else if (bus->chip_id == 0x4321) { /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */ out->revision = 4; - sprom_extract_r4(out, in); + sprom_extract_r45(out, in); } else { if (out->revision == 0) goto unsupported; if (out->revision >= 1 && out->revision <= 3) { sprom_extract_r123(out, in); } - if (out->revision == 4) - sprom_extract_r4(out, in); - if (out->revision >= 5) + if (out->revision == 4 || out->revision == 5) + sprom_extract_r45(out, in); + if (out->revision > 5) goto unsupported; } diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index ebad0ba..271bb4b 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -316,6 +316,21 @@ #define SSB_SPROM4_PA1B1 0x1090 #define SSB_SPROM4_PA1B2 0x1092 +/* SPROM Revision 5 (inherits most data from rev 4) */ +#define SSB_SPROM5_BFLLO 0x104A /* Boardflags (low 16 bits) */ +#define SSB_SPROM5_BFLHI 0x104C /* Board Flags Hi */ +#define SSB_SPROM5_IL0MAC 0x1052 /* 6 byte MAC address for a/b/g/n */ +#define SSB_SPROM5_CCODE 0x1044 /* Country Code (2 bytes) */ +#define SSB_SPROM5_GPIOA 0x1076 /* Gen. Purpose IO # 0 and 1 */ +#define SSB_SPROM5_GPIOA_P0 0x00FF /* Pin 0 */ +#define SSB_SPROM5_GPIOA_P1 0xFF00 /* Pin 1 */ +#define SSB_SPROM5_GPIOA_P1_SHIFT 8 +#define SSB_SPROM5_GPIOB 0x1078 /* Gen. Purpose IO # 2 and 3 */ +#define SSB_SPROM5_GPIOB_P2 0x00FF /* Pin 2 */ +#define SSB_SPROM5_GPIOB_P3 0xFF00 /* Pin 3 */ +#define SSB_SPROM5_GPIOB_P3_SHIFT 8 + + /* Values for SSB_SPROM1_BINF_CCODE */ enum { SSB_SPROM1CCODE_WORLD = 0, -- cgit v0.10.2 From 87c8c72d532f96257162f978d5945dcf7f0df19e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Aug 2008 15:15:35 -0400 Subject: libertas: convert CMD_802_11_RF_TX_POWER to a direct command And while we're at it, grab min/max TX power from the firmware and use that to validate incoming TX power requests from WEXT. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index af5fd70..c0db988 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -614,47 +614,67 @@ static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_cmd_802_11_rf_tx_power(struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +/** + * @brief Get the min, max, and current TX power + * + * @param priv A pointer to struct lbs_private structure + * @param curlevel Current power level in dBm + * @param minlevel Minimum supported power level in dBm (optional) + * @param maxlevel Maximum supported power level in dBm (optional) + * + * @return 0 on success, error on failure + */ +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel) { - - struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER); - prtp->action = cpu_to_le16(cmd_action); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); + if (ret == 0) { + *curlevel = le16_to_cpu(cmd.curlevel); + if (minlevel) + *minlevel = le16_to_cpu(cmd.minlevel); + if (maxlevel) + *maxlevel = le16_to_cpu(cmd.maxlevel); + } - lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", - le16_to_cpu(cmd->size), le16_to_cpu(cmd->command), - le16_to_cpu(prtp->action)); + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} - switch (cmd_action) { - case CMD_ACT_TX_POWER_OPT_GET: - prtp->action = cpu_to_le16(CMD_ACT_GET); - prtp->currentlevel = 0; - break; +/** + * @brief Set the TX power + * + * @param priv A pointer to struct lbs_private structure + * @param dbm The desired power level in dBm + * + * @return 0 on success, error on failure + */ +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) +{ + struct cmd_ds_802_11_rf_tx_power cmd; + int ret; - case CMD_ACT_TX_POWER_OPT_SET_HIGH: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH); - break; + lbs_deb_enter(LBS_DEB_CMD); - case CMD_ACT_TX_POWER_OPT_SET_MID: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID); - break; + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + cmd.curlevel = cpu_to_le16(dbm); - case CMD_ACT_TX_POWER_OPT_SET_LOW: - prtp->action = cpu_to_le16(CMD_ACT_SET); - prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); - break; - } + lbs_deb_cmd("SET_RF_TX_POWER: %d dBm\n", dbm); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_TX_POWER, &cmd); lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } static int lbs_cmd_802_11_monitor_mode(struct cmd_ds_command *cmd, @@ -1420,11 +1440,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_reg_access(cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_RF_TX_POWER: - ret = lbs_cmd_802_11_rf_tx_power(cmdptr, - cmd_action, pdata_buf); - break; - case CMD_802_11_MONITOR_MODE: ret = lbs_cmd_802_11_monitor_mode(cmdptr, cmd_action, pdata_buf); diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index a53b51f..6fba8ef 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -61,4 +61,8 @@ int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, int lbs_cmd_802_11_key_material(struct lbs_private *priv, uint16_t cmd_action, struct assoc_request *assoc); +int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, + s16 *maxlevel); +int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 24de3c3..dfaf03a 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -188,21 +188,6 @@ static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, return 0; } -static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - - lbs_deb_enter(LBS_DEB_CMD); - - priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); - - lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -287,10 +272,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_snmp_mib(priv, resp); break; - case CMD_RET(CMD_802_11_RF_TX_POWER): - ret = lbs_ret_802_11_rf_tx_power(priv, resp); - break; - case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): spin_lock_irqsave(&priv->driver_lock, flags); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f5bb40c..560d4d3 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -253,7 +253,9 @@ struct lbs_private { u32 connect_status; u32 mesh_connect_status; u16 regioncode; - u16 txpowerlevel; + s16 txpower_cur; + s16 txpower_min; + s16 txpower_max; /** POWER MANAGEMENT AND PnP SUPPORT */ u8 surpriseremoved; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index c92e41b..413030f 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -178,16 +178,6 @@ #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 #define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 -/* Define action or option for CMD_802_11_RF_TX_POWER */ -#define CMD_ACT_TX_POWER_OPT_GET 0x0000 -#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 -#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 -#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 - -#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 -#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 -#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 - /* Define action or option for CMD_802_11_DATA_RATE */ #define CMD_ACT_SET_TX_AUTO 0x0000 #define CMD_ACT_SET_TX_FIX_RATE 0x0001 diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 913b480..7f155cd 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -435,8 +435,12 @@ struct cmd_ds_802_11_mac_address { }; struct cmd_ds_802_11_rf_tx_power { + struct cmd_header hdr; + __le16 action; - __le16 currentlevel; + __le16 curlevel; + s8 maxlevel; + s8 minlevel; }; struct cmd_ds_802_11_rf_antenna { @@ -701,7 +705,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_snmp_mib smib; - struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; struct cmd_ds_802_11_ad_hoc_join adj; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index bd32ac0..3c13619 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -956,17 +956,24 @@ EXPORT_SYMBOL_GPL(lbs_resume); static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; + s16 curlevel = 0, minlevel = 0, maxlevel = 0; lbs_deb_enter(LBS_DEB_FW); - /* - * Read MAC address from HW - */ + /* Read MAC address from firmware */ memset(priv->current_addr, 0xff, ETH_ALEN); ret = lbs_update_hw_spec(priv); if (ret) goto done; + /* Read power levels if available */ + ret = lbs_get_tx_power(priv, &curlevel, &minlevel, &maxlevel); + if (ret == 0) { + priv->txpower_cur = curlevel; + priv->txpower_min = minlevel; + priv->txpower_max = maxlevel; + } + lbs_set_mac_control(priv); done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 8b3ed77..10a8066 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -422,26 +422,24 @@ static int lbs_get_txpow(struct net_device *dev, { int ret = 0; struct lbs_private *priv = dev->priv; + s16 curlevel = 0; lbs_deb_enter(LBS_DEB_WEXT); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); - + ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); if (ret) goto out; - lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); - vwrq->value = priv->txpowerlevel; + lbs_deb_wext("tx power level %d dbm\n", curlevel); + + priv->txpower_cur = curlevel; + vwrq->value = curlevel; vwrq->fixed = 1; if (priv->radioon) { vwrq->disabled = 0; vwrq->flags = IW_TXPOW_DBM; - } else { + } else vwrq->disabled = 1; - } out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -693,22 +691,12 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, range->sensitivity = 0; - /* - * Setup the supported power level ranges - */ + /* Setup the supported power level ranges */ memset(range->txpower, 0, sizeof(range->txpower)); - range->txpower[0] = 5; - range->txpower[1] = 7; - range->txpower[2] = 9; - range->txpower[3] = 11; - range->txpower[4] = 13; - range->txpower[5] = 15; - range->txpower[6] = 17; - range->txpower[7] = 19; - - range->num_txpower = 8; - range->txpower_capa = IW_TXPOW_DBM; - range->txpower_capa |= IW_TXPOW_RANGE; + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = priv->txpower_min; + range->txpower[1] = priv->txpower_max; + range->num_txpower = 2; range->event_capa[0] = (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | @@ -1844,39 +1832,46 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, { int ret = 0; struct lbs_private *priv = dev->priv; - - u16 dbm; + s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { lbs_radio_ioctl(priv, RADIO_OFF); - return 0; + goto out; } - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; - - lbs_radio_ioctl(priv, RADIO_ON); + if (vwrq->fixed == 0) { + /* Auto power control */ + priv->preamble = CMD_TYPE_AUTO_PREAMBLE; + dbm = priv->txpower_max; + } else { + /* Userspace check in iwrange if it should use dBm or mW, + * therefore this should never happen... Jean II */ + if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + ret = -EOPNOTSUPP; + goto out; + } - /* Userspace check in iwrange if it should use dBm or mW, - * therefore this should never happen... Jean II */ - if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { - return -EOPNOTSUPP; - } else - dbm = (u16) vwrq->value; + /* Validate requested power level against firmware allowed levels */ + if (priv->txpower_min && (dbm < priv->txpower_min)) { + ret = -EINVAL; + goto out; + } - /* auto tx power control */ + if (priv->txpower_max && (dbm > priv->txpower_max)) { + ret = -EINVAL; + goto out; + } + } - if (vwrq->fixed == 0) - dbm = 0xffff; + lbs_radio_ioctl(priv, RADIO_ON); - lbs_deb_wext("txpower set %d dbm\n", dbm); + lbs_deb_wext("txpower set %d dBm\n", dbm); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RF_TX_POWER, - CMD_ACT_TX_POWER_OPT_SET_LOW, - CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); + ret = lbs_set_tx_power(priv, dbm); +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -- cgit v0.10.2 From 191bb40e725304c5fcfabd92c57eef58799f0e25 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 17:46:18 -0400 Subject: libertas: convert CMD_802_11_DEAUTHENTICATE to a direct command and remove DISASSOCIATE because it's not in any of the specs and has never been used. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index a267d6e..5072a89 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1029,7 +1029,9 @@ void lbs_association_worker(struct work_struct *work) */ if (priv->mode == IW_MODE_INFRA) { if (should_deauth_infrastructure(priv, assoc_req)) { - ret = lbs_send_deauthentication(priv); + ret = lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); if (ret) { lbs_deb_assoc("Deauthentication due to new " "configuration request failed: %d\n", @@ -1290,18 +1292,6 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len) } /** - * @brief Send Deauthentication Request - * - * @param priv A pointer to struct lbs_private structure - * @return 0--success, -1--fail - */ -int lbs_send_deauthentication(struct lbs_private *priv) -{ - return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); -} - -/** * @brief This function prepares command of authenticate. * * @param priv A pointer to struct lbs_private structure @@ -1353,26 +1343,37 @@ out: return ret; } -int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd) +/** + * @brief Deauthenticate from a specific BSS + * + * @param priv A pointer to struct lbs_private structure + * @param bssid The specific BSS to deauthenticate from + * @param reason The 802.11 sec. 7.3.1.7 Reason Code for deauthenticating + * + * @return 0 on success, error on failure + */ +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], + u16 reason) { - struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; + struct cmd_ds_802_11_deauthenticate cmd; + int ret; lbs_deb_enter(LBS_DEB_JOIN); - cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + - S_DS_GEN); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.macaddr, &bssid[0], ETH_ALEN); + cmd.reasoncode = cpu_to_le16(reason); - /* set AP MAC address */ - memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); - /* Reason code 3 = Station is leaving */ -#define REASON_CODE_STA_LEAVING 3 - dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); + /* Clean up everything even if there was an error; can't assume that + * we're still authenticated to the AP after trying to deauth. + */ + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); - return 0; + return ret; } int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -1815,16 +1816,6 @@ done: return ret; } -int lbs_ret_80211_disassociate(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} - int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp) { diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index c516fbe..92ba2c2 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -20,7 +20,7 @@ int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, - struct cmd_ds_command *cmd); + u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); @@ -28,12 +28,9 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); -int lbs_ret_80211_disassociate(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); int lbs_stop_adhoc_network(struct lbs_private *priv); -int lbs_send_deauthentication(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index c0db988..8364a2f 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1413,10 +1413,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_DEAUTHENTICATE: - ret = lbs_cmd_80211_deauthenticate(priv, cmdptr); - break; - case CMD_802_11_AD_HOC_START: ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index dfaf03a..c94604c 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -258,11 +258,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_DISASSOCIATE): - case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = lbs_ret_80211_disassociate(priv); - break; - case CMD_RET(CMD_802_11_AD_HOC_START): case CMD_RET(CMD_802_11_AD_HOC_JOIN): ret = lbs_ret_80211_ad_hoc_start(priv, resp); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 413030f..caebb9b 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -61,7 +61,6 @@ #define CMD_RF_REG_MAP 0x0023 #define CMD_802_11_DEAUTHENTICATE 0x0024 #define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_802_11_DISASSOCIATE 0x0026 #define CMD_MAC_CONTROL 0x0028 #define CMD_802_11_AD_HOC_START 0x002b #define CMD_802_11_AD_HOC_JOIN 0x002c diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 7f155cd..342c2e3 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -232,7 +232,9 @@ struct cmd_ds_802_11_authenticate { }; struct cmd_ds_802_11_deauthenticate { - u8 macaddr[6]; + struct cmd_header hdr; + + u8 macaddr[ETH_ALEN]; __le16 reasoncode; }; @@ -251,11 +253,6 @@ struct cmd_ds_802_11_associate { #endif } __attribute__ ((packed)); -struct cmd_ds_802_11_disassociate { - u8 destmacaddr[6]; - __le16 reasoncode; -}; - struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; @@ -697,7 +694,6 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_deauthenticate deauth; struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_ad_hoc_result result; @@ -710,7 +706,6 @@ struct cmd_ds_command { struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; - struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; struct cmd_ds_rf_reg_access rfreg; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 3c13619..5e4c4e4 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -291,7 +291,9 @@ static ssize_t lbs_rtap_set(struct device *dev, if (priv->infra_open || priv->mesh_open) return -EBUSY; if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); lbs_add_rtap(priv); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 10a8066..38295ee 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -986,7 +986,9 @@ static int lbs_mesh_set_freq(struct net_device *dev, if (fwrq->m != priv->curbssparams.channel) { lbs_deb_wext("mesh channel change forces eth disconnect\n"); if (priv->mode == IW_MODE_INFRA) - lbs_send_deauthentication(priv); + lbs_cmd_80211_deauthenticate(priv, + priv->curbssparams.bssid, + WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) lbs_stop_adhoc_network(priv); } -- cgit v0.10.2 From d5db2dfa660de13c3643149b89c7602dd49aa168 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 17:51:07 -0400 Subject: libertas: convert CMD_802_11_RADIO_CONTROL to a direct command and return errors for operations like join & scan that aren't possible when the radio is turned off. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 5072a89..d47e4d5 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -25,7 +25,7 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = * @brief Associate to a specific BSS discovered in a scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to the BSS descriptor to associate with. + * @param assoc_req The association request describing the BSS to associate with * * @return 0-success, otherwise fail */ @@ -33,29 +33,29 @@ static int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret; + u8 preamble = RADIO_PREAMBLE_LONG; lbs_deb_enter(LBS_DEB_ASSOC); ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); - if (ret) - goto done; + goto out; - /* set preamble to firmware */ + /* Use short preamble only when both the BSS and firmware support it */ if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - else - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); -done: +out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -64,8 +64,7 @@ done: * @brief Join an adhoc network found in a previous scan * * @param priv A pointer to struct lbs_private structure - * @param pbssdesc Pointer to a BSS descriptor found in a previous scan - * to attempt to join + * @param assoc_req The association request describing the BSS to join * * @return 0--success, -1--fail */ @@ -74,6 +73,9 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, { struct bss_descriptor *bss = &assoc_req->bss; int ret = 0; + u8 preamble = RADIO_PREAMBLE_LONG; + + lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", escape_essid(priv->curbssparams.ssid, @@ -106,18 +108,16 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, goto out; } - /* Use shortpreamble only when both creator and card supports - short preamble */ - if (!(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) || - !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { - lbs_deb_join("AdhocJoin: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; - } else { + /* Use short preamble only when both the BSS and firmware support it */ + if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + (bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); @@ -129,6 +129,7 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, OID_802_11_SSID, assoc_req); out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } @@ -136,25 +137,27 @@ out: * @brief Start an Adhoc Network * * @param priv A pointer to struct lbs_private structure - * @param adhocssid The ssid of the Adhoc Network + * @param assoc_req The association request describing the BSS to start * @return 0--success, -1--fail */ static int lbs_start_adhoc_network(struct lbs_private *priv, struct assoc_request *assoc_req) { int ret = 0; + u8 preamble = RADIO_PREAMBLE_LONG; + + lbs_deb_enter(LBS_DEB_ASSOC); priv->adhoccreate = 1; if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); - priv->preamble = CMD_TYPE_SHORT_PREAMBLE; - } else { - lbs_deb_join("AdhocStart: Long preamble\n"); - priv->preamble = CMD_TYPE_LONG_PREAMBLE; + preamble = RADIO_PREAMBLE_SHORT; } - lbs_set_radio_control(priv); + ret = lbs_set_radio(priv, preamble, 1); + if (ret) + goto out; lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); @@ -162,6 +165,8 @@ static int lbs_start_adhoc_network(struct lbs_private *priv, ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); +out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8364a2f..f3073a5 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1289,41 +1289,47 @@ void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, priv->cur_cmd = NULL; } -int lbs_set_radio_control(struct lbs_private *priv) +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on) { - int ret = 0; struct cmd_ds_802_11_radio_control cmd; + int ret = -EINVAL; lbs_deb_enter(LBS_DEB_CMD); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); - switch (priv->preamble) { - case CMD_TYPE_SHORT_PREAMBLE: - cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case CMD_TYPE_LONG_PREAMBLE: - cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); - break; + /* Only v8 and below support setting the preamble */ + if (priv->fwrelease < 0x09000000) { + switch (preamble) { + case RADIO_PREAMBLE_SHORT: + if (!(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) + goto out; + /* Fall through */ + case RADIO_PREAMBLE_AUTO: + case RADIO_PREAMBLE_LONG: + cmd.control = cpu_to_le16(preamble); + break; + default: + goto out; + } + } - case CMD_TYPE_AUTO_PREAMBLE: - default: - cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; + if (radio_on) + cmd.control |= cpu_to_le16(0x1); + else { + cmd.control &= cpu_to_le16(~0x1); + priv->txpower_cur = 0; } - if (priv->radioon) - cmd.control |= cpu_to_le16(TURN_ON_RF); - else - cmd.control &= cpu_to_le16(~TURN_ON_RF); + lbs_deb_cmd("RADIO_CONTROL: radio %s, preamble %d\n", + radio_on ? "ON" : "OFF", preamble); - lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, - priv->preamble); + priv->radio_on = radio_on; ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); +out: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 6fba8ef..11ac996 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -65,4 +65,6 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel); int lbs_set_tx_power(struct lbs_private *priv, s16 dbm); +int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); + #endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index a8ac974..1a8888c 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -34,7 +34,6 @@ int lbs_process_event(struct lbs_private *priv, u32 event); void lbs_queue_event(struct lbs_private *priv, u32 event); void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx); -int lbs_set_radio_control(struct lbs_private *priv); u32 lbs_fw_index_to_data_rate(u8 index); u8 lbs_data_rate_to_fw_index(u32 rate); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 560d4d3..fd59e18 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -293,8 +293,7 @@ struct lbs_private { u16 nextSNRNF; u16 numSNRNF; - u8 radioon; - u32 preamble; + u8 radio_on; /** data rate stuff */ u8 cur_rate; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index caebb9b..da618fc 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -152,11 +152,6 @@ #define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 #define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 -/* Define action or option for CMD_802_11_RADIO_CONTROL */ -#define CMD_TYPE_AUTO_PREAMBLE 0x0001 -#define CMD_TYPE_SHORT_PREAMBLE 0x0002 -#define CMD_TYPE_LONG_PREAMBLE 0x0003 - /* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ #define CMD_SUBSCRIBE_RSSI_LOW 0x0001 #define CMD_SUBSCRIBE_SNR_LOW 0x0002 @@ -165,13 +160,9 @@ #define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 #define CMD_SUBSCRIBE_SNR_HIGH 0x0020 -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 +#define RADIO_PREAMBLE_LONG 0x00 +#define RADIO_PREAMBLE_SHORT 0x02 +#define RADIO_PREAMBLE_AUTO 0x04 /* Define action or option for CMD_802_11_RF_CHANNEL */ #define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 5e4c4e4..dafe62e 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1051,7 +1051,7 @@ static int lbs_init_adapter(struct lbs_private *priv) priv->mode = IW_MODE_INFRA; priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; priv->mac_control = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - priv->radioon = RADIO_ON; + priv->radio_on = 1; priv->enablehwauto = 1; priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; priv->psmode = LBS802_11POWERMODECAM; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 4b27456..8f66903 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -944,6 +944,11 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + if (!netif_running(dev)) { ret = -ENETDOWN; goto out; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 38295ee..4307090 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -120,34 +120,6 @@ static struct chan_freq_power *find_cfp_by_band_and_freq( return cfp; } - -/** - * @brief Set Radio On/OFF - * - * @param priv A pointer to struct lbs_private structure - * @option Radio Option - * @return 0 --success, otherwise fail - */ -static int lbs_radio_ioctl(struct lbs_private *priv, u8 option) -{ - int ret = 0; - - lbs_deb_enter(LBS_DEB_WEXT); - - if (priv->radioon != option) { - lbs_deb_wext("switching radio %s\n", option ? "on" : "off"); - priv->radioon = option; - - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_RADIO_CONTROL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); - } - - lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); - return ret; -} - /** * @brief Copy active data rates based on adapter mode and status * @@ -420,26 +392,30 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - int ret = 0; struct lbs_private *priv = dev->priv; s16 curlevel = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + lbs_deb_wext("tx power off\n"); + vwrq->value = 0; + vwrq->disabled = 1; + goto out; + } + ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL); if (ret) goto out; lbs_deb_wext("tx power level %d dbm\n", curlevel); - priv->txpower_cur = curlevel; + vwrq->value = curlevel; vwrq->fixed = 1; - if (priv->radioon) { - vwrq->disabled = 0; - vwrq->flags = IW_TXPOW_DBM; - } else - vwrq->disabled = 1; + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1839,13 +1815,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - lbs_radio_ioctl(priv, RADIO_OFF); + lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0); goto out; } if (vwrq->fixed == 0) { /* Auto power control */ - priv->preamble = CMD_TYPE_AUTO_PREAMBLE; dbm = priv->txpower_max; } else { /* Userspace check in iwrange if it should use dBm or mW, @@ -1867,7 +1842,12 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, } } - lbs_radio_ioctl(priv, RADIO_ON); + /* If the radio was off, turn it on */ + if (!priv->radio_on) { + ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1); + if (ret) + goto out; + } lbs_deb_wext("txpower set %d dBm\n", dbm); @@ -1925,6 +1905,11 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (in_ssid_len > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2002,6 +1987,11 @@ static int lbs_mesh_set_essid(struct net_device *dev, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) { + ret = -EINVAL; + goto out; + } + /* Check the size of the string */ if (dwrq->length > IW_ESSID_MAX_SIZE) { ret = -E2BIG; @@ -2043,6 +2033,9 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->radio_on) + return -EINVAL; + if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; -- cgit v0.10.2 From f5fe1fdaae86a74d6977fafd8fdd8697e398dafd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 21 Aug 2008 21:46:59 -0400 Subject: libertas: convert adhoc operations to direct commands with fixes for v9 and later firmware too. Signed-off-by: Dan Williams Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index d47e4d5..4ddf44b 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -8,6 +8,7 @@ #include "scan.h" #include "cmd.h" +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp); static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -20,6 +21,82 @@ static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) = #define CAPINFO_MASK (~(0xda00)) +/** + * @brief This function finds common rates between rates and card rates. + * + * It will fill common rates in rates as output if found. + * + * NOTE: Setting the MSB of the basic rates need to be taken + * care, either before or after calling this function + * + * @param priv A pointer to struct lbs_private structure + * @param rates the buffer which keeps input and output + * @param rates_size the size of rate1 buffer; new size of buffer on return + * + * @return 0 on success, or -1 on error + */ +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) +{ + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); + int ret = 0, i, j; + u8 tmp[30]; + size_t tmp_size = 0; + + /* For each rate in card_rates that exists in rate1, copy to tmp */ + for (i = 0; card_rates[i] && (i < num_card_rates); i++) { + for (j = 0; rates[j] && (j < *rates_size); j++) { + if (rates[j] == card_rates[i]) + tmp[tmp_size++] = card_rates[i]; + } + } + + lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); + lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); + lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); + + if (!priv->enablehwauto) { + for (i = 0; i < tmp_size; i++) { + if (tmp[i] == priv->cur_rate) + goto done; + } + lbs_pr_alert("Previously set fixed data rate %#x isn't " + "compatible with the network.\n", priv->cur_rate); + ret = -1; + goto done; + } + ret = 0; + +done: + memset(rates, 0, *rates_size); + *rates_size = min_t(int, tmp_size, *rates_size); + memcpy(rates, tmp, *rates_size); + return ret; +} + + +/** + * @brief Sets the MSB on basic rates as the firmware requires + * + * Scan through an array and set the MSB for basic data rates. + * + * @param rates buffer of data rates + * @param len size of buffer + */ +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) +{ + int i; + + for (i = 0; i < len; i++) { + if (rates[i] == 0x02 || rates[i] == 0x04 || + rates[i] == 0x0b || rates[i] == 0x16) + rates[i] |= 0x80; + } +} + /** * @brief Associate to a specific BSS discovered in a scan @@ -66,14 +143,17 @@ out: * @param priv A pointer to struct lbs_private structure * @param assoc_req The association request describing the BSS to join * - * @return 0--success, -1--fail + * @return 0 on success, error on failure */ -static int lbs_join_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_join(struct lbs_private *priv, struct assoc_request *assoc_req) { + struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; - int ret = 0; u8 preamble = RADIO_PREAMBLE_LONG; + DECLARE_MAC_BUF(mac); + u16 ratesize = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); @@ -123,10 +203,88 @@ static int lbs_join_adhoc_network(struct lbs_private *priv, lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); priv->adhoccreate = 0; + priv->curbssparams.channel = bss->channel; - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, - 0, CMD_OPTION_WAITFORRSP, - OID_802_11_SSID, assoc_req); + /* Build the join command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + cmd.bss.type = CMD_BSS_TYPE_IBSS; + cmd.bss.beaconperiod = cpu_to_le16(bss->beaconperiod); + + memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN); + memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len); + + memcpy(&cmd.bss.phyparamset, &bss->phyparamset, + sizeof(union ieeetypes_phyparamset)); + + memcpy(&cmd.bss.ssparamset, &bss->ssparamset, + sizeof(union IEEEtypes_ssparamset)); + + cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); + lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", + bss->capability, CAPINFO_MASK); + + /* information on BSSID descriptor passed to FW */ + lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", + print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + + /* Only v8 and below support setting these */ + if (priv->fwrelease < 0x09000000) { + /* failtimeout */ + cmd.failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); + /* probedelay */ + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + } + + /* Copy Data rates from the rates recorded in scan response */ + memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates)); + ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES); + memcpy(cmd.bss.rates, bss->rates, ratesize); + if (get_common_rates(priv, cmd.bss.rates, &ratesize)) { + lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n"); + ret = -1; + goto out; + } + + /* Copy the ad-hoc creation rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, cmd.bss.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.bss.rates, ratesize); + + cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); + + if (assoc_req->secinfo.wep_enabled) { + u16 tmp = le16_to_cpu(cmd.bss.capability); + tmp |= WLAN_CAPABILITY_PRIVACY; + cmd.bss.capability = cpu_to_le16(tmp); + } + + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + __le32 local_ps_mode = cpu_to_le32(LBS802_11POWERMODECAM); + + /* wake up first */ + ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + CMD_ACT_SET, 0, 0, + &local_ps_mode); + if (ret) { + ret = -1; + goto out; + } + } + + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { + ret = -1; + goto out; + } + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -138,20 +296,22 @@ out: * * @param priv A pointer to struct lbs_private structure * @param assoc_req The association request describing the BSS to start - * @return 0--success, -1--fail + * + * @return 0 on success, error on failure */ -static int lbs_start_adhoc_network(struct lbs_private *priv, +static int lbs_adhoc_start(struct lbs_private *priv, struct assoc_request *assoc_req) { - int ret = 0; + struct cmd_ds_802_11_ad_hoc_start cmd; u8 preamble = RADIO_PREAMBLE_LONG; + size_t ratesize = 0; + u16 tmpcap = 0; + int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); - priv->adhoccreate = 1; - if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { - lbs_deb_join("AdhocStart: Short preamble\n"); + lbs_deb_join("ADHOC_START: Will use short preamble\n"); preamble = RADIO_PREAMBLE_SHORT; } @@ -159,21 +319,107 @@ static int lbs_start_adhoc_network(struct lbs_private *priv, if (ret) goto out; - lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); - lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); + /* Build the start command */ + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, - 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); + memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); + + lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->ssid_len); + + cmd.bsstype = CMD_BSS_TYPE_IBSS; + + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + cmd.beaconperiod = cpu_to_le16(priv->beacon_period); + + WARN_ON(!assoc_req->channel); + + /* set Physical parameter set */ + cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.len = 1; + cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; + + /* set IBSS parameter set */ + cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.len = 2; + cmd.ssparamset.ibssparamset.atimwindow = 0; + + /* set capability info */ + tmpcap = WLAN_CAPABILITY_IBSS; + if (assoc_req->secinfo.wep_enabled) { + lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n"); + tmpcap |= WLAN_CAPABILITY_PRIVACY; + } else + lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n"); + + cmd.capability = cpu_to_le16(tmpcap); + + /* Only v8 and below support setting probe delay */ + if (priv->fwrelease < 0x09000000) + cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); + + ratesize = min(sizeof(cmd.rates), sizeof(lbs_bg_rates)); + memcpy(cmd.rates, lbs_bg_rates, ratesize); + + /* Copy the ad-hoc creating rates into Current BSS state structure */ + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &cmd.rates, ratesize); + + /* Set MSB on basic rates as the firmware requires, but _after_ + * copying to current bss rates. + */ + lbs_set_basic_rate_flags(cmd.rates, ratesize); + + lbs_deb_join("ADHOC_START: rates=%02x %02x %02x %02x\n", + cmd.rates[0], cmd.rates[1], cmd.rates[2], cmd.rates[3]); + + if (lbs_create_dnld_countryinfo_11d(priv)) { + lbs_deb_join("ADHOC_START: dnld_countryinfo_11d failed\n"); + ret = -1; + goto out; + } + + lbs_deb_join("ADHOC_START: Starting Ad-Hoc BSS on channel %d, band %d\n", + assoc_req->channel, assoc_req->band); + + priv->adhoccreate = 1; + priv->mode = IW_MODE_ADHOC; + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd); + if (ret == 0) + ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int lbs_stop_adhoc_network(struct lbs_private *priv) +/** + * @brief Stop and Ad-Hoc network and exit Ad-Hoc mode + * + * @param priv A pointer to struct lbs_private structure + * @return 0 on success, or an error + */ +int lbs_adhoc_stop(struct lbs_private *priv) { - return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); + struct cmd_ds_802_11_ad_hoc_stop cmd; + int ret; + + lbs_deb_enter(LBS_DEB_JOIN); + + memset(&cmd, 0, sizeof (cmd)); + cmd.hdr.size = cpu_to_le16 (sizeof (cmd)); + + ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd); + + /* Clean up everything even if there was an error */ + lbs_mac_event_disconnected(priv); + + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, @@ -485,14 +731,14 @@ static int assoc_helper_essid(struct lbs_private *priv, if (bss != NULL) { lbs_deb_assoc("SSID found, will join\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } else { /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, IW_ESSID_MAX_SIZE); assoc_req->bss.ssid_len = assoc_req->ssid_len; - lbs_start_adhoc_network(priv, assoc_req); + lbs_adhoc_start(priv, assoc_req); } } @@ -525,7 +771,7 @@ static int assoc_helper_bssid(struct lbs_private *priv, ret = lbs_associate(priv, assoc_req); lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { - lbs_join_adhoc_network(priv, assoc_req); + lbs_adhoc_join(priv, assoc_req); } out: @@ -1045,7 +1291,7 @@ void lbs_association_worker(struct work_struct *work) } } else if (priv->mode == IW_MODE_ADHOC) { if (should_stop_adhoc(priv, assoc_req)) { - ret = lbs_stop_adhoc_network(priv); + ret = lbs_adhoc_stop(priv); if (ret) { lbs_deb_assoc("Teardown of AdHoc network due to " "new configuration request failed: %d\n", @@ -1221,82 +1467,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv) /** - * @brief This function finds common rates between rate1 and card rates. - * - * It will fill common rates in rate1 as output if found. - * - * NOTE: Setting the MSB of the basic rates need to be taken - * care, either before or after calling this function - * - * @param priv A pointer to struct lbs_private structure - * @param rate1 the buffer which keeps input and output - * @param rate1_size the size of rate1 buffer; new size of buffer on return - * - * @return 0 or -1 - */ -static int get_common_rates(struct lbs_private *priv, - u8 *rates, - u16 *rates_size) -{ - u8 *card_rates = lbs_bg_rates; - size_t num_card_rates = sizeof(lbs_bg_rates); - int ret = 0, i, j; - u8 tmp[30]; - size_t tmp_size = 0; - - /* For each rate in card_rates that exists in rate1, copy to tmp */ - for (i = 0; card_rates[i] && (i < num_card_rates); i++) { - for (j = 0; rates[j] && (j < *rates_size); j++) { - if (rates[j] == card_rates[i]) - tmp[tmp_size++] = card_rates[i]; - } - } - - lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); - lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); - lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - - if (!priv->enablehwauto) { - for (i = 0; i < tmp_size; i++) { - if (tmp[i] == priv->cur_rate) - goto done; - } - lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", priv->cur_rate); - ret = -1; - goto done; - } - ret = 0; - -done: - memset(rates, 0, *rates_size); - *rates_size = min_t(int, tmp_size, *rates_size); - memcpy(rates, tmp, *rates_size); - return ret; -} - - -/** - * @brief Sets the MSB on basic rates as the firmware requires - * - * Scan through an array and set the MSB for basic data rates. - * - * @param rates buffer of data rates - * @param len size of buffer - */ -static void lbs_set_basic_rate_flags(u8 *rates, size_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (rates[i] == 0x02 || rates[i] == 0x04 || - rates[i] == 0x0b || rates[i] == 0x16) - rates[i] |= 0x80; - } -} - -/** * @brief This function prepares command of authenticate. * * @param priv A pointer to struct lbs_private structure @@ -1495,231 +1665,6 @@ done: return ret; } -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; - int ret = 0; - int cmdappendsize = 0; - struct assoc_request *assoc_req = pdata_buf; - u16 tmpcap = 0; - size_t ratesize = 0; - - lbs_deb_enter(LBS_DEB_JOIN); - - if (!priv) { - ret = -1; - goto done; - } - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START); - - /* - * Fill in the parameters for 2 data structures: - * 1. cmd_ds_802_11_ad_hoc_start command - * 2. priv->scantable[i] - * - * Driver will fill up SSID, bsstype,IBSS param, Physical Param, - * probe delay, and cap info. - * - * Firmware will fill up beacon period, DTIM, Basic rates - * and operational rates. - */ - - memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE); - memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len); - - lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->ssid_len); - - /* set the BSS type */ - adhs->bsstype = CMD_BSS_TYPE_IBSS; - priv->mode = IW_MODE_ADHOC; - if (priv->beacon_period == 0) - priv->beacon_period = MRVDRV_BEACON_INTERVAL; - adhs->beaconperiod = cpu_to_le16(priv->beacon_period); - - /* set Physical param set */ -#define DS_PARA_IE_ID 3 -#define DS_PARA_IE_LEN 1 - - adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; - adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; - - WARN_ON(!assoc_req->channel); - - lbs_deb_join("ADHOC_S_CMD: Creating ADHOC on channel %d\n", - assoc_req->channel); - - adhs->phyparamset.dsparamset.currentchan = assoc_req->channel; - - /* set IBSS param set */ -#define IBSS_PARA_IE_ID 6 -#define IBSS_PARA_IE_LEN 2 - - adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; - adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; - adhs->ssparamset.ibssparamset.atimwindow = 0; - - /* set capability info */ - tmpcap = WLAN_CAPABILITY_IBSS; - if (assoc_req->secinfo.wep_enabled) { - lbs_deb_join("ADHOC_S_CMD: WEP enabled, " - "setting privacy on\n"); - tmpcap |= WLAN_CAPABILITY_PRIVACY; - } else { - lbs_deb_join("ADHOC_S_CMD: WEP disabled, " - "setting privacy off\n"); - } - adhs->capability = cpu_to_le16(tmpcap); - - /* probedelay */ - adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); - memcpy(adhs->rates, lbs_bg_rates, ratesize); - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(adhs->rates, ratesize); - - lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", - adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); - - lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - - if (lbs_create_dnld_countryinfo_11d(priv)) { - lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) + - S_DS_GEN + cmdappendsize); - - ret = 0; -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd) -{ - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); - cmd->size = cpu_to_le16(S_DS_GEN); - - return 0; -} - -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, void *pdata_buf) -{ - struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; - struct assoc_request *assoc_req = pdata_buf; - struct bss_descriptor *bss = &assoc_req->bss; - int cmdappendsize = 0; - int ret = 0; - u16 ratesize = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_JOIN); - - cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN); - - join_cmd->bss.type = CMD_BSS_TYPE_IBSS; - join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod); - - memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN); - memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len); - - memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset, - sizeof(union ieeetypes_phyparamset)); - - memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset, - sizeof(union IEEEtypes_ssparamset)); - - join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK); - lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", - bss->capability, CAPINFO_MASK); - - /* information on BSSID descriptor passed to FW */ - lbs_deb_join( - "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, join_cmd->bss.bssid), - join_cmd->bss.ssid); - - /* failtimeout */ - join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); - - /* probedelay */ - join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - - priv->curbssparams.channel = bss->channel; - - /* Copy Data rates from the rates recorded in scan response */ - memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); - ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); - memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { - lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); - ret = -1; - goto done; - } - - /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); - memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); - - /* Set MSB on basic rates as the firmware requires, but _after_ - * copying to current bss rates. - */ - lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); - - join_cmd->bss.ssparamset.ibssparamset.atimwindow = - cpu_to_le16(bss->atimwindow); - - if (assoc_req->secinfo.wep_enabled) { - u16 tmp = le16_to_cpu(join_cmd->bss.capability); - tmp |= WLAN_CAPABILITY_PRIVACY; - join_cmd->bss.capability = cpu_to_le16(tmp); - } - - if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { - /* wake up first */ - __le32 Localpsmode; - - Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - ret = lbs_prepare_and_send_command(priv, - CMD_802_11_PS_MODE, - CMD_ACT_SET, - 0, 0, &Localpsmode); - - if (ret) { - ret = -1; - goto done; - } - } - - if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { - ret = -1; - goto done; - } - - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) + - S_DS_GEN + cmdappendsize); - -done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); - return ret; -} - int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp) { @@ -1821,24 +1766,19 @@ done: return ret; } -int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *resp) +static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) { int ret = 0; u16 command = le16_to_cpu(resp->command); u16 result = le16_to_cpu(resp->result); - struct cmd_ds_802_11_ad_hoc_result *padhocresult; + struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); - padhocresult = &resp->params.result; - - lbs_deb_join("ADHOC_RESP: size = %d\n", le16_to_cpu(resp->size)); - lbs_deb_join("ADHOC_RESP: command = %x\n", command); - lbs_deb_join("ADHOC_RESP: result = %x\n", result); + adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp; if (!priv->in_progress_assoc_req) { lbs_deb_join("ADHOC_RESP: no in-progress association " @@ -1852,26 +1792,19 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, * Join result code 0 --> SUCCESS */ if (result) { - lbs_deb_join("ADHOC_RESP: failed\n"); + lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result); if (priv->connect_status == LBS_CONNECTED) lbs_mac_event_disconnected(priv); ret = -1; goto done; } - /* - * Now the join cmd should be successful - * If BSSID has changed use SSID to compare instead of BSSID - */ - lbs_deb_join("ADHOC_RESP: associated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); - /* Send a Media Connected event, according to the Spec */ priv->connect_status = LBS_CONNECTED; if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ - memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN); + memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN); } /* Set the BSSID from the joined/started descriptor */ @@ -1890,22 +1823,13 @@ int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); - lbs_deb_join("ADHOC_RESP: BSSID = %s\n", - print_mac(mac, padhocresult->bssid)); + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", + escape_essid(bss->ssid, bss->ssid_len), + print_mac(mac, priv->curbssparams.bssid), + priv->curbssparams.channel); done: lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); return ret; } -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv) -{ - lbs_deb_enter(LBS_DEB_JOIN); - - lbs_mac_event_disconnected(priv); - - lbs_deb_leave(LBS_DEB_JOIN); - return 0; -} diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index 92ba2c2..8b7336d 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -12,13 +12,9 @@ struct cmd_ds_command; int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); -int lbs_cmd_80211_ad_hoc_stop(struct cmd_ds_command *cmd); -int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, - struct cmd_ds_command *cmd, - void *pdata_buf); + +int lbs_adhoc_stop(struct lbs_private *priv); + int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN], u16 reason); int lbs_cmd_80211_associate(struct lbs_private *priv, @@ -27,10 +23,7 @@ int lbs_cmd_80211_associate(struct lbs_private *priv, int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv); int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); -int lbs_stop_adhoc_network(struct lbs_private *priv); - #endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index f3073a5..802547e 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1419,10 +1419,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; - case CMD_802_11_AD_HOC_START: - ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RESET: ret = lbs_cmd_802_11_reset(cmdptr, cmd_action); break; @@ -1447,18 +1443,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv, cmd_action, pdata_buf); break; - case CMD_802_11_AD_HOC_JOIN: - ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); - break; - case CMD_802_11_RSSI: ret = lbs_cmd_802_11_rssi(priv, cmdptr); break; - case CMD_802_11_AD_HOC_STOP: - ret = lbs_cmd_80211_ad_hoc_stop(cmdptr); - break; - case CMD_802_11_SET_AFC: case CMD_802_11_GET_AFC: diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index c94604c..0371c83 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -258,11 +258,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_80211_associate(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_START): - case CMD_RET(CMD_802_11_AD_HOC_JOIN): - ret = lbs_ret_80211_ad_hoc_start(priv, resp); - break; - case CMD_RET(CMD_802_11_SNMP_MIB): ret = lbs_ret_802_11_snmp_mib(priv, resp); break; @@ -285,10 +280,6 @@ static inline int handle_cmd_response(struct lbs_private *priv, ret = lbs_ret_802_11_rssi(priv, resp); break; - case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = lbs_ret_80211_ad_hoc_stop(priv); - break; - case CMD_RET(CMD_802_11D_DOMAIN_INFO): ret = lbs_ret_802_11d_domain_info(resp); break; diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index 342c2e3..d27c276 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -257,11 +257,6 @@ struct cmd_ds_802_11_associate_rsp { struct ieeetypes_assocrsp assocRsp; }; -struct cmd_ds_802_11_ad_hoc_result { - u8 pad[3]; - u8 bssid[ETH_ALEN]; -}; - struct cmd_ds_802_11_set_wep { struct cmd_header hdr; @@ -508,10 +503,12 @@ struct cmd_ds_802_11_rate_adapt_rateset { }; struct cmd_ds_802_11_ad_hoc_start { + struct cmd_header hdr; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 bsstype; __le16 beaconperiod; - u8 dtimperiod; + u8 dtimperiod; /* Reserved on v9 and later */ union IEEEtypes_ssparamset ssparamset; union ieeetypes_phyparamset phyparamset; __le16 probedelay; @@ -520,9 +517,16 @@ struct cmd_ds_802_11_ad_hoc_start { u8 tlv_memory_size_pad[100]; } __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_result { + struct cmd_header hdr; + + u8 pad[3]; + u8 bssid[ETH_ALEN]; +}; + struct adhoc_bssdesc { - u8 bssid[6]; - u8 ssid[32]; + u8 bssid[ETH_ALEN]; + u8 ssid[IW_ESSID_MAX_SIZE]; u8 type; __le16 beaconperiod; u8 dtimperiod; @@ -540,10 +544,15 @@ struct adhoc_bssdesc { } __attribute__ ((packed)); struct cmd_ds_802_11_ad_hoc_join { + struct cmd_header hdr; + struct adhoc_bssdesc bss; - __le16 failtimeout; - __le16 probedelay; + __le16 failtimeout; /* Reserved on v9 and later */ + __le16 probedelay; /* Reserved on v9 and later */ +} __attribute__ ((packed)); +struct cmd_ds_802_11_ad_hoc_stop { + struct cmd_header hdr; } __attribute__ ((packed)); struct cmd_ds_802_11_enable_rsn { @@ -694,16 +703,13 @@ struct cmd_ds_command { union { struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_associate associate; - struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; - struct cmd_ds_802_11_ad_hoc_result result; struct cmd_ds_802_11_authenticate auth; struct cmd_ds_802_11_get_stat gstat; struct cmd_ds_802_3_get_stat gstat_8023; struct cmd_ds_802_11_snmp_mib smib; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_ad_hoc_join adj; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_mac_reg_access macreg; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index dafe62e..2436634 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -295,7 +295,7 @@ static ssize_t lbs_rtap_set(struct device *dev, priv->curbssparams.bssid, WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); lbs_add_rtap(priv); } priv->monitormode = monitor_mode; diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 4307090..426f1fe 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -966,7 +966,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, priv->curbssparams.bssid, WLAN_REASON_DEAUTH_LEAVING); else if (priv->mode == IW_MODE_ADHOC) - lbs_stop_adhoc_network(priv); + lbs_adhoc_stop(priv); } lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m); lbs_update_channel(priv); -- cgit v0.10.2 From 31ce12fb3ebf88b054deb99ad729e84888bf6125 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 20 Aug 2008 17:45:06 -0500 Subject: ssb: Clean up extraction of MAC addresses from SPROM Only rev 1 and 2 ssb SPROMs have fields named et0mac and et1mac; however, all of the extraction routines extract pseudo data for these fields from regions that are all 1's resulting in a hardware address of FF:FF:FF:FF:FF:FF. This patch forces such a fill at the beginning of the data extraction process, and only does the formal extraction if the SPROM rev is 1 or 2. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 0de4b5e..d5cde05 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -327,11 +327,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) s8 gain; u16 loc[3]; - if (out->revision == 3) { /* rev 3 moved MAC */ + if (out->revision == 3) /* rev 3 moved MAC */ loc[0] = SSB_SPROM3_IL0MAC; - loc[1] = SSB_SPROM3_ET0MAC; - loc[2] = SSB_SPROM3_ET1MAC; - } else { + else { loc[0] = SSB_SPROM1_IL0MAC; loc[1] = SSB_SPROM1_ET0MAC; loc[2] = SSB_SPROM1_ET1MAC; @@ -340,13 +338,15 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(loc[0]) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } - for (i = 0; i < 3; i++) { - v = in[SPOFF(loc[1]) + i]; - *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); - } - for (i = 0; i < 3; i++) { - v = in[SPOFF(loc[2]) + i]; - *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); + if (out->revision < 3) { /* only rev 1-2 have et0, et1 */ + for (i = 0; i < 3; i++) { + v = in[SPOFF(loc[1]) + i]; + *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(loc[2]) + i]; + *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); + } } SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A, @@ -409,19 +409,11 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) il0mac_offset = SSB_SPROM4_IL0MAC; else il0mac_offset = SSB_SPROM5_IL0MAC; - /* extract the equivalent of the r1 variables */ + /* extract the MAC address */ for (i = 0; i < 3; i++) { v = in[SPOFF(il0mac_offset) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } - for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM4_ET0MAC) + i]; - *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); - } - for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM4_ET1MAC) + i]; - *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); - } SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); @@ -482,6 +474,8 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, out->revision = in[size - 1] & 0x00FF; ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); + memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */ + memset(out->et1mac, 0xFF, 6); if ((bus->chip_id & 0xFF00) == 0x4400) { /* Workaround: The BCM44XX chip has a stupid revision * number stored in the SPROM. diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 271bb4b..99a0f99 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -245,8 +245,6 @@ /* SPROM Revision 3 (inherits most data from rev 2) */ #define SSB_SPROM3_IL0MAC 0x104A /* 6 bytes MAC address for 802.11b/g */ -#define SSB_SPROM3_ET0MAC 0x1050 /* 6 bytes MAC address for Ethernet ?? */ -#define SSB_SPROM3_ET1MAC 0x1050 /* 6 bytes MAC address for 802.11a ?? */ #define SSB_SPROM3_OFDMAPO 0x102C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */ #define SSB_SPROM3_OFDMALPO 0x1030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */ #define SSB_SPROM3_OFDMAHPO 0x1034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */ @@ -267,8 +265,6 @@ /* SPROM Revision 4 */ #define SSB_SPROM4_IL0MAC 0x104C /* 6 byte MAC address for a/b/g/n */ -#define SSB_SPROM4_ET0MAC 0x1018 /* 6 bytes MAC address for Ethernet ?? */ -#define SSB_SPROM4_ET1MAC 0x1018 /* 6 bytes MAC address for 802.11a ?? */ #define SSB_SPROM4_ETHPHY 0x105A /* Ethernet PHY settings ?? */ #define SSB_SPROM4_ETHPHY_ET0A 0x001F /* MII Address for enet0 */ #define SSB_SPROM4_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */ -- cgit v0.10.2 From 87e8b64e6856a41c5204a22c47cc14b1b0b57332 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 21 Aug 2008 21:45:56 +0300 Subject: mac80211_hwsim: Add minimal IEEE 802.11n support Set some semi-random values for HT and add more queues to allow IEEE 802.11n association to be tested with mac80211_hwsim. This with the latest hostapd git tree version can complete a simulated 802.11n association successfully (with mac80211 client MLME). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 248d31a..732429d 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -446,7 +446,8 @@ static int __init init_mac80211_hwsim(void) SET_IEEE80211_PERM_ADDR(hw, addr); hw->channel_change_time = 1; - hw->queues = 1; + hw->queues = 4; + hw->ampdu_queues = 1; memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels)); memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates)); @@ -454,6 +455,19 @@ static int __init init_mac80211_hwsim(void) data->band.n_channels = ARRAY_SIZE(hwsim_channels); data->band.bitrates = data->rates; data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); + data->band.ht_info.ht_supported = 1; + data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; + data->band.ht_info.ampdu_factor = 0x3; + data->band.ht_info.ampdu_density = 0x6; + memset(data->band.ht_info.supp_mcs_set, 0, + sizeof(data->band.ht_info.supp_mcs_set)); + data->band.ht_info.supp_mcs_set[0] = 0xff; + data->band.ht_info.supp_mcs_set[1] = 0xff; + data->band.ht_info.supp_mcs_set[12] = + IEEE80211_HT_CAP_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); -- cgit v0.10.2 From e022edbd2bfb5f9a7ddf1cca43544f7b54c6fe02 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 22 Aug 2008 17:31:33 +0300 Subject: ath9k: Use mac80211 for multicast power save buffering Replace the internal ath9k implementation of multicast/broadcast frame power save buffering (AP mode) in ath9k with use of mac80211 ieee80211_get_buffered_bc() mechanism. This removes quite a bit of duplicated functionality and simplifies the driver part. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 18028a3..841893b 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -144,6 +144,7 @@ struct ath_desc { #define ATH9K_TXDESC_EXT_AND_CTL 0x0080 #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 +#define ATH9K_TXDESC_CAB 0x0400 #define ATH9K_RXDESC_INTREQ 0x0020 diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index ee118562..fdbabc1 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -140,56 +140,6 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* Move everything from the vap's mcast queue to the hardware cab queue. - * Caller must hold mcasq lock and cabq lock - * XXX MORE_DATA bit? - */ -static void empty_mcastq_into_cabq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - struct ath_buf *bfmcast; - - BUG_ON(list_empty(&mcastq->axq_q)); - - bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list); - - /* link the descriptors */ - if (!cabq->axq_link) - ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr); - else - *cabq->axq_link = bfmcast->bf_daddr; - - /* append the private vap mcast list to the cabq */ - - cabq->axq_depth += mcastq->axq_depth; - cabq->axq_totalqueued += mcastq->axq_totalqueued; - cabq->axq_linkbuf = mcastq->axq_linkbuf; - cabq->axq_link = mcastq->axq_link; - list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q); - mcastq->axq_depth = 0; - mcastq->axq_totalqueued = 0; - mcastq->axq_linkbuf = NULL; - mcastq->axq_link = NULL; -} - -/* TODO: use ieee80211_get_buffered_bc() to fetch power saved mcast frames */ -/* This is only run at DTIM. We move everything from the vap's mcast queue - * to the hardware cab queue. Caller must hold the mcastq lock. */ -static void trigger_mcastq(struct ath_hal *ah, - struct ath_txq *mcastq, struct ath_txq *cabq) -{ - spin_lock_bh(&cabq->axq_lock); - - if (!list_empty(&mcastq->axq_q)) - empty_mcastq_into_cabq(ah, mcastq, cabq); - - /* cabq is gated by beacon so it is safe to start here */ - if (!list_empty(&cabq->axq_q)) - ath9k_hw_txstart(ah, cabq->axq_qnum); - - spin_unlock_bh(&cabq->axq_lock); -} - /* * Generate beacon frame and queue cab data for a vap. * @@ -200,19 +150,14 @@ static void trigger_mcastq(struct ath_hal *ah, */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { - struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; int cabq_depth; - int mcastq_depth; - int is_beacon_dtim = 0; struct ath_txq *cabq; - struct ath_txq *mcastq; struct ieee80211_tx_info *info; avp = sc->sc_vaps[if_id]; - mcastq = &avp->av_mcastq; cabq = sc->sc_cabq; ASSERT(avp); @@ -250,11 +195,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) skb_end_pointer(skb) - skb->head, PCI_DMA_TODEVICE); - /* TODO: convert to use ieee80211_get_buffered_bc() */ - /* XXX: spin_lock_bh should not be used here, but sparse bitches - * otherwise. We should fix sparse :) */ - spin_lock_bh(&mcastq->axq_lock); - mcastq_depth = avp->av_mcastq.axq_depth; + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -268,10 +209,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); - if (avp->av_boff.bo_tim) - is_beacon_dtim = avp->av_boff.bo_tim[4] & 1; - - if (mcastq_depth && is_beacon_dtim && cabq_depth) { + if (skb && cabq_depth) { /* * Unlock the cabq lock as ath_tx_draintxq acquires * the lock again which is a common function and that @@ -291,10 +229,11 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * Enable the CAB queue before the beacon queue to * insure cab frames are triggered by this beacon. */ - if (is_beacon_dtim) - trigger_mcastq(ah, mcastq, cabq); + while (skb) { + ath_tx_cabq(sc, skb); + skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + } - spin_unlock_bh(&mcastq->axq_lock); return bf; } @@ -426,7 +365,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * NB: the beacon data buffer must be 32-bit aligned; * we assume the wbuf routines will return us something * with this alignment (perhaps should assert). - * FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and + * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 57645ee..c262ef2 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c @@ -533,9 +533,6 @@ int ath_vap_attach(struct ath_softc *sc, /* Set the VAP opmode */ avp->av_opmode = opmode; avp->av_bslot = -1; - INIT_LIST_HEAD(&avp->av_mcastq.axq_q); - INIT_LIST_HEAD(&avp->av_mcastq.axq_acq); - spin_lock_init(&avp->av_mcastq.axq_lock); ath9k_hw_set_tsfadjust(sc->sc_ah, 1); @@ -575,9 +572,6 @@ int ath_vap_detach(struct ath_softc *sc, int if_id) ath_stoprecv(sc); /* stop recv side */ ath_flushrecv(sc); /* flush recv queue */ - /* Reclaim any pending mcast bufs on the vap. */ - ath_tx_draintxq(sc, &avp->av_mcastq, false); - kfree(avp); sc->sc_vaps[if_id] = NULL; sc->sc_nvaps--; diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index ca7e613..de1d12f 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -568,6 +568,7 @@ u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth); void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, struct ath_xmit_status *tx_status, struct ath_node *an); +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); /**********************/ /* Node / Aggregation */ @@ -713,12 +714,6 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; -/* offsets in a beacon frame for - * quick acess of beacon content by low-level driver */ -struct ath_beacon_offset { - u8 *bo_tim; /* start of atim/dtim */ -}; - void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); @@ -755,10 +750,8 @@ struct ath_vap { struct ieee80211_vif *av_if_data; enum ath9k_opmode av_opmode; /* VAP operational mode */ struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_beacon_offset av_boff; /* dynamic update state */ struct ath_tx_control av_btxctl; /* txctl information for beacon */ int av_bslot; /* beacon slot index */ - struct ath_txq av_mcastq; /* multicast transmit queue */ struct ath_vap_config av_config;/* vap configuration parameters*/ struct ath_rate_node *rc_node; }; diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 55f4868..dca00c3 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1362,6 +1362,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 04f94d2..a18cea6 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -60,79 +60,6 @@ static u32 bits_per_symbol[][2] = { #define IS_HT_RATE(_rate) ((_rate) & 0x80) /* - * Insert a chain of ath_buf (descriptors) on a multicast txq - * but do NOT start tx DMA on this queue. - * NB: must be called with txq lock held - */ - -static void ath_tx_mcastqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, - struct list_head *head) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_buf *bf; - - if (list_empty(head)) - return; - - /* - * Insert the frame on the outbound list and - * pass it on to the hardware. - */ - bf = list_first_entry(head, struct ath_buf, list); - - /* - * The CAB queue is started from the SWBA handler since - * frames only go out on DTIM and to avoid possible races. - */ - ath9k_hw_set_interrupts(ah, 0); - - /* - * If there is anything in the mcastq, we want to set - * the "more data" bit in the last item in the queue to - * indicate that there is "more data". It makes sense to add - * it here since you are *always* going to have - * more data when adding to this queue, no matter where - * you call from. - */ - - if (txq->axq_depth) { - struct ath_buf *lbf; - struct ieee80211_hdr *hdr; - - /* - * Add the "more data flag" to the last frame - */ - - lbf = list_entry(txq->axq_q.prev, struct ath_buf, list); - hdr = (struct ieee80211_hdr *) - ((struct sk_buff *)(lbf->bf_mpdu))->data; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - /* - * Now, concat the frame onto the queue - */ - list_splice_tail_init(head, &txq->axq_q); - txq->axq_depth++; - txq->axq_totalqueued++; - txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); - - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: txq depth = %d\n", __func__, txq->axq_depth); - if (txq->axq_link != NULL) { - *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, - "%s: link[%u](%p)=%llx (%p)\n", - __func__, - txq->axq_qnum, txq->axq_link, - ito64(bf->bf_daddr), bf->bf_desc); - } - txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link); - ath9k_hw_set_interrupts(ah, sc->sc_imask); -} - -/* * Insert a chain of ath_buf (descriptors) on a txq and * assume the descriptors are already chained together by caller. * NB: must be called with txq lock held @@ -277,8 +204,6 @@ static int ath_tx_prepare(struct ath_softc *sc, __le16 fc; u8 *qc; - memset(txctl, 0, sizeof(struct ath_tx_control)); - txctl->dev = sc; hdr = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -329,12 +254,18 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill qnum */ - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { + txctl->qnum = 0; + txq = sc->sc_cabq; + } else { + txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->sc_txq[txctl->qnum]; + } spin_lock_bh(&txq->axq_lock); /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20)) { + if (txq->axq_depth >= (ATH_TXBUF - 20) && + !(txctl->flags & ATH9K_TXDESC_CAB)) { DPRINTF(sc, ATH_DBG_FATAL, "%s: TX queue: %d is full, depth: %d\n", __func__, @@ -354,7 +285,7 @@ static int ath_tx_prepare(struct ath_softc *sc, /* Fill flags */ - txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) txctl->flags |= ATH9K_TXDESC_NOACK; @@ -1982,13 +1913,18 @@ static int ath_tx_start_dma(struct ath_softc *sc, struct list_head bf_head; struct ath_desc *ds; struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq = &sc->sc_txq[txctl->qnum]; + struct ath_txq *txq; struct ath_tx_info_priv *tx_info_priv; struct ath_rc_series *rcs; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); __le16 fc = hdr->frame_control; + if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) + txq = sc->sc_cabq; + else + txq = &sc->sc_txq[txctl->qnum]; + /* For each sglist entry, allocate an ath_buf for DMA */ INIT_LIST_HEAD(&bf_head); spin_lock_bh(&sc->sc_txbuflock); @@ -2093,27 +2029,7 @@ static int ath_tx_start_dma(struct ath_softc *sc, bf->bf_tidno = txctl->tidno; } - if (is_multicast_ether_addr(hdr->addr1)) { - struct ath_vap *avp = sc->sc_vaps[txctl->if_id]; - - /* - * When servicing one or more stations in power-save - * mode (or) if there is some mcast data waiting on - * mcast queue (to prevent out of order delivery of - * mcast,bcast packets) multicast frames must be - * buffered until after the beacon. We use the private - * mcast queue for that. - */ - /* XXX? more bit in 802.11 frame header */ - spin_lock_bh(&avp->av_mcastq.axq_lock); - if (txctl->ps || avp->av_mcastq.axq_depth) - ath_tx_mcastqaddbuf(sc, - &avp->av_mcastq, &bf_head); - else - ath_tx_txqaddbuf(sc, txq, &bf_head); - spin_unlock_bh(&avp->av_mcastq.axq_lock); - } else - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_tx_txqaddbuf(sc, txq, &bf_head); } spin_unlock_bh(&txq->axq_lock); return 0; @@ -2407,6 +2323,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) struct ath_tx_control txctl; int error = 0; + memset(&txctl, 0, sizeof(struct ath_tx_control)); error = ath_tx_prepare(sc, skb, &txctl); if (error == 0) /* @@ -2871,3 +2788,57 @@ void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) } } } + +void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) +{ + int hdrlen, padsize; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ath_tx_control txctl; + + /* + * As a temporary workaround, assign seq# here; this will likely need + * to be cleaned up to work better with Beacon transmission and virtual + * BSSes. + */ + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + sc->seq_no += 0x10; + hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + } + + /* Add the padding after the header if this is not already done */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + padsize = hdrlen % 4; + if (skb_headroom(skb) < padsize) { + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " + "failed\n", __func__); + dev_kfree_skb_any(skb); + return; + } + skb_push(skb, padsize); + memmove(skb->data, skb->data + padsize, hdrlen); + } + + DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", + __func__, + skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); + txctl.flags = ATH9K_TXDESC_CAB; + if (ath_tx_prepare(sc, skb, &txctl) == 0) { + /* + * Start DMA mapping. + * ath_tx_start_dma() will be called either synchronously + * or asynchrounsly once DMA is complete. + */ + xmit_map_sg(sc, skb, &txctl); + } else { + ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); + DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); + dev_kfree_skb_any(skb); + } +} + -- cgit v0.10.2 From a3ec233c90f0b8a5c00bf182f2c3ea9119b46caa Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Sat, 23 Aug 2008 13:56:25 +0800 Subject: wireless: remove unused #include The driver(s) below do not use LINUX_VERSION_CODE nor KERNEL_VERSION. drivers/net/wireless/b43legacy/main.c drivers/net/wireless/iwlwifi/iwl-3945-led.c drivers/net/wireless/iwlwifi/iwl-led.c drivers/net/wireless/iwlwifi/iwl-rfkill.c This patch removes the said #include . Signed-off-by: Huang Weiyi Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 2541c81..1cb77db 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index d333696..705c65b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index cb11c4a..4eee1b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index e5e5846..5d64229 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -27,7 +27,6 @@ *****************************************************************************/ #include #include -#include #include #include -- cgit v0.10.2 From 154e3af17fdce617605b63f3534dac2c10c90922 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 23 Aug 2008 22:15:25 +0200 Subject: p54: fix rssi auto calibration Ever wondered why the signal was so bad with p54 compared to madwifi, or intel? Well, if you have revision 1 rssi calibration curve points in your EEPROM, then wonder no more. The firmware wants a extra 1 byte padding for every curve point. But someone forgot to put them into the EEPROM's data structure... So now, big question: what happens when we blindly "memcpy" these data points? Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 29be3dc..4a6b536 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -155,14 +155,14 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } EXPORT_SYMBOL_GPL(p54_parse_firmware); -static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) +static int p54_convert_rev0(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) { struct p54_common *priv = dev->priv; - struct pda_pa_curve_data_sample_rev1 *rev1; - struct pda_pa_curve_data_sample_rev0 *rev0; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev0 *src; size_t cd_len = sizeof(*curve_data) + - (curve_data->points_per_channel*sizeof(*rev1) + 2) * + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; @@ -180,27 +180,63 @@ static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev, *((__le16 *)target) = *freq; target += sizeof(__le16); for (j = 0; j < curve_data->points_per_channel; j++) { - rev1 = target; - rev0 = source; + dst = target; + src = source; - rev1->rf_power = rev0->rf_power; - rev1->pa_detector = rev0->pa_detector; - rev1->data_64qam = rev0->pcv; + dst->rf_power = src->rf_power; + dst->pa_detector = src->pa_detector; + dst->data_64qam = src->pcv; /* "invent" the points for the other modulations */ #define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y) - rev1->data_16qam = SUB(rev0->pcv, 12); - rev1->data_qpsk = SUB(rev1->data_16qam, 12); - rev1->data_bpsk = SUB(rev1->data_qpsk, 12); - rev1->data_barker= SUB(rev1->data_bpsk, 14); + dst->data_16qam = SUB(src->pcv, 12); + dst->data_qpsk = SUB(dst->data_16qam, 12); + dst->data_bpsk = SUB(dst->data_qpsk, 12); + dst->data_barker = SUB(dst->data_bpsk, 14); #undef SUB - target += sizeof(*rev1); - source += sizeof(*rev0); + target += sizeof(*dst); + source += sizeof(*src); } } return 0; } +static int p54_convert_rev1(struct ieee80211_hw *dev, + struct pda_pa_curve_data *curve_data) +{ + struct p54_common *priv = dev->priv; + struct p54_pa_curve_data_sample *dst; + struct pda_pa_curve_data_sample_rev1 *src; + size_t cd_len = sizeof(*curve_data) + + (curve_data->points_per_channel*sizeof(*dst) + 2) * + curve_data->channels; + unsigned int i, j; + void *source, *target; + + priv->curve_data = kmalloc(cd_len, GFP_KERNEL); + if (!priv->curve_data) + return -ENOMEM; + + memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); + source = curve_data->data; + target = priv->curve_data->data; + for (i = 0; i < curve_data->channels; i++) { + __le16 *freq = source; + source += sizeof(__le16); + *((__le16 *)target) = *freq; + target += sizeof(__le16); + for (j = 0; j < curve_data->points_per_channel; j++) { + memcpy(target, source, sizeof(*src)); + + target += sizeof(*dst); + source += sizeof(*src); + } + source++; + } + + return 0; +} + int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -250,27 +286,32 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) entry->data[1]*sizeof(*priv->output_limit)); priv->output_limit_len = entry->data[1]; break; - case PDR_PRISM_PA_CAL_CURVE_DATA: - if (data_len < sizeof(struct pda_pa_curve_data)) { + case PDR_PRISM_PA_CAL_CURVE_DATA: { + struct pda_pa_curve_data *curve_data = + (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; } - if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) { - priv->curve_data = kmalloc(data_len, GFP_KERNEL); - if (!priv->curve_data) { - err = -ENOMEM; - goto err; - } - - memcpy(priv->curve_data, entry->data, data_len); - } else { - err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data); - if (err) - goto err; + switch (curve_data->cal_method_rev) { + case 0: + err = p54_convert_rev0(dev, curve_data); + break; + case 1: + err = p54_convert_rev1(dev, curve_data); + break; + default: + printk(KERN_ERR "p54: unknown curve data " + "revision %d\n", + curve_data->cal_method_rev); + err = -ENODEV; + break; } + if (err) + goto err; - break; + } case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: priv->iq_autocal = kmalloc(data_len, GFP_KERNEL); if (!priv->iq_autocal) { @@ -672,12 +713,9 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) struct p54_control_hdr *hdr; struct p54_tx_control_channel *chan; unsigned int i; - size_t payload_len = sizeof(*chan) + sizeof(u32)*2 + - sizeof(*chan->curve_data) * - priv->curve_data->points_per_channel; void *entry; - hdr = kzalloc(sizeof(*hdr) + payload_len + + hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + priv->tx_hdr_len, GFP_KERNEL); if (!hdr) return -ENOMEM; @@ -689,10 +727,10 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) hdr->magic1 = cpu_to_le16(0x8001); hdr->len = cpu_to_le16(sizeof(*chan)); hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len); + p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*chan)); - chan->magic1 = cpu_to_le16(0x1); - chan->magic2 = cpu_to_le16(0x0); + chan->flags = cpu_to_le16(0x1); + chan->dwell = cpu_to_le16(0x0); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -710,35 +748,41 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) continue; chan->val_barker = 0x38; - chan->val_bpsk = priv->output_limit[i].val_bpsk; - chan->val_qpsk = priv->output_limit[i].val_qpsk; - chan->val_16qam = priv->output_limit[i].val_16qam; - chan->val_64qam = priv->output_limit[i].val_64qam; + chan->val_bpsk = chan->dup_bpsk = + priv->output_limit[i].val_bpsk; + chan->val_qpsk = chan->dup_qpsk = + priv->output_limit[i].val_qpsk; + chan->val_16qam = chan->dup_16qam = + priv->output_limit[i].val_16qam; + chan->val_64qam = chan->dup_64qam = + priv->output_limit[i].val_64qam; break; } if (i == priv->output_limit_len) goto err; - chan->pa_points_per_curve = priv->curve_data->points_per_channel; - entry = priv->curve_data->data; for (i = 0; i < priv->curve_data->channels; i++) { if (*((__le16 *)entry) != freq) { entry += sizeof(__le16); - entry += sizeof(struct pda_pa_curve_data_sample_rev1) * - chan->pa_points_per_curve; + entry += sizeof(struct p54_pa_curve_data_sample) * + priv->curve_data->points_per_channel; continue; } entry += sizeof(__le16); + chan->pa_points_per_curve = + min(priv->curve_data->points_per_channel, (u8) 8); + memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * chan->pa_points_per_curve); break; } - memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4); + chan->rssical_mul = cpu_to_le16(130); + chan->rssical_add = cpu_to_le16(0xfe70); /* -400 */ - priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1); + priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*chan), 1); return 0; err: diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 9bc2a1c..a79c1a1 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -89,6 +89,16 @@ struct pda_pa_curve_data_sample_rev1 { u8 data_qpsk; u8 data_16qam; u8 data_64qam; +} __attribute__ ((packed)); + +struct p54_pa_curve_data_sample { + u8 rf_power; + u8 pa_detector; + u8 data_barker; + u8 data_bpsk; + u8 data_qpsk; + u8 data_16qam; + u8 data_64qam; u8 padding; } __attribute__ ((packed)); @@ -212,8 +222,8 @@ struct p54_tx_control_filter { } __attribute__ ((packed)); struct p54_tx_control_channel { - __le16 magic1; - __le16 magic2; + __le16 flags; + __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; u8 pa_points_per_curve; @@ -222,8 +232,13 @@ struct p54_tx_control_channel { u8 val_qpsk; u8 val_16qam; u8 val_64qam; - struct pda_pa_curve_data_sample_rev1 curve_data[0]; - /* additional padding/data after curve_data */ + struct pda_pa_curve_data_sample_rev1 curve_data[8]; + u8 dup_bpsk; + u8 dup_qpsk; + u8 dup_16qam; + u8 dup_64qam; + __le16 rssical_mul; + __le16 rssical_add; } __attribute__ ((packed)); struct p54_tx_control_led { -- cgit v0.10.2 From 031d10ee5a6df5aba6b4ac8bb01dd023cd5efc02 Mon Sep 17 00:00:00 2001 From: Chr Date: Sun, 24 Aug 2008 03:15:06 +0200 Subject: p54: take tx_queue's lock in rx_frame_sent p54_rx_frame_sent will alter the tx_queue. Therefore we should hold the lock to protect against concurrent p54_assign_address calls. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 4a6b536..5cd88bc 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -432,7 +432,9 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; + unsigned long flags; + spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); range = (void *)info->driver_data; @@ -453,6 +455,8 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) last_addr = range->end_addr; __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + memset(&info->status, 0, sizeof(info->status)); entry_hdr = (struct p54_control_hdr *) entry->data; entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; @@ -470,12 +474,14 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) info->status.ack_signal = le16_to_cpu(payload->ack_rssi); skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); ieee80211_tx_status_irqsafe(dev, entry); - break; + goto out; } else last_addr = range->end_addr; entry = entry->next; } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); +out: if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + sizeof(struct p54_control_hdr)) p54_wake_free_queues(dev); -- cgit v0.10.2 From 84df3ed30b72c3516d72bc9734d4425746b15dfc Mon Sep 17 00:00:00 2001 From: Chr Date: Sun, 24 Aug 2008 03:15:16 +0200 Subject: p54: redo queue numbering The firmware supports 8 different queues and not only 4. So, let's make some room for further tasks (ap/adhoc support) in this area. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 10df07d..fca8762 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -66,7 +66,7 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - struct ieee80211_tx_queue_stats tx_stats[4]; + struct ieee80211_tx_queue_stats tx_stats[8]; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 5cd88bc..17e06bb 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -146,10 +146,10 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[0].limit = 3; - priv->tx_stats[1].limit = 4; - priv->tx_stats[2].limit = 3; - priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 3; + priv->tx_stats[5].limit = 4; + priv->tx_stats[6].limit = 3; + priv->tx_stats[7].limit = 1; dev->queues = 4; } } @@ -418,7 +418,7 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) int i; for (i = 0; i < dev->queues; i++) - if (priv->tx_stats[i].len < priv->tx_stats[i].limit) + if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } @@ -463,7 +463,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - priv->tx_stats[entry_data->hw_queue - 4].len--; + priv->tx_stats[entry_data->hw_queue].len--; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (!(payload->status & 0x01)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -606,7 +606,7 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) u8 rate; u8 cts_rate = 0x20; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)]; + current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; if (unlikely(current_queue->len > current_queue->limit)) return NETDEV_TX_BUSY; current_queue->len++; @@ -1037,7 +1037,7 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - memcpy(stats, &priv->tx_stats, sizeof(stats[0]) * dev->queues); + memcpy(stats, &priv->tx_stats[4], sizeof(stats[0]) * dev->queues); return 0; } @@ -1075,7 +1075,11 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) dev->channel_change_time = 1000; /* TODO: find actual value */ dev->max_signal = 127; - priv->tx_stats[0].limit = 5; + priv->tx_stats[0].limit = 1; + priv->tx_stats[1].limit = 1; + priv->tx_stats[2].limit = 1; + priv->tx_stats[3].limit = 1; + priv->tx_stats[4].limit = 5; dev->queues = 1; dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + -- cgit v0.10.2 From 7262d59366f972b898ea134639112d34bcac35b3 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 24 Aug 2008 22:30:38 +0200 Subject: p54pci: rx tasklet refactoring This patch moves the all of p54pci's receiver code out of the bloated interrupt handler routine and into a less critical tasklet. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index ea2dc3d..e9db449 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -3,6 +3,7 @@ * Linux device driver for PCI based Prism54 * * Copyright (c) 2006, Michael Wu + * Copyright (c) 2008, Christian Lamparter * * Based on the islsm (softmac prism54) driver, which is: * Copyright 2004-2006 Jean-Baptiste Note , et al. @@ -237,20 +238,22 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) return err; } -static void p54p_refill_rx_ring(struct ieee80211_hw *dev) +static void p54p_refill_rx_ring(struct ieee80211_hw *dev, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; - u32 limit, host_idx, idx; + u32 limit, idx, i; - host_idx = le32_to_cpu(ring_control->host_idx[0]); - limit = host_idx; - limit -= le32_to_cpu(ring_control->device_idx[0]); - limit = ARRAY_SIZE(ring_control->rx_data) - limit; + idx = le32_to_cpu(ring_control->host_idx[ring_index]); + limit = idx; + limit -= le32_to_cpu(ring_control->device_idx[ring_index]); + limit = ring_limit - limit; - idx = host_idx % ARRAY_SIZE(ring_control->rx_data); + i = idx % ring_limit; while (limit-- > 1) { - struct p54p_desc *desc = &ring_control->rx_data[idx]; + struct p54p_desc *desc = &ring[i]; if (!desc->host_addr) { struct sk_buff *skb; @@ -267,16 +270,106 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev) desc->device_addr = 0; // FIXME: necessary? desc->len = cpu_to_le16(MAX_RX_SIZE); desc->flags = 0; - priv->rx_buf[idx] = skb; + rx_buf[i] = skb; } + i++; idx++; - host_idx++; - idx %= ARRAY_SIZE(ring_control->rx_data); + i %= ring_limit; } wmb(); - ring_control->host_idx[0] = cpu_to_le32(host_idx); + ring_control->host_idx[ring_index] = cpu_to_le32(idx); +} + +static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + struct sk_buff **rx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; + + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]); + idx %= ring_limit; + while (i != idx) { + u16 len; + struct sk_buff *skb; + desc = &ring[i]; + len = le16_to_cpu(desc->len); + skb = rx_buf[i]; + + if (!skb) + continue; + + skb_put(skb, len); + + if (p54_rx(dev, skb)) { + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + rx_buf[i] = NULL; + desc->host_addr = 0; + } else { + skb_trim(skb, 0); + desc->len = cpu_to_le16(MAX_RX_SIZE); + } + + i++; + i %= ring_limit; + } + + p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); +} + +/* caller must hold priv->lock */ +static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, + int ring_index, struct p54p_desc *ring, u32 ring_limit, + void **tx_buf) +{ + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + struct p54p_desc *desc; + u32 idx, i; + + i = (*index) % ring_limit; + (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); + idx %= ring_limit; + + while (i != idx) { + desc = &ring[i]; + kfree(tx_buf[i]); + tx_buf[i] = NULL; + + pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + + desc->host_addr = 0; + desc->device_addr = 0; + desc->len = 0; + desc->flags = 0; + + i++; + i %= ring_limit; + } +} + +static void p54p_rx_tasklet(unsigned long dev_id) +{ + struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; + struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; + + p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, + ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); + + p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data, + ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data); + + wmb(); + P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } static irqreturn_t p54p_interrupt(int irq, void *dev_id) @@ -298,65 +391,18 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) reg &= P54P_READ(int_enable); if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { - struct p54p_desc *desc; - u32 idx, i; - i = priv->tx_idx; - i %= ARRAY_SIZE(ring_control->tx_data); - priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]); - idx %= ARRAY_SIZE(ring_control->tx_data); - - while (i != idx) { - desc = &ring_control->tx_data[i]; - if (priv->tx_buf[i]) { - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; - } - - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, + 3, ring_control->tx_mgmt, + ARRAY_SIZE(ring_control->tx_mgmt), + priv->tx_buf_mgmt); - desc->host_addr = 0; - desc->device_addr = 0; - desc->len = 0; - desc->flags = 0; + p54p_check_tx_ring(dev, &priv->tx_idx_data, + 1, ring_control->tx_data, + ARRAY_SIZE(ring_control->tx_data), + priv->tx_buf_data); - i++; - i %= ARRAY_SIZE(ring_control->tx_data); - } - - i = priv->rx_idx; - i %= ARRAY_SIZE(ring_control->rx_data); - priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]); - idx %= ARRAY_SIZE(ring_control->rx_data); - while (i != idx) { - u16 len; - struct sk_buff *skb; - desc = &ring_control->rx_data[i]; - len = le16_to_cpu(desc->len); - skb = priv->rx_buf[i]; - - skb_put(skb, len); - - if (p54_rx(dev, skb)) { - pci_unmap_single(priv->pdev, - le32_to_cpu(desc->host_addr), - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - - priv->rx_buf[i] = NULL; - desc->host_addr = 0; - } else { - skb_trim(skb, 0); - desc->len = cpu_to_le16(MAX_RX_SIZE); - } - - i++; - i %= ARRAY_SIZE(ring_control->rx_data); - } + tasklet_schedule(&priv->rx_tasklet); - p54p_refill_rx_ring(dev); - - wmb(); - P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) complete(&priv->boot_comp); @@ -392,7 +438,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) - priv->tx_buf[i] = data; + priv->tx_buf_data[i] = data; spin_unlock_irqrestore(&priv->lock, flags); @@ -420,8 +466,14 @@ static int p54p_open(struct ieee80211_hw *dev) } memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - priv->rx_idx = priv->tx_idx = 0; - p54p_refill_rx_ring(dev); + priv->rx_idx_data = priv->tx_idx_data = 0; + priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0; + + p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data, + ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data); + + p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt, + ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt); p54p_upload_firmware(dev); @@ -465,6 +517,8 @@ static void p54p_stop(struct ieee80211_hw *dev) unsigned int i; struct p54p_desc *desc; + tasklet_kill(&priv->rx_tasklet); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); @@ -473,26 +527,51 @@ static void p54p_stop(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); - for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { desc = &ring_control->rx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); - kfree_skb(priv->rx_buf[i]); - priv->rx_buf[i] = NULL; + kfree_skb(priv->rx_buf_data[i]); + priv->rx_buf_data[i] = NULL; } - for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { + for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { + desc = &ring_control->rx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(priv->rx_buf_mgmt[i]); + priv->rx_buf_mgmt[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { desc = &ring_control->tx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); + + kfree(priv->tx_buf_data[i]); + priv->tx_buf_data[i] = NULL; + } + + for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { + desc = &ring_control->tx_mgmt[i]; + if (desc->host_addr) + pci_unmap_single(priv->pdev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), + PCI_DMA_TODEVICE); - kfree(priv->tx_buf[i]); - priv->tx_buf[i] = NULL; + kfree(priv->tx_buf_mgmt[i]); + priv->tx_buf_mgmt[i] = NULL; } - memset(ring_control, 0, sizeof(ring_control)); + memset(ring_control, 0, sizeof(*ring_control)); } static int __devinit p54p_probe(struct pci_dev *pdev, @@ -585,6 +664,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, priv->common.tx = p54p_tx; spin_lock_init(&priv->lock); + tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); err = ieee80211_register_hw(dev); if (err) { diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 07678ef..4a67780 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -92,13 +92,17 @@ struct p54p_priv { struct p54_common common; struct pci_dev *pdev; struct p54p_csr __iomem *map; + struct tasklet_struct rx_tasklet; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; - u32 rx_idx, tx_idx; - struct sk_buff *rx_buf[8]; - void *tx_buf[32]; + u32 rx_idx_data, tx_idx_data; + u32 rx_idx_mgmt, tx_idx_mgmt; + struct sk_buff *rx_buf_data[8]; + struct sk_buff *rx_buf_mgmt[4]; + void *tx_buf_data[32]; + void *tx_buf_mgmt[4]; struct completion boot_comp; }; -- cgit v0.10.2 From 36aedc903ea11a4188de0a118d26c9f20afdd272 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 25 Aug 2008 11:58:58 +0300 Subject: mac80211/cfg80211: HT capabilities for NEW_STA Allow userspace (e.g., hostapd) to set HT capabilities for associated STAs. This is based on a patch from Zhu Yi (only the NL80211_ATTR_HT_CAPABILITY for NEW_STA part is included here). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 447c02a..0c1147d 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -207,6 +207,9 @@ enum nl80211_commands { * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled * (u8, 0 or 1) * + * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -254,16 +257,25 @@ enum nl80211_attrs { NL80211_ATTR_BSS_SHORT_PREAMBLE, NL80211_ATTR_BSS_SHORT_SLOT_TIME, + NL80211_ATTR_HT_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; +/* + * Allow user space programs to use #ifdef on new attributes by defining them + * here + */ +#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY + #define NL80211_MAX_SUPP_RATES 32 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 +#define NL80211_HT_CAPABILITY_LEN 26 /** * enum nl80211_iftype - (virtual) interface types diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7afef14..0a72d1e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -152,6 +152,7 @@ struct station_parameters { u16 aid; u8 supported_rates_len; u8 plink_action; + struct ieee80211_ht_cap *ht_capa; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 2b19532..928813c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -674,6 +674,11 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->supp_rates[local->oper_channel->band] = rates; } + if (params->ht_capa) { + ieee80211_ht_cap_ie_to_ht_info(params->ht_capa, + &sta->ht_info); + } + if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { switch (params->plink_action) { case PLINK_ACTION_OPEN: diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 47542ee..4d6c02a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -91,6 +91,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, + + [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, + .len = NL80211_HT_CAPABILITY_LEN }, }; /* message building helper */ @@ -1129,6 +1132,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); + if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], ¶ms.station_flags)) return -EINVAL; @@ -1192,6 +1199,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) + params.ht_capa = + nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], ¶ms.station_flags)) -- cgit v0.10.2 From c83be6885e2f1ee6e0b290b6cfc82014c675e087 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 25 Aug 2008 20:47:29 +0530 Subject: ath9k: Add LED support Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 841893b..020b97f 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -757,14 +757,11 @@ struct ath9k_node_stats { #define ATH9K_RSSI_EP_MULTIPLIER (1<<7) -enum ath9k_gpio_output_mux_type { - ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES -}; +#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 +#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 +#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 enum { ATH9K_RESET_POWER_ON, @@ -1008,4 +1005,7 @@ void ath9k_hw_get_channel_centers(struct ath_hal *ah, bool ath9k_get_channel_edges(struct ath_hal *ah, u16 flags, u16 *low, u16 *high); +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); #endif diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index de1d12f..0692fc3 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -39,6 +39,7 @@ #include #include #include +#include #include "ath9k.h" #include "rc.h" @@ -803,6 +804,27 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv, void ath_setdefantenna(void *sc, u32 antenna); /********************/ +/* LED Control */ +/********************/ + +#define ATH_LED_PIN 1 + +enum ath_led_type { + ATH_LED_RADIO, + ATH_LED_ASSOC, + ATH_LED_TX, + ATH_LED_RX +}; + +struct ath_led { + struct ath_softc *sc; + struct led_classdev led_cdev; + enum ath_led_type led_type; + char name[32]; + bool registered; +}; + +/********************/ /* Main driver core */ /********************/ @@ -884,6 +906,7 @@ struct ath_ht_info { #define SC_OP_PREAMBLE_SHORT BIT(7) #define SC_OP_PROTECT_ENABLE BIT(8) #define SC_OP_RXFLUSH BIT(9) +#define SC_OP_LED_ASSOCIATED BIT(10) struct ath_softc { struct ieee80211_hw *hw; @@ -988,6 +1011,12 @@ struct ath_softc { spinlock_t sc_txbuflock; spinlock_t sc_resetlock; spinlock_t node_lock; + + /* LEDs */ + struct ath_led radio_led; + struct ath_led assoc_led; + struct ath_led tx_led; + struct ath_led rx_led; }; int ath_init(u16 devid, struct ath_softc *sc); diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 47c60ac..2578411 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -2800,32 +2800,11 @@ static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, } } -static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - enum ath9k_gpio_output_mux_type - halSignalType) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - u32 ah_signal_type; u32 gpio_shift; - static u32 MuxSignalConversionTable[] = { - - AR_GPIO_OUTPUT_MUX_AS_OUTPUT, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED, - - AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED, - - AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED, - }; - - if ((halSignalType >= 0) - && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable))) - ah_signal_type = MuxSignalConversionTable[halSignalType]; - else - return false; - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); gpio_shift = 2 * gpio; @@ -2834,16 +2813,12 @@ static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, AR_GPIO_OE_OUT, (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), (AR_GPIO_OE_OUT_DRV << gpio_shift)); - - return true; } -static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, - u32 val) +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) { REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), AR_GPIO_BIT(gpio)); - return true; } static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) @@ -5923,7 +5898,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, else ath9k_hw_set_gpio(ah, 9, 1); } - ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_cfg_output(ah, 9, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } ecode = ath9k_hw_process_ini(ah, chan, macmode); diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index dca00c3..996bb9c 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1172,12 +1172,130 @@ enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) return sc->sc_ht_info.tx_chan_width; } +/********************************/ +/* LED functions */ +/********************************/ + +static void ath_led_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); + struct ath_softc *sc = led->sc; + + switch (brightness) { + case LED_OFF: + if (led->led_type == ATH_LED_ASSOC || + led->led_type == ATH_LED_RADIO) + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, + (led->led_type == ATH_LED_RADIO) ? 1 : + !!(sc->sc_flags & SC_OP_LED_ASSOCIATED)); + break; + case LED_FULL: + if (led->led_type == ATH_LED_ASSOC) + sc->sc_flags |= SC_OP_LED_ASSOCIATED; + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0); + break; + default: + break; + } +} + +static int ath_register_led(struct ath_softc *sc, struct ath_led *led, + char *trigger) +{ + int ret; + + led->sc = sc; + led->led_cdev.name = led->name; + led->led_cdev.default_trigger = trigger; + led->led_cdev.brightness_set = ath_led_brightness; + + ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev); + if (ret) + DPRINTF(sc, ATH_DBG_FATAL, + "Failed to register led:%s", led->name); + else + led->registered = 1; + return ret; +} + +static void ath_unregister_led(struct ath_led *led) +{ + if (led->registered) { + led_classdev_unregister(&led->led_cdev); + led->registered = 0; + } +} + +static void ath_deinit_leds(struct ath_softc *sc) +{ + ath_unregister_led(&sc->assoc_led); + sc->sc_flags &= ~SC_OP_LED_ASSOCIATED; + ath_unregister_led(&sc->tx_led); + ath_unregister_led(&sc->rx_led); + ath_unregister_led(&sc->radio_led); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); +} + +static void ath_init_leds(struct ath_softc *sc) +{ + char *trigger; + int ret; + + /* Configure gpio 1 for output */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + /* LED off, active low */ + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + + trigger = ieee80211_get_radio_led_name(sc->hw); + snprintf(sc->radio_led.name, sizeof(sc->radio_led.name), + "ath9k-%s:radio", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->radio_led, trigger); + sc->radio_led.led_type = ATH_LED_RADIO; + if (ret) + goto fail; + + trigger = ieee80211_get_assoc_led_name(sc->hw); + snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name), + "ath9k-%s:assoc", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->assoc_led, trigger); + sc->assoc_led.led_type = ATH_LED_ASSOC; + if (ret) + goto fail; + + trigger = ieee80211_get_tx_led_name(sc->hw); + snprintf(sc->tx_led.name, sizeof(sc->tx_led.name), + "ath9k-%s:tx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->tx_led, trigger); + sc->tx_led.led_type = ATH_LED_TX; + if (ret) + goto fail; + + trigger = ieee80211_get_rx_led_name(sc->hw); + snprintf(sc->rx_led.name, sizeof(sc->rx_led.name), + "ath9k-%s:rx", wiphy_name(sc->hw->wiphy)); + ret = ath_register_led(sc, &sc->rx_led, trigger); + sc->rx_led.led_type = ATH_LED_RX; + if (ret) + goto fail; + + return; + +fail: + ath_deinit_leds(sc); +} + static int ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + /* Deinit LED control */ + ath_deinit_leds(sc); + /* Unregister hw */ ieee80211_unregister_hw(hw); @@ -1271,18 +1389,21 @@ static int ath_attach(u16 devid, goto bad; } + /* Initialize LED control */ + ath_init_leds(sc); + /* initialize tx/rx engine */ error = ath_tx_init(sc, ATH_TXBUF); if (error != 0) - goto bad1; + goto detach; error = ath_rx_init(sc, ATH_RXBUF); if (error != 0) - goto bad1; + goto detach; return 0; -bad1: +detach: ath_detach(sc); bad: return error; @@ -1427,6 +1548,10 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, 3); @@ -1436,6 +1561,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int ath_pci_resume(struct pci_dev *pdev) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; u32 val; int err; @@ -1452,6 +1579,11 @@ static int ath_pci_resume(struct pci_dev *pdev) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + /* Enable LED */ + ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN, + AR_GPIO_OUTPUT_MUX_AS_OUTPUT); + ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); + return 0; } diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 42b0890..60617ae 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -899,12 +899,6 @@ enum { #define AR_GPIO_OUTPUT_MUX2 0x4064 #define AR_GPIO_OUTPUT_MUX3 0x4068 -#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1 -#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5 -#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6 - #define AR_INPUT_STATE 0x406c #define AR_EEPROM_STATUS_DATA 0x407c -- cgit v0.10.2 From 822ceaefaaaea4bcd7965e3f4b3479e805f7dfa5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:10:29 +0530 Subject: ath9k: Remove more dead code Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 020b97f..28b8d84 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -628,11 +628,6 @@ struct ath9k_country_entry { (IEEE80211_WEP_IVLEN + \ IEEE80211_WEP_KIDLEN + \ IEEE80211_WEP_CRCLEN)) -#define IEEE80211_MAX_LEN (2300 + FCS_LEN + \ - (IEEE80211_WEP_IVLEN + \ - IEEE80211_WEP_KIDLEN + \ - IEEE80211_WEP_CRCLEN)) - #define MAX_RATE_POWER 63 enum ath9k_power_mode { diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index fdbabc1..c43fd58 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -454,31 +454,6 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) } /* - * Reclaim beacon resources and return buffer to the pool. - * - * This function will free any wbuf frames that are still attached to the - * beacon buffers in the ATH object. Note that this does not de-allocate - * any wbuf objects that are in the transmit queue and have not yet returned - * to the ATH object. -*/ - -void ath_beacon_free(struct ath_softc *sc) -{ - struct ath_buf *bf; - - list_for_each_entry(bf, &sc->sc_bbuf, list) { - if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu; - pci_unmap_single(sc->pdev, bf->bf_dmacontext, - skb_end_pointer(skb) - skb->head, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - } - } -} - -/* * Tasklet for Sending Beacons * * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 5cb3912..2113818 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -825,10 +825,6 @@ struct ath_hal_5416 { #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 -#define ar5416CheckOpMode(_opmode) \ - ((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) || \ - (_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR)) - #define AR5416_EEPROM_MAGIC_OFFSET 0x0 #define AR5416_EEPROM_S 2 diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 996bb9c..dc45eef 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -1167,11 +1167,6 @@ int ath_rx_subframe(struct ath_node *an, return 0; } -enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc) -{ - return sc->sc_ht_info.tx_chan_width; -} - /********************************/ /* LED functions */ /********************************/ -- cgit v0.10.2 From 14cc709f338f44f1ff69fa0b0e35e9de3ee62eb5 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:10:49 +0530 Subject: ath9k: Do not update frame's duration field When AR_DurUpdateEna is set, the frame's duration field is updated by the MAC based on the current rate. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index 0692fc3..b6b6868 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -516,7 +516,6 @@ struct ath_tx_control { u32 keyix; int min_rate; int mcast_rate; - u16 nextfraglen; struct ath_softc *dev; dma_addr_t dmacontext; }; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index a18cea6..87aebf1 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -227,7 +227,6 @@ static int ath_tx_prepare(struct ath_softc *sc, } txctl->if_id = 0; - txctl->nextfraglen = 0; txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); txctl->txpower = MAX_RATE_POWER; /* FIXME */ @@ -344,51 +343,18 @@ static int ath_tx_prepare(struct ath_softc *sc, } rix = rcs[0].rix; - /* - * Calculate duration. This logically belongs in the 802.11 - * layer but it lacks sufficient information to calculate it. - */ - if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) { - u16 dur; + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { /* - * XXX not right with fragmentation. - */ - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - dur = rt->info[rix].spAckDuration; - else - dur = rt->info[rix].lpAckDuration; - - if (le16_to_cpu(hdr->frame_control) & - IEEE80211_FCTL_MOREFRAGS) { - dur += dur; /* Add additional 'SIFS + ACK' */ - - /* - ** Compute size of next fragment in order to compute - ** durations needed to update NAV. - ** The last fragment uses the ACK duration only. - ** Add time for next fragment. - */ - dur += ath9k_hw_computetxtime(sc->sc_ah, rt, - txctl->nextfraglen, - rix, - (sc->sc_flags & SC_OP_PREAMBLE_SHORT)); - } - - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - /* - ** Force hardware to use computed duration for next - ** fragment by disabling multi-rate retry, which - ** updates duration based on the multi-rate - ** duration table. - */ - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; - /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; - } - - hdr->duration_id = cpu_to_le16(dur); + ** Force hardware to use computed duration for next + ** fragment by disabling multi-rate retry, which + ** updates duration based on the multi-rate + ** duration table. + */ + rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; + rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; + /* reset tries but keep rate index */ + rcs[0].tries = ATH_TXMAXTRY; } /* -- cgit v0.10.2 From 1fe1132bad8e98fa34cfb4a3901340d1214b95d7 Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:11:06 +0530 Subject: ath9k: Remove sc_lastrx as we don't use it anywhere Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index b6b6868..1faa1ef 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -970,7 +970,6 @@ struct ath_softc { struct ath_descdma sc_rxdma; int sc_rxbufsize; /* rx size based on mtu */ u32 *sc_rxlink; /* link ptr in last RX desc */ - u64 sc_lastrx; /* tsf of last rx'd frame */ /* TX */ struct list_head sc_txbuf; diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 87aebf1..3fc6641 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -2309,8 +2309,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) void ath_tx_tasklet(struct ath_softc *sc) { - u64 tsf = ath9k_hw_gettsf64(sc->sc_ah); - int i, nacked = 0; + int i; u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1); ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask); @@ -2320,10 +2319,8 @@ void ath_tx_tasklet(struct ath_softc *sc) */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - nacked += ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->sc_txq[i]); } - if (nacked) - sc->sc_lastrx = tsf; } void ath_tx_draintxq(struct ath_softc *sc, -- cgit v0.10.2 From 5701ed843ea87bf8a1d2c4dee5edcb463558db4a Mon Sep 17 00:00:00 2001 From: Sujith Date: Tue, 26 Aug 2008 08:11:26 +0530 Subject: ath9k: rc.h cleanup Use kernel doc syntax for comments and remove a few unused macros. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 1dd7c71..390019e 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -1141,14 +1141,14 @@ static void ath_rc_ratefind(struct ath_softc *sc, /* * Return the Tx rate series. */ -void ath_rate_findrate(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, - int num_rates, - unsigned int rcflag, - struct ath_rc_series series[], - int *is_probe, - int is_retry) +static void ath_rate_findrate(struct ath_softc *sc, + struct ath_rate_node *ath_rc_priv, + int num_tries, + int num_rates, + unsigned int rcflag, + struct ath_rc_series series[], + int *is_probe, + int is_retry) { struct ath_vap *avp = ath_rc_priv->avp; @@ -1942,7 +1942,7 @@ static void ath_get_rate(void *priv, struct net_device *dev, struct ath_rate_node *ath_rc_priv; struct ath_node *an; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe, chk, ret; + int is_probe = FALSE, chk, ret; s8 lowest_idx; __le16 fc = hdr->frame_control; u8 *qc, tid; diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index 71aef9c..b95b415 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -71,9 +71,6 @@ enum ieee80211_fixed_rate_mode { */ #define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) -#define SHORT_PRE 1 -#define LONG_PRE 0 - #define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS #define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS #define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI @@ -102,18 +99,18 @@ enum { WLAN_RC_PHY_MAX }; -#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) -#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ - || (_phy == WLAN_RC_PHY_HT_40_DS) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) +#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \ + || (_phy == WLAN_RC_PHY_HT_40_DS) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ - || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) + || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \ + || (_phy == WLAN_RC_PHY_HT_40_DS_HGI)) #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) @@ -135,56 +132,59 @@ enum { #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -/* Index into the rate table */ -#define INIT_RATE_MAX_20 23 -#define INIT_RATE_MAX_40 40 - #define RATE_TABLE_SIZE 64 -/* XXX: Convert to kdoc */ +/** + * struct ath_rate_table - Rate Control table + * @valid: valid for use in rate control + * @valid_single_stream: valid for use in rate control for + * single stream operation + * @phy: CCK/OFDM + * @ratekbps: rate in Kbits per second + * @user_ratekbps: user rate in Kbits per second + * @ratecode: rate that goes into HW descriptors + * @short_preamble: Mask for enabling short preamble in ratecode for CCK + * @dot11rate: value that goes into supported + * rates info element of MLME + * @ctrl_rate: Index of next lower basic rate, used for duration computation + * @max_4ms_framelen: maximum frame length(bytes) for tx duration + * @probe_interval: interval for rate control to probe for other rates + * @rssi_reduce_interval: interval for rate control to reduce rssi + * @initial_ratemax: initial ratemax value used in ath_rc_sib_update() + */ struct ath_rate_table { int rate_cnt; struct { - int valid; /* Valid for use in rate control */ - int valid_single_stream;/* Valid for use in rate control - for single stream operation */ - u8 phy; /* CCK/OFDM/TURBO/XR */ - u32 ratekbps; /* Rate in Kbits per second */ - u32 user_ratekbps; /* User rate in KBits per second */ - u8 ratecode; /* rate that goes into - hw descriptors */ - u8 short_preamble; /* Mask for enabling short preamble - in rate code for CCK */ - u8 dot11rate; /* Value that goes into supported - rates info element of MLME */ - u8 ctrl_rate; /* Index of next lower basic rate, - used for duration computation */ - int8_t rssi_ack_validmin; /* Rate control related */ - int8_t rssi_ack_deltamin; /* Rate control related */ - u8 base_index; /* base rate index */ - u8 cw40index; /* 40cap rate index */ - u8 sgi_index; /* shortgi rate index */ - u8 ht_index; /* shortgi rate index */ - u32 max_4ms_framelen; /* Maximum frame length(bytes) - for 4ms tx duration */ + int valid; + int valid_single_stream; + u8 phy; + u32 ratekbps; + u32 user_ratekbps; + u8 ratecode; + u8 short_preamble; + u8 dot11rate; + u8 ctrl_rate; + int8_t rssi_ack_validmin; + int8_t rssi_ack_deltamin; + u8 base_index; + u8 cw40index; + u8 sgi_index; + u8 ht_index; + u32 max_4ms_framelen; } info[RATE_TABLE_SIZE]; - u32 probe_interval; /* interval for ratectrl to - probe for other rates */ - u32 rssi_reduce_interval; /* interval for ratectrl - to reduce RSSI */ - u8 initial_ratemax; /* the initial ratemax value used - in ath_rc_sib_update() */ + u32 probe_interval; + u32 rssi_reduce_interval; + u8 initial_ratemax; }; #define ATH_RC_PROBE_ALLOWED 0x00000001 #define ATH_RC_MINRATE_LASTRATE 0x00000002 -#define ATH_RC_SHORT_PREAMBLE 0x00000004 struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; + u8 rix; + u8 tries; + u8 flags; + u32 max_4ms_framelen; }; /* rcs_flags definition */ @@ -201,42 +201,56 @@ struct ath_rc_series { #define MAX_TX_RATE_PHY 48 struct ath_tx_ratectrl_state { - int8_t rssi_thres; /* required rssi for this rate (dB) */ - u8 per; /* recent estimate of packet error rate (%) */ + int8_t rssi_thres; /* required rssi for this rate (dB) */ + u8 per; /* recent estimate of packet error rate (%) */ }; +/** + * struct ath_tx_ratectrl - TX Rate control Information + * @state: RC state + * @rssi_last: last ACK rssi + * @rssi_last_lookup: last ACK rssi used for lookup + * @rssi_last_prev: previous last ACK rssi + * @rssi_last_prev2: 2nd previous last ACK rssi + * @rssi_sum_cnt: count of rssi_sum for averaging + * @rssi_sum_rate: rate that we are averaging + * @rssi_sum: running sum of rssi for averaging + * @probe_rate: rate we are probing at + * @rssi_time: msec timestamp for last ack rssi + * @rssi_down_time: msec timestamp for last down step + * @probe_time: msec timestamp for last probe + * @hw_maxretry_pktcnt: num of packets since we got HW max retry error + * @max_valid_rate: maximum number of valid rate + * @per_down_time: msec timestamp for last PER down step + * @valid_phy_ratecnt: valid rate count + * @rate_max_phy: phy index for the max rate + * @probe_interval: interval for ratectrl to probe for other rates + */ struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */ - int8_t rssi_last; /* last ack rssi */ - int8_t rssi_last_lookup; /* last ack rssi used for lookup */ - int8_t rssi_last_prev; /* previous last ack rssi */ - int8_t rssi_last_prev2; /* 2nd previous last ack rssi */ - int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */ - int32_t rssi_sum_rate; /* rate that we are averaging */ - int32_t rssi_sum; /* running sum of rssi for averaging */ - u32 valid_txrate_mask; /* mask of valid rates */ - u8 rate_table_size; /* rate table size */ - u8 rate_max; /* max rate that has recently worked */ - u8 probe_rate; /* rate we are probing at */ - u32 rssi_time; /* msec timestamp for last ack rssi */ - u32 rssi_down_time; /* msec timestamp for last down step */ - u32 probe_time; /* msec timestamp for last probe */ - u8 hw_maxretry_pktcnt; /* num packets since we got - HW max retry error */ - u8 max_valid_rate; /* maximum number of valid rate */ - u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */ - u32 per_down_time; /* msec timstamp for last - PER down step */ + struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; + int8_t rssi_last; + int8_t rssi_last_lookup; + int8_t rssi_last_prev; + int8_t rssi_last_prev2; + int32_t rssi_sum_cnt; + int32_t rssi_sum_rate; + int32_t rssi_sum; + u8 rate_table_size; + u8 probe_rate; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u8 hw_maxretry_pktcnt; + u8 max_valid_rate; + u8 valid_rate_index[MAX_TX_RATE_TBL]; + u32 per_down_time; /* 11n state */ - u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */ - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; - u8 rc_phy_mode; - u8 rate_max_phy; /* Phy index for the max rate */ - u32 rate_max_lastused; /* msec timstamp of when we - last used rateMaxPhy */ - u32 probe_interval; /* interval for ratectrl to probe - for other rates */ + u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 rc_phy_mode; + u8 rate_max_phy; + u32 probe_interval; }; struct ath_rateset { @@ -248,29 +262,32 @@ struct ath_rateset { struct ath_rate_softc { /* phy tables that contain rate control data */ const void *hw_rate_table[ATH9K_MODE_MAX]; - int fixedrix; /* -1 or index of fixed rate */ + + /* -1 or index of fixed rate */ + int fixedrix; }; /* per-node state */ struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */ - u32 prev_data_rix; /* rate idx of last data frame */ + struct ath_tx_ratectrl tx_ratectrl; - /* map of rate ix -> negotiated rate set ix */ - u8 rixmap[MAX_TX_RATE_TBL]; + /* rate idx of last data frame */ + u32 prev_data_rix; - /* map of ht rate ix -> negotiated rate set ix */ - u8 ht_rixmap[MAX_TX_RATE_TBL]; + /* ht capabilities */ + u8 ht_cap; - u8 ht_cap; /* ht capabilities */ - u8 ant_tx; /* current transmit antenna */ + /* When TRUE, only single stream Tx possible */ + u8 single_stream; - u8 single_stream; /* When TRUE, only single - stream Tx possible */ - struct ath_rateset neg_rates; /* Negotiated rates */ - struct ath_rateset neg_ht_rates; /* Negotiated HT rates */ - struct ath_rate_softc *asc; /* back pointer to atheros softc */ - struct ath_vap *avp; /* back pointer to vap */ + /* Negotiated rates */ + struct ath_rateset neg_rates; + + /* Negotiated HT rates */ + struct ath_rateset neg_ht_rates; + + struct ath_rate_softc *asc; + struct ath_vap *avp; }; /* Driver data of ieee80211_tx_info */ @@ -297,17 +314,10 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp); /* - * Return the tx rate series. - */ -void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, - unsigned int rcflag, struct ath_rc_series[], - int *is_probe, int isretry); -/* * Return rate index for given Dot11 Rate. */ u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); + u8 dot11_rate); /* Routines to register/unregister rate control algorithm */ int ath_rate_control_register(void); -- cgit v0.10.2 From 849e0576a76bc421aacd782f97948856f487726c Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 26 Aug 2008 11:57:57 -0300 Subject: rfkill: use strict_strtoul (v2) Switch sysfs parsing to something that actually works properly. Signed-off-by: Henrique de Moraes Holschuh Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 47e0b2d..173d039 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -402,12 +402,16 @@ static ssize_t rfkill_state_store(struct device *dev, const char *buf, size_t count) { struct rfkill *rfkill = to_rfkill(dev); - unsigned int state = simple_strtoul(buf, NULL, 0); + unsigned long state; int error; if (!capable(CAP_NET_ADMIN)) return -EPERM; + error = strict_strtoul(buf, 0, &state); + if (error) + return error; + /* RFKILL_STATE_HARD_BLOCKED is illegal here... */ if (state != RFKILL_STATE_UNBLOCKED && state != RFKILL_STATE_SOFT_BLOCKED) @@ -435,7 +439,8 @@ static ssize_t rfkill_claim_store(struct device *dev, const char *buf, size_t count) { struct rfkill *rfkill = to_rfkill(dev); - bool claim = !!simple_strtoul(buf, NULL, 0); + unsigned long claim_tmp; + bool claim; int error; if (!capable(CAP_NET_ADMIN)) @@ -444,6 +449,11 @@ static ssize_t rfkill_claim_store(struct device *dev, if (rfkill->user_claim_unsupported) return -EOPNOTSUPP; + error = strict_strtoul(buf, 0, &claim_tmp); + if (error) + return error; + claim = !!claim_tmp; + /* * Take the global lock to make sure the kernel is not in * the middle of rfkill_switch_all -- cgit v0.10.2 From 01b510b9c29caf2134c31d2bc8c2c5cc73987eb6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 26 Aug 2008 11:57:58 -0300 Subject: rfkill: add missing line break Trivial patch adding a missing line break on rfkill_claim_show(). Signed-off-by: Felipe Balbi Acked-by: Henrique de Moraes Holschuh Acked-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 173d039..b630f35 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -431,7 +431,7 @@ static ssize_t rfkill_claim_show(struct device *dev, { struct rfkill *rfkill = to_rfkill(dev); - return sprintf(buf, "%d", rfkill->user_claim); + return sprintf(buf, "%d\n", rfkill->user_claim); } static ssize_t rfkill_claim_store(struct device *dev, -- cgit v0.10.2 From f745ba03a12a1c4b98a88a96ab39d9b58ac677a2 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 26 Aug 2008 11:57:59 -0300 Subject: rfkill: add WARN and BUG_ON paranoia (v2) BUG_ON() and WARN() the heck out of buggy drivers calling into the rfkill subsystem. Also switch from WARN_ON(1) to the new descriptive WARN(). Signed-off-by: Henrique de Moraes Holschuh Acked-by: Ivo van Doorn Cc: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index b630f35..910699c 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -76,6 +76,7 @@ static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); */ int register_rfkill_notifier(struct notifier_block *nb) { + BUG_ON(!nb); return blocking_notifier_chain_register(&rfkill_notifier_list, nb); } EXPORT_SYMBOL_GPL(register_rfkill_notifier); @@ -91,6 +92,7 @@ EXPORT_SYMBOL_GPL(register_rfkill_notifier); */ int unregister_rfkill_notifier(struct notifier_block *nb) { + BUG_ON(!nb); return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); } EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); @@ -202,6 +204,9 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, * RFKILL_STATE_HARD_BLOCKED */ break; default: + WARN(1, KERN_WARNING + "rfkill: illegal state %d passed as parameter " + "to rfkill_toggle_radio\n", state); return -EINVAL; } @@ -236,7 +241,11 @@ static void __rfkill_switch_all(const enum rfkill_type type, { struct rfkill *rfkill; - if (unlikely(state >= RFKILL_STATE_MAX)) + if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX), + KERN_WARNING + "rfkill: illegal state %d or type %d " + "passed as parameter to __rfkill_switch_all\n", + state, type)) return; rfkill_global_states[type].current_state = state; @@ -334,7 +343,11 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) { enum rfkill_state oldstate; - if (unlikely(state >= RFKILL_STATE_MAX)) + BUG_ON(!rfkill); + if (WARN((state >= RFKILL_STATE_MAX), + KERN_WARNING + "rfkill: illegal state %d passed as parameter " + "to rfkill_force_state\n", state)) return -EINVAL; mutex_lock(&rfkill->mutex); @@ -593,10 +606,10 @@ static int rfkill_check_duplicity(const struct rfkill *rfkill) memset(seen, 0, sizeof(seen)); list_for_each_entry(p, &rfkill_list, node) { - if (p == rfkill) { - WARN_ON(1); + if (WARN((p == rfkill), KERN_WARNING + "rfkill: illegal attempt to register " + "an already registered rfkill struct\n")) return -EEXIST; - } set_bit(p->type, seen); } @@ -664,6 +677,12 @@ struct rfkill * __must_check rfkill_allocate(struct device *parent, struct rfkill *rfkill; struct device *dev; + if (WARN((type >= RFKILL_TYPE_MAX), + KERN_WARNING + "rfkill: illegal type %d passed as parameter " + "to rfkill_allocate\n", type)) + return NULL; + rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL); if (!rfkill) return NULL; @@ -736,11 +755,12 @@ int __must_check rfkill_register(struct rfkill *rfkill) struct device *dev = &rfkill->dev; int error; - if (!rfkill->toggle_radio) - return -EINVAL; - if (rfkill->type >= RFKILL_TYPE_MAX) - return -EINVAL; - if (rfkill->state >= RFKILL_STATE_MAX) + if (WARN((!rfkill || !rfkill->toggle_radio || + rfkill->type >= RFKILL_TYPE_MAX || + rfkill->state >= RFKILL_STATE_MAX), + KERN_WARNING + "rfkill: attempt to register a " + "badly initialized rfkill struct\n")) return -EINVAL; snprintf(dev->bus_id, sizeof(dev->bus_id), @@ -775,6 +795,7 @@ EXPORT_SYMBOL(rfkill_register); */ void rfkill_unregister(struct rfkill *rfkill) { + BUG_ON(!rfkill); device_del(&rfkill->dev); rfkill_remove_switch(rfkill); rfkill_led_trigger_unregister(rfkill); @@ -811,9 +832,12 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) { int error; - if (type >= RFKILL_TYPE_MAX || - (state != RFKILL_STATE_SOFT_BLOCKED && - state != RFKILL_STATE_UNBLOCKED)) + if (WARN((type >= RFKILL_TYPE_MAX || + (state != RFKILL_STATE_SOFT_BLOCKED && + state != RFKILL_STATE_UNBLOCKED)), + KERN_WARNING + "rfkill: illegal state %d or type %d passed as " + "parameter to rfkill_set_default\n", state, type)) return -EINVAL; mutex_lock(&rfkill_mutex); -- cgit v0.10.2 From 15635744484d4255778fc641261be27179c51f9a Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 26 Aug 2008 11:58:00 -0300 Subject: rfkill: rename rfkill_mutex to rfkill_global_mutex rfkill_mutex and rfkill->mutex are too easy to confuse with each other. Rename rfkill_mutex to rfkill_global_mutex, so that they are easier to tell apart with just one glance. Signed-off-by: Henrique de Moraes Holschuh Acked-by: Ivo van Doorn Cc: Michael Buesch Signed-off-by: John W. Linville diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 910699c..d573579 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -37,7 +37,7 @@ MODULE_DESCRIPTION("RF switch support"); MODULE_LICENSE("GPL"); static LIST_HEAD(rfkill_list); /* list of registered rf switches */ -static DEFINE_MUTEX(rfkill_mutex); +static DEFINE_MUTEX(rfkill_global_mutex); static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; module_param_named(default_state, rfkill_default_state, uint, 0444); @@ -234,7 +234,7 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, * unless a specific switch is claimed by userspace (in which case, * that switch is left alone) or suspended. * - * Caller must have acquired rfkill_mutex. + * Caller must have acquired rfkill_global_mutex. */ static void __rfkill_switch_all(const enum rfkill_type type, const enum rfkill_state state) @@ -263,14 +263,14 @@ static void __rfkill_switch_all(const enum rfkill_type type, * @type: type of interfaces to be affected * @state: the new state * - * Acquires rfkill_mutex and calls __rfkill_switch_all(@type, @state). + * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). * Please refer to __rfkill_switch_all() for details. */ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) { - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); __rfkill_switch_all(type, state); - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); } EXPORT_SYMBOL(rfkill_switch_all); @@ -278,7 +278,7 @@ EXPORT_SYMBOL(rfkill_switch_all); * rfkill_epo - emergency power off all transmitters * * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, - * ignoring everything in its path but rfkill_mutex and rfkill->mutex. + * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. * * The global state before the EPO is saved and can be restored later * using rfkill_restore_states(). @@ -288,7 +288,8 @@ void rfkill_epo(void) struct rfkill *rfkill; int i; - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); + list_for_each_entry(rfkill, &rfkill_list, node) { mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); @@ -300,7 +301,7 @@ void rfkill_epo(void) rfkill_global_states[i].current_state = RFKILL_STATE_SOFT_BLOCKED; } - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); } EXPORT_SYMBOL_GPL(rfkill_epo); @@ -315,10 +316,11 @@ void rfkill_restore_states(void) { int i; - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); + for (i = 0; i < RFKILL_TYPE_MAX; i++) __rfkill_switch_all(i, rfkill_global_states[i].default_state); - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); } EXPORT_SYMBOL_GPL(rfkill_restore_states); @@ -471,7 +473,7 @@ static ssize_t rfkill_claim_store(struct device *dev, * Take the global lock to make sure the kernel is not in * the middle of rfkill_switch_all */ - error = mutex_lock_interruptible(&rfkill_mutex); + error = mutex_lock_interruptible(&rfkill_global_mutex); if (error) return error; @@ -486,7 +488,7 @@ static ssize_t rfkill_claim_store(struct device *dev, rfkill->user_claim = claim; } - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); return error ? error : count; } @@ -621,7 +623,7 @@ static int rfkill_add_switch(struct rfkill *rfkill) { int error; - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); error = rfkill_check_duplicity(rfkill); if (error < 0) @@ -642,16 +644,16 @@ static int rfkill_add_switch(struct rfkill *rfkill) error = 0; unlock_out: - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); return error; } static void rfkill_remove_switch(struct rfkill *rfkill) { - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); list_del_init(&rfkill->node); - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); @@ -840,7 +842,7 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) "parameter to rfkill_set_default\n", state, type)) return -EINVAL; - mutex_lock(&rfkill_mutex); + mutex_lock(&rfkill_global_mutex); if (!test_and_set_bit(type, rfkill_states_lockdflt)) { rfkill_global_states[type].default_state = state; @@ -848,7 +850,7 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) } else error = -EPERM; - mutex_unlock(&rfkill_mutex); + mutex_unlock(&rfkill_global_mutex); return error; } EXPORT_SYMBOL_GPL(rfkill_set_default); -- cgit v0.10.2 From de9cc7a4e6f975ca5e91cf8745b3e35a7e780bae Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Mon, 25 Aug 2008 14:06:32 -0700 Subject: libertas: use the common frame control functions Signed-off-by: Harvey Harrison Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index 2c1d680..c948021 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -477,9 +477,9 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) { struct ieee80211_rx_status stats; struct rxpd *prxpd; - bool is_qos, is_4addr, is_amsdu, need_padding; + int need_padding; unsigned int flags; - u16 fc, fc_le; + struct ieee80211_hdr *hdr; prxpd = (struct rxpd *) skb->data; @@ -497,19 +497,15 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) stats.rate_idx = prxpd->rx_rate; skb_pull(skb, sizeof(struct rxpd)); - fc_le = *((__le16 *) skb->data); - fc = le16_to_cpu(fc_le); + hdr = (struct ieee80211_hdr *)skb->data; flags = le32_to_cpu(*(__le32 *)(skb->data + 4)); - is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (fc & IEEE80211_STYPE_QOS_DATA); - is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); - is_amsdu = ((fc & 0x8C) == 0x88) && - (*(skb->data + ieee80211_hdrlen(fc_le) - QOS_CONTROL_LEN) - & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); + need_padding = ieee80211_is_data_qos(hdr->frame_control); + need_padding ^= ieee80211_has_a4(hdr->frame_control); + need_padding ^= ieee80211_is_data_qos(hdr->frame_control) && + (*ieee80211_get_qos_ctl(hdr) & + IEEE80211_QOS_CONTROL_A_MSDU_PRESENT); - need_padding = is_qos ^ is_4addr ^ is_amsdu; if (need_padding) { memmove(skb->data + 2, skb->data, skb->len); skb_reserve(skb, 2); -- cgit v0.10.2 From 0262ab0df64a67d4c0ed7577a29b7d866819cc68 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:04:26 +0200 Subject: rt2x00: Fix race conditions in flag handling Some of the flags should be accessed atomically to prevent race conditions. The flags that are most important are those that can change often and indicate the actual state of the device, queue or queue entry. The big flag rename was done to move all state flags to the same naming type as the other rt2x00dev flags and made sure all places where the flags were used were changed. ;) Thanks to Stephen for most of the queue flags updates, which fixes some of the most obvious consequences of the race conditions. Among those the notorious: rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. rt2x00queue_write_tx_frame: Error - Arrived at non-free entry in the non-full queue 0. Signed-off-by: Stephen Blackheath Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 0107cec..18b703c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1241,7 +1241,7 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index e0ff76f..5cc706a 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1377,7 +1377,7 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) if (!reg) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 3b90ed6..c6be4dd 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1297,7 +1297,7 @@ static void rt2500usb_beacondone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; - if (!test_bit(DEVICE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &entry->queue->rt2x00dev->flags)) return; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 3fa3d5b..08095bf 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -629,14 +629,14 @@ enum rt2x00_flags { /* * Device state flags */ - DEVICE_PRESENT, - DEVICE_REGISTERED_HW, - DEVICE_INITIALIZED, - DEVICE_STARTED, - DEVICE_STARTED_SUSPEND, - DEVICE_ENABLED_RADIO, - DEVICE_DISABLED_RADIO_HW, - DEVICE_DIRTY_CONFIG, + DEVICE_STATE_PRESENT, + DEVICE_STATE_REGISTERED_HW, + DEVICE_STATE_INITIALIZED, + DEVICE_STATE_STARTED, + DEVICE_STATE_STARTED_SUSPEND, + DEVICE_STATE_ENABLED_RADIO, + DEVICE_STATE_DISABLED_RADIO_HW, + DEVICE_STATE_DIRTY_CONFIG, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index ea37c79..ca051f5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -121,7 +121,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * Antenna setup changes require the RX to be disabled, * else the changes will be ignored by the device. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); /* @@ -136,7 +136,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00dev->link.ant.active.rx = libconf.ant.rx; rt2x00dev->link.ant.active.tx = libconf.ant.tx; - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 328ff8b..330ab77 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -34,7 +34,7 @@ */ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -94,8 +94,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) * Don't enable the radio twice. * And check if the hardware button has been disabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || - test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || + test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags)) return 0; /* @@ -117,7 +117,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00leds_led_radio(rt2x00dev, true); rt2x00led_led_activity(rt2x00dev, true); - __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags); + set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); /* * Enable RX. @@ -134,7 +134,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -354,7 +354,7 @@ static void rt2x00lib_link_tuner(struct work_struct *work) * When the radio is shutting down we should * immediately cease all link tuning. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; /* @@ -431,7 +431,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, * note that in the spinlock protected area above the delayed_flags * have been cleared correctly. */ - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; if (delayed_flags & DELAYED_UPDATE_BEACON) @@ -484,7 +484,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return; ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, @@ -572,7 +572,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); /* @@ -888,7 +888,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) { - if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { @@ -906,6 +906,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) struct hw_mode_spec *spec = &rt2x00dev->spec; int status; + if (test_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags)) + return 0; + /* * Initialize HW modes. */ @@ -927,7 +930,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags); + set_bit(DEVICE_STATE_REGISTERED_HW, &rt2x00dev->flags); return 0; } @@ -937,7 +940,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) */ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) { - if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return; /* @@ -960,7 +963,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) { int status; - if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags)) return 0; /* @@ -979,7 +982,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) return status; } - __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags); + set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags); /* * Register the extra components. @@ -993,7 +996,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) { int retval; - if (test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; /* @@ -1024,15 +1027,15 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - __set_bit(DEVICE_STARTED, &rt2x00dev->flags); - __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); + set_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); return 0; } void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) { - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return; /* @@ -1044,8 +1047,6 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; - - __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); } /* @@ -1100,7 +1101,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00rfkill_allocate(rt2x00dev); rt2x00debug_register(rt2x00dev); - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); return 0; @@ -1113,7 +1114,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) { - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * Disable radio. @@ -1158,14 +1159,15 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) int retval; NOTICE(rt2x00dev, "Going to sleep.\n"); - __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Only continue if mac80211 has open interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) goto exit; - __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags); + + set_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags); /* * Disable radio. @@ -1237,7 +1239,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Only continue if mac80211 had open interfaces. */ - if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags)) + if (!test_and_clear_bit(DEVICE_STATE_STARTED_SUSPEND, &rt2x00dev->flags)) return 0; /* @@ -1264,7 +1266,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * We are ready again to receive requests from mac80211. */ - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags); /* * It is possible that during that mac80211 has attempted @@ -1284,7 +1286,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) return 0; exit: - rt2x00lib_disable_radio(rt2x00dev); + rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 3af4273..11be895 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -117,7 +117,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * Note that we can only stop the TX queues inside the TX path * due to possible race conditions in mac80211. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) goto exit_fail; /* @@ -175,7 +175,7 @@ int rt2x00mac_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; return rt2x00lib_start(rt2x00dev); @@ -186,7 +186,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return; rt2x00lib_stop(rt2x00dev); @@ -206,8 +206,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * Don't allow interfaces to be added * the device has disappeared. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - !test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return -ENODEV; switch (conf->type) { @@ -256,7 +256,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, */ for (i = 0; i < queue->limit; i++) { entry = &queue->entries[i]; - if (!__test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) + if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) break; } @@ -310,7 +310,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * either the device has disappeared or when * no interface is present. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || (conf->type == IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_ap_count) || (conf->type != IEEE80211_IF_TYPE_AP && !rt2x00dev->intf_sta_count)) return; @@ -324,7 +324,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, * Release beacon entry so it is available for * new interfaces again. */ - __clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); + clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); /* * Make sure the bssid and mac address registers @@ -344,14 +344,14 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; /* * Check if we need to disable the radio, * if this is not the case, at least the RX must be disabled. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) { + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { if (!conf->radio_enabled) rt2x00lib_disable_radio(rt2x00dev); else @@ -366,14 +366,14 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * initialized. */ force_reconfig = - __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags); + test_and_clear_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); rt2x00lib_config(rt2x00dev, conf, force_reconfig); /* * Reenable RX only if the radio should be on. */ - if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); else if (conf->radio_enabled) return rt2x00lib_enable_radio(rt2x00dev); @@ -395,7 +395,7 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw, * Mac80211 might be calling this function while we are trying * to remove the device or perhaps suspending it. */ - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; spin_lock(&intf->lock); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index c0f97c5..d10a801 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -356,7 +356,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (unlikely(rt2x00queue_full(queue))) return -EINVAL; - if (__test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { + if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", @@ -396,7 +396,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) * the frame to mac80211 because the skb->cb has now been tainted. */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { - __clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); dev_kfree_skb_any(entry->skb); entry->skb = NULL; return 0; @@ -405,7 +405,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) rt2x00queue_map_txskb(queue->rt2x00dev, skb); - __set_bit(ENTRY_DATA_PENDING, &entry->flags); + set_bit(ENTRY_DATA_PENDING, &entry->flags); rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index 04b2971..8a2fefb 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -41,16 +41,16 @@ static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state) /* * Only continue if there are enabled interfaces. */ - if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) return 0; if (state == RFKILL_STATE_UNBLOCKED) { INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n"); - __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + clear_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); retval = rt2x00lib_enable_radio(rt2x00dev); } else if (state == RFKILL_STATE_SOFT_BLOCKED) { INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n"); - __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags); + set_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags); rt2x00lib_disable_radio(rt2x00dev); } else { WARNING(rt2x00dev, "Received unexpected rfkill state %d.\n", diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2050227..2dd7c83 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -163,7 +163,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct txdone_entry_desc txdesc; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; @@ -232,7 +232,7 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) { struct queue_entry_priv_usb *entry_priv = entry->priv_data; - if (__test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } @@ -283,7 +283,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u8 rxd[32]; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) || + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || !test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; @@ -293,7 +293,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * a problem. */ if (urb->actual_length < entry->queue->desc_size || urb->status) { - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(urb, GFP_ATOMIC); return; } @@ -361,7 +361,7 @@ void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, entry->skb->data, entry->skb->len, rt2x00usb_interrupt_rxdone, entry); - __set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 23cf93d..9d27ce0 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2121,7 +2121,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) if (!reg && !reg_mcu) return IRQ_NONE; - if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; /* -- cgit v0.10.2 From 3ee54a07d34fd9b5c34bb1488113fb32be58e38f Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:04:50 +0200 Subject: rt2x00: Map extra_tx_headroom to DMA If a driver requests additional headroom it should be mapped to DMA as well because it will be send to the hardware as well (as form of extra descriptor). Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index d10a801..2822684 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -100,8 +100,21 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - skbdesc->skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len, - DMA_TO_DEVICE); + /* + * If device has requested headroom, we should make sure that + * is also mapped to the DMA so it can be used for transfering + * additional descriptor information to the hardware. + */ + skb_push(skb, rt2x00dev->hw->extra_tx_headroom); + + skbdesc->skb_dma = + dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + + /* + * Restore data pointer to original location again. + */ + skb_pull(skb, rt2x00dev->hw->extra_tx_headroom); + skbdesc->flags |= SKBDESC_DMA_MAPPED_TX; } EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb); @@ -117,7 +130,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb) } if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) { - dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len, + /* + * Add headroom to the skb length, it has been removed + * by the driver, but it was actually mapped to DMA. + */ + dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, + skb->len + rt2x00dev->hw->extra_tx_headroom, DMA_TO_DEVICE); skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX; } -- cgit v0.10.2 From 2575c11d6ee7266f0f035e55c5056b36597cd336 Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 29 Aug 2008 21:05:21 +0200 Subject: rt2x00: Only configure hardware when radio is enabled Some hardware configuration registers such as antenna and channel configuration can only be written when the radio is enabled. Previously, we didn't consider this, so some configuration items could be set inconsistently after reenabling the radio. This patch changes the config() handler to only reprogram the hardware when the radio is enabled. Configuration changes that are made while the radio is off are postponed until the radio is switched back on. We also leave the radio turned off during initialization and only enable it when requested by mac80211. This allows us to get rid of the DIRTY_CONFIG flag, because the device is now guaranteed to be completely initialized when brought up by mac80211. Signed-off-by: Mattias Nissler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 08095bf..5e4f783 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -636,7 +636,6 @@ enum rt2x00_flags { DEVICE_STATE_STARTED_SUSPEND, DEVICE_STATE_ENABLED_RADIO, DEVICE_STATE_DISABLED_RADIO_HW, - DEVICE_STATE_DIRTY_CONFIG, /* * Driver requirements diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 330ab77..5278ae2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1014,21 +1014,11 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) if (retval) return retval; - /* - * Enable radio. - */ - retval = rt2x00lib_enable_radio(rt2x00dev); - if (retval) { - rt2x00lib_uninitialize(rt2x00dev); - return retval; - } - rt2x00dev->intf_ap_count = 0; rt2x00dev->intf_sta_count = 0; rt2x00dev->intf_associated = 0; set_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags); - set_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 11be895..64292c2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -338,7 +338,8 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; - int force_reconfig; + int radio_on; + int status; /* * Mac80211 might be calling this function while we are trying @@ -348,35 +349,34 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return 0; /* - * Check if we need to disable the radio, - * if this is not the case, at least the RX must be disabled. + * Only change device state when the radio is enabled. It does not + * matter what parameters we have configured when the radio is disabled + * because we won't be able to send or receive anyway. Also note that + * some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled. */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { - if (!conf->radio_enabled) - rt2x00lib_disable_radio(rt2x00dev); - else - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - } + radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); + if (conf->radio_enabled) { + /* For programming the values, we have to turn RX off */ + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); - /* - * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently - * been started and the configuration must be forced upon the hardware. - * Otherwise registers will not be intialized correctly and could - * result in non-working hardware because essential registers aren't - * initialized. - */ - force_reconfig = - test_and_clear_bit(DEVICE_STATE_DIRTY_CONFIG, &rt2x00dev->flags); + /* Enable the radio */ + status = rt2x00lib_enable_radio(rt2x00dev); + if (unlikely(status)) + return status; - rt2x00lib_config(rt2x00dev, conf, force_reconfig); + /* + * When we've just turned on the radio, we want to reprogram + * everything to ensure a consistent state + */ + rt2x00lib_config(rt2x00dev, conf, !radio_on); - /* - * Reenable RX only if the radio should be on. - */ - if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); - else if (conf->radio_enabled) - return rt2x00lib_enable_radio(rt2x00dev); + } else { + /* Disable the radio */ + rt2x00lib_disable_radio(rt2x00dev); + } return 0; } -- cgit v0.10.2 From 2af0a570b45ec315f364ea2c8a6d072cfcaa9d32 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:05:45 +0200 Subject: rt2x00: Initialize txop during conf_tx() callback The txop parameter is supported by rt61pci and rt73usb, and thus should be written to the register instead of using the fixed value set during initialization. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 64292c2..56829fa 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -666,10 +666,11 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ queue->aifs = params->aifs; + queue->txop = params->txop; INFO(rt2x00dev, - "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d.\n", - queue_idx, queue->cw_min, queue->cw_max, queue->aifs); + "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n", + queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2822684..a5e9650 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -736,6 +736,7 @@ static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, queue->rt2x00dev = rt2x00dev; queue->qid = qid; + queue->txop = 0; queue->aifs = 2; queue->cw_min = 5; queue->cw_max = 10; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 37f3f98..654fa0c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -368,6 +368,7 @@ enum queue_index { * @length: Number of frames in queue. * @index: Index pointers to entry positions in the queue, * use &enum queue_index to get a specific index field. + * @txop: maximum burst time. * @aifs: The aifs value for outgoing frames (field ignored in RX queue). * @cw_min: The cw min value for outgoing frames (field ignored in RX queue). * @cw_max: The cw max value for outgoing frames (field ignored in RX queue). @@ -387,6 +388,7 @@ struct data_queue { unsigned short length; unsigned short index[Q_INDEX_MAX]; + unsigned short txop; unsigned short aifs; unsigned short cw_min; unsigned short cw_max; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 9d27ce0..5253710 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1478,16 +1478,6 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - /* * Clear all beacons * For the Beacon base registers we only need to clear @@ -2652,6 +2642,63 @@ static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2679,7 +2726,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index f58fd05..636b4e0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1277,16 +1277,6 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC0_TX_OP, 0); - rt2x00_set_field32(®, AC_TXOP_CSR0_AC1_TX_OP, 0); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); - - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC2_TX_OP, 192); - rt2x00_set_field32(®, AC_TXOP_CSR1_AC3_TX_OP, 48); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); @@ -2246,6 +2236,63 @@ static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, return 0; } +static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, + const struct ieee80211_tx_queue_params *params) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + struct rt2x00_field32 field; + int retval; + u32 reg; + + /* + * First pass the configuration through rt2x00lib, that will + * update the queue settings and validate the input. After that + * we are free to update the registers based on the value + * in the queue parameter. + */ + retval = rt2x00mac_conf_tx(hw, queue_idx, params); + if (retval) + return retval; + + queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + + /* Update WMM TXOP register */ + if (queue_idx < 2) { + field.bit_offset = queue_idx * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + } else if (queue_idx < 4) { + field.bit_offset = (queue_idx - 2) * 16; + field.bit_mask = 0xffff << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00_set_field32(®, field, queue->txop); + rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + } + + /* Update WMM registers */ + field.bit_offset = queue_idx * 4; + field.bit_mask = 0xf << field.bit_offset; + + rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00_set_field32(®, field, queue->aifs); + rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_min); + rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + + rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00_set_field32(®, field, queue->cw_max); + rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + + return 0; +} + #if 0 /* * Mac80211 demands get_tsf must be atomic. @@ -2283,7 +2330,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, - .conf_tx = rt2x00mac_conf_tx, + .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, }; -- cgit v0.10.2 From 6c6aa3c004e702532cb0f549a96eb2f75636bd3b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:07:16 +0200 Subject: rt2x00: Add Signal type flag Instead of using the PLCP flag to indicate if the signal value is plcp or the bitrate we should add a new flag to mark the bitrate type explicitely. This is usefull when new types are added later for rt2800. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 5cc706a..2a96a01 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1316,6 +1316,8 @@ static void rt2500pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c6be4dd..c5f49e3 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1280,6 +1280,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5278ae2..369b0b2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -653,7 +653,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, if (((rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && (rate->plcp == rxdesc.signal)) || - (!(rxdesc.dev_flags & RXDONE_SIGNAL_PLCP) && + ((rxdesc.dev_flags & RXDONE_SIGNAL_BITRATE) && (rate->bitrate == rxdesc.signal))) { idx = i; break; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 654fa0c..9dbf04f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -140,13 +140,14 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) /** * enum rxdone_entry_desc_flags: Flags for &struct rxdone_entry_desc * - * @RXDONE_SIGNAL_PLCP: Does the signal field contain the plcp value, - * or does it contain the bitrate itself. + * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. + * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, - RXDONE_MY_BSS = 1 << 1, + RXDONE_SIGNAL_BITRATE = 1 << 1, + RXDONE_MY_BSS = 1 << 2, }; /** diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 5253710..d740f56 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1991,6 +1991,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 636b4e0..cf236ec 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1766,6 +1766,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_OFDM)) rxdesc->dev_flags |= RXDONE_SIGNAL_PLCP; + else + rxdesc->dev_flags |= RXDONE_SIGNAL_BITRATE; if (rt2x00_get_field32(word0, RXD_W0_MY_BSS)) rxdesc->dev_flags |= RXDONE_MY_BSS; -- cgit v0.10.2 From 1abc3656e961e62218257a85b3fe0a90ccd9036c Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Fri, 29 Aug 2008 21:07:20 +0200 Subject: rt2x00: skb->data pointer should not include TX descriptor Make sure the skb->data pointer points to the frame data, not the TX descriptor. The frame dumping code relies on that. Signed-off-by: Mattias Nissler Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index c5f49e3..0e008b6 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1114,8 +1114,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 2dd7c83..b73a7e0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -168,11 +168,6 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) return; /* - * Remove the descriptor data from the buffer. - */ - skb_pull(entry->skb, entry->queue->desc_size); - - /* * Obtain the status about this packet. * Note that when the status is 0 it does not mean the * frame was send out correctly. It only means the frame @@ -224,6 +219,12 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); + /* + * Make sure the skb->data pointer points to the frame, not the + * descriptor. + */ + skb_pull(entry->skb, entry->queue->desc_size); + return 0; } EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cf236ec..e698ae0 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1556,8 +1556,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_KEY_TABLE, test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, - skb->len - skbdesc->desc_len); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher); -- cgit v0.10.2 From 35e032d82f3e2a9b0d92077b4fbc97166525ed53 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 29 Aug 2008 21:07:22 +0200 Subject: rt2x00: Release rt2x00 2.2.1 Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 5e4f783..6f296ce 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.2.0" +#define DRV_VERSION "2.2.1" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* -- cgit v0.10.2 From ef1a628d83fc0423c36e773281162be790503168 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 27 Aug 2008 18:53:02 +0200 Subject: b43: Implement dynamic PHY API This patch implements a dynamic "ops" based PHY API. This is needed in order to conveniently support future PHY types to avoid the "switch"-hell. This patch does not change any functionality. It just moves lots of code from one place to another and adjusts it for the changed data structures. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 8c52b0b..fb6ffce 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,7 +1,9 @@ b43-y += main.o b43-y += tables.o b43-$(CONFIG_B43_NPHY) += tables_nphy.o -b43-y += phy.o +b43-y += phy_common.o +b43-y += phy_g.o +b43-y += phy_a.o b43-$(CONFIG_B43_NPHY) += nphy.o b43-y += sysfs.o b43-y += xmit.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index edcdfa3..fc28015 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -12,7 +12,7 @@ #include "leds.h" #include "rfkill.h" #include "lo.h" -#include "phy.h" +#include "phy_common.h" /* The unique identifier of the firmware that's officially supported by @@ -508,122 +508,6 @@ struct b43_iv { } __attribute__((__packed__)); -struct b43_phy { - /* Band support flags. */ - bool supports_2ghz; - bool supports_5ghz; - - /* GMODE bit enabled? */ - bool gmode; - - /* Analog Type */ - u8 analog; - /* B43_PHYTYPE_ */ - u8 type; - /* PHY revision number. */ - u8 rev; - - /* Radio versioning */ - u16 radio_manuf; /* Radio manufacturer */ - u16 radio_ver; /* Radio version */ - u8 radio_rev; /* Radio revision */ - - bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ - - /* ACI (adjacent channel interference) flags. */ - bool aci_enable; - bool aci_wlan_automatic; - bool aci_hw_rssi; - - /* Radio switched on/off */ - bool radio_on; - struct { - /* Values saved when turning the radio off. - * They are needed when turning it on again. */ - bool valid; - u16 rfover; - u16 rfoverval; - } radio_off_context; - - u16 minlowsig[2]; - u16 minlowsigpos[2]; - - /* TSSI to dBm table in use */ - const s8 *tssi2dbm; - /* Target idle TSSI */ - int tgt_idle_tssi; - /* Current idle TSSI */ - int cur_idle_tssi; - - /* LocalOscillator control values. */ - struct b43_txpower_lo_control *lo_control; - /* Values from b43_calc_loopback_gain() */ - s16 max_lb_gain; /* Maximum Loopback gain in hdB */ - s16 trsw_rx_gain; /* TRSW RX gain in hdB */ - s16 lna_lod_gain; /* LNA lod */ - s16 lna_gain; /* LNA */ - s16 pga_gain; /* PGA */ - - /* Desired TX power level (in dBm). - * This is set by the user and adjusted in b43_phy_xmitpower(). */ - u8 power_level; - /* A-PHY TX Power control value. */ - u16 txpwr_offset; - - /* Current TX power level attenuation control values */ - struct b43_bbatt bbatt; - struct b43_rfatt rfatt; - u8 tx_control; /* B43_TXCTL_XXX */ - - /* Hardware Power Control enabled? */ - bool hardware_power_control; - - /* Current Interference Mitigation mode */ - int interfmode; - /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: - * bit 0-11: offset - * bit 12-15: register ID - * bit 16-32: value - * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT - */ -#define B43_INTERFSTACK_SIZE 26 - u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure - - /* Saved values from the NRSSI Slope calculation */ - s16 nrssi[2]; - s32 nrssislope; - /* In memory nrssi lookup table. */ - s8 nrssi_lt[64]; - - /* current channel */ - u8 channel; - - u16 lofcal; - - u16 initval; //FIXME rename? - - /* PHY TX errors counter. */ - atomic_t txerr_cnt; - - /* The device does address auto increment for the OFDM tables. - * We cache the previously used address here and omit the address - * write on the next table access, if possible. */ - u16 ofdmtab_addr; /* The address currently set in hardware. */ - enum { /* The last data flow direction. */ - B43_OFDMTAB_DIRECTION_UNKNOWN = 0, - B43_OFDMTAB_DIRECTION_READ, - B43_OFDMTAB_DIRECTION_WRITE, - } ofdmtab_addr_direction; - -#if B43_DEBUG - /* Manual TX-power control enabled? */ - bool manual_txpower_control; - /* PHY registers locked by b43_phy_lock()? */ - bool phy_locked; -#endif /* B43_DEBUG */ -}; - /* Data structures for DMA transmission, per 80211 core. */ struct b43_dma { struct b43_dmaring *tx_ring_AC_BK; /* Background */ @@ -908,6 +792,15 @@ static inline int b43_is_mode(struct b43_wl *wl, int type) return (wl->operating && wl->if_type == type); } +/** + * b43_current_band - Returns the currently used band. + * Returns one of IEEE80211_BAND_2GHZ and IEEE80211_BAND_5GHZ. + */ +static inline enum ieee80211_band b43_current_band(struct b43_wl *wl) +{ + return wl->hw->conf.channel->band; +} + static inline u16 b43_read16(struct b43_wldev *dev, u16 offset) { return ssb_read16(dev->dev, offset); diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 29851bc..06a01da 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -443,76 +443,6 @@ out_unlock: return count; } -static ssize_t txpower_g_read_file(struct b43_wldev *dev, - char *buf, size_t bufsize) -{ - ssize_t count = 0; - - if (dev->phy.type != B43_PHYTYPE_G) { - fappend("Device is not a G-PHY\n"); - goto out; - } - fappend("Control: %s\n", dev->phy.manual_txpower_control ? - "MANUAL" : "AUTOMATIC"); - fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att); - fappend("Radio attenuation: %u\n", dev->phy.rfatt.att); - fappend("TX Mixer Gain: %s\n", - (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF"); - fappend("PA Gain 2dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF"); - fappend("PA Gain 3dB: %s\n", - (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF"); - fappend("\n\n"); - fappend("You can write to this file:\n"); - fappend("Writing \"auto\" enables automatic txpower control.\n"); - fappend - ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" " - "enables manual txpower control.\n"); - fappend("Example: 5 4 0 0 1\n"); - fappend("Enables manual control with Baseband attenuation 5, " - "Radio attenuation 4, No TX Mixer Gain, " - "No PA Gain 2dB, With PA Gain 3dB.\n"); -out: - return count; -} - -static int txpower_g_write_file(struct b43_wldev *dev, - const char *buf, size_t count) -{ - if (dev->phy.type != B43_PHYTYPE_G) - return -ENODEV; - if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { - /* Automatic control */ - dev->phy.manual_txpower_control = 0; - b43_phy_xmitpower(dev); - } else { - int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0; - /* Manual control */ - if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt, - &txmix, &pa2db, &pa3db) != 5) - return -EINVAL; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - dev->phy.manual_txpower_control = 1; - dev->phy.bbatt.att = bbatt; - dev->phy.rfatt.att = rfatt; - dev->phy.tx_control = 0; - if (txmix) - dev->phy.tx_control |= B43_TXCTL_TXMIX; - if (pa2db) - dev->phy.tx_control |= B43_TXCTL_PA2DB; - if (pa3db) - dev->phy.tx_control |= B43_TXCTL_PA3DB; - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &dev->phy.bbatt, - &dev->phy.rfatt, dev->phy.tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - } - - return 0; -} - /* wl->irq_lock is locked */ static int restart_write_file(struct b43_wldev *dev, const char *buf, size_t count) @@ -560,7 +490,7 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, err = -ENODEV; goto out; } - lo = phy->lo_control; + lo = phy->g->lo_control; fappend("-- Local Oscillator calibration data --\n\n"); fappend("HW-power-control enabled: %d\n", dev->phy.hardware_power_control); @@ -578,8 +508,8 @@ static ssize_t loctls_read_file(struct b43_wldev *dev, list_for_each_entry(cal, &lo->calib_list, list) { bool active; - active = (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)); + active = (b43_compare_bbatt(&cal->bbatt, &phy->g->bbatt) && + b43_compare_rfatt(&cal->rfatt, &phy->g->rfatt)); fappend("BB(%d), RF(%d,%d) -> I=%d, Q=%d " "(expires in %lu sec)%s\n", cal->bbatt.att, @@ -763,7 +693,6 @@ B43_DEBUGFS_FOPS(mmio32read, mmio32read__read_file, mmio32read__write_file, 1); B43_DEBUGFS_FOPS(mmio32write, NULL, mmio32write__write_file, 1); B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1); B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0); -B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0); B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1); B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0); @@ -877,7 +806,6 @@ void b43_debugfs_add_device(struct b43_wldev *dev) ADD_FILE(mmio32write, 0200); ADD_FILE(tsf, 0600); ADD_FILE(txstat, 0400); - ADD_FILE(txpower_g, 0600); ADD_FILE(restart, 0200); ADD_FILE(loctls, 0400); @@ -907,7 +835,6 @@ void b43_debugfs_remove_device(struct b43_wldev *dev) debugfs_remove(e->file_mmio32write.dentry); debugfs_remove(e->file_tsf.dentry); debugfs_remove(e->file_txstat.dentry); - debugfs_remove(e->file_txpower_g.dentry); debugfs_remove(e->file_restart.dentry); debugfs_remove(e->file_loctls.dentry); diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 9c854d6..6a18a14 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -29,7 +29,7 @@ #include "b43.h" #include "lo.h" -#include "phy.h" +#include "phy_g.h" #include "main.h" #include @@ -174,7 +174,8 @@ static u16 lo_txctl_register_table(struct b43_wldev *dev, static void lo_measure_txctl_values(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 reg, mask; u16 trsw_rx, pga; u16 radio_pctl_reg; @@ -195,7 +196,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) int lb_gain; /* Loopback gain (in dB) */ trsw_rx = 0; - lb_gain = phy->max_lb_gain / 2; + lb_gain = gphy->max_lb_gain / 2; if (lb_gain > 10) { radio_pctl_reg = 0; pga = abs(10 - lb_gain) / 6; @@ -226,7 +227,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) } b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | radio_pctl_reg); - b43_phy_set_baseband_attenuation(dev, 2); + b43_gphy_set_baseband_attenuation(dev, 2); reg = lo_txctl_register_table(dev, &mask, NULL); mask = ~mask; @@ -277,7 +278,8 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) static void lo_read_power_vector(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; u64 tmp; u64 power_vector = 0; @@ -298,6 +300,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, s16 max_rx_gain, int use_trsw_rx) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (max_rx_gain < 0) @@ -308,7 +311,7 @@ static void lo_measure_gain_values(struct b43_wldev *dev, int trsw_rx_gain; if (use_trsw_rx) { - trsw_rx_gain = phy->trsw_rx_gain / 2; + trsw_rx_gain = gphy->trsw_rx_gain / 2; if (max_rx_gain >= trsw_rx_gain) { trsw_rx_gain = max_rx_gain - trsw_rx_gain; trsw_rx = 0x20; @@ -316,38 +319,38 @@ static void lo_measure_gain_values(struct b43_wldev *dev, } else trsw_rx_gain = max_rx_gain; if (trsw_rx_gain < 9) { - phy->lna_lod_gain = 0; + gphy->lna_lod_gain = 0; } else { - phy->lna_lod_gain = 1; + gphy->lna_lod_gain = 1; trsw_rx_gain -= 8; } trsw_rx_gain = clamp_val(trsw_rx_gain, 0, 0x2D); - phy->pga_gain = trsw_rx_gain / 3; - if (phy->pga_gain >= 5) { - phy->pga_gain -= 5; - phy->lna_gain = 2; + gphy->pga_gain = trsw_rx_gain / 3; + if (gphy->pga_gain >= 5) { + gphy->pga_gain -= 5; + gphy->lna_gain = 2; } else - phy->lna_gain = 0; + gphy->lna_gain = 0; } else { - phy->lna_gain = 0; - phy->trsw_rx_gain = 0x20; + gphy->lna_gain = 0; + gphy->trsw_rx_gain = 0x20; if (max_rx_gain >= 0x14) { - phy->lna_lod_gain = 1; - phy->pga_gain = 2; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 2; } else if (max_rx_gain >= 0x12) { - phy->lna_lod_gain = 1; - phy->pga_gain = 1; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 1; } else if (max_rx_gain >= 0xF) { - phy->lna_lod_gain = 1; - phy->pga_gain = 0; + gphy->lna_lod_gain = 1; + gphy->pga_gain = 0; } else { - phy->lna_lod_gain = 0; - phy->pga_gain = 0; + gphy->lna_lod_gain = 0; + gphy->pga_gain = 0; } } tmp = b43_radio_read16(dev, 0x7A); - if (phy->lna_lod_gain == 0) + if (gphy->lna_lod_gain == 0) tmp &= ~0x0008; else tmp |= 0x0008; @@ -392,10 +395,11 @@ static void lo_measure_setup(struct b43_wldev *dev, { struct ssb_sprom *sprom = &dev->dev->bus->sprom; struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; u16 tmp; - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); @@ -496,7 +500,7 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) b43_dummy_transmission(dev); - b43_radio_selectchannel(dev, 6, 0); + b43_gphy_channel_switch(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); @@ -520,18 +524,19 @@ static void lo_measure_restore(struct b43_wldev *dev, struct lo_g_saved_values *sav) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; u16 tmp; if (phy->rev >= 2) { b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); - tmp = (phy->pga_gain << 8); + tmp = (gphy->pga_gain << 8); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0); udelay(5); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2); udelay(2); b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3); } else { - tmp = (phy->pga_gain | 0xEFA0); + tmp = (gphy->pga_gain | 0xEFA0); b43_phy_write(dev, B43_PHY_PGACTL, tmp); } if (phy->type == B43_PHYTYPE_G) { @@ -572,7 +577,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); } - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { tmp = (sav->phy_lo_mask & 0xBFFF); b43_phy_write(dev, B43_PHY_LO_MASK, tmp); b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); @@ -580,7 +585,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); } - b43_radio_selectchannel(dev, sav->old_channel, 1); + b43_gphy_channel_switch(dev, sav->old_channel, 1); } struct b43_lo_g_statemachine { @@ -597,6 +602,7 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, struct b43_lo_g_statemachine *d) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl test_loctl; struct b43_loctl orig_loctl; struct b43_loctl prev_loctl = { @@ -646,9 +652,9 @@ static int lo_probe_possible_loctls(struct b43_wldev *dev, test_loctl.q != prev_loctl.q) && (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) { b43_lo_write(dev, &test_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < d->lowest_feedth) { memcpy(probe_loctl, &test_loctl, sizeof(struct b43_loctl)); @@ -677,6 +683,7 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, int *max_rx_gain) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_lo_g_statemachine d; u16 feedth; int found_lower; @@ -693,17 +700,17 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, max_repeat = 4; do { b43_lo_write(dev, &d.min_loctl); - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); if (feedth < 0x258) { if (feedth >= 0x12C) *max_rx_gain += 6; else *max_rx_gain += 3; - feedth = lo_measure_feedthrough(dev, phy->lna_gain, - phy->pga_gain, - phy->trsw_rx_gain); + feedth = lo_measure_feedthrough(dev, gphy->lna_gain, + gphy->pga_gain, + gphy->trsw_rx_gain); } d.lowest_feedth = feedth; @@ -752,6 +759,7 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, const struct b43_rfatt *rfatt) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; struct b43_loctl loctl = { .i = 0, .q = 0, @@ -782,11 +790,11 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, if (rfatt->with_padmix) max_rx_gain -= pad_mix_gain; if (has_loopback_gain(phy)) - max_rx_gain += phy->max_lb_gain; + max_rx_gain += gphy->max_lb_gain; lo_measure_gain_values(dev, max_rx_gain, has_loopback_gain(phy)); - b43_phy_set_baseband_attenuation(dev, bbatt->att); + b43_gphy_set_baseband_attenuation(dev, bbatt->att); lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain); lo_measure_restore(dev, &saved_regs); @@ -820,7 +828,7 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, const struct b43_bbatt *bbatt, const struct b43_rfatt *rfatt) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *c; c = b43_find_lo_calib(lo, bbatt, rfatt); @@ -839,7 +847,8 @@ struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; int i; int rf_offset, bb_offset; const struct b43_rfatt *rfatt; @@ -917,14 +926,14 @@ static inline void b43_lo_fixup_rfatt(struct b43_rfatt *rf) void b43_lo_g_adjust(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; struct b43_lo_calib *cal; struct b43_rfatt rf; - memcpy(&rf, &phy->rfatt, sizeof(rf)); + memcpy(&rf, &gphy->rfatt, sizeof(rf)); b43_lo_fixup_rfatt(&rf); - cal = b43_get_calib_lo_settings(dev, &phy->bbatt, &rf); + cal = b43_get_calib_lo_settings(dev, &gphy->bbatt, &rf); if (!cal) return; b43_lo_write(dev, &cal->ctl); @@ -952,7 +961,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_lo_g_maintanance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; unsigned long now; unsigned long expire; struct b43_lo_calib *cal, *tmp; @@ -962,7 +972,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!lo) return; now = jiffies; - hwpctl = b43_has_hardware_pctl(phy); + hwpctl = b43_has_hardware_pctl(dev); if (hwpctl) { /* Read the power vector and update it, if needed. */ @@ -983,8 +993,8 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) if (!time_before(cal->calib_time, expire)) continue; /* This item expired. */ - if (b43_compare_bbatt(&cal->bbatt, &phy->bbatt) && - b43_compare_rfatt(&cal->rfatt, &phy->rfatt)) { + if (b43_compare_bbatt(&cal->bbatt, &gphy->bbatt) && + b43_compare_rfatt(&cal->rfatt, &gphy->rfatt)) { B43_WARN_ON(current_item_expired); current_item_expired = 1; } @@ -1002,7 +1012,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) /* Recalibrate currently used LO setting. */ if (b43_debug(dev, B43_DBG_LO)) b43dbg(dev->wl, "LO: Recalibrating current LO setting\n"); - cal = b43_calibrate_lo_setting(dev, &phy->bbatt, &phy->rfatt); + cal = b43_calibrate_lo_setting(dev, &gphy->bbatt, &gphy->rfatt); if (cal) { list_add(&cal->list, &lo->calib_list); b43_lo_write(dev, &cal->ctl); @@ -1013,7 +1023,7 @@ void b43_lo_g_maintanance_work(struct b43_wldev *dev) void b43_lo_g_cleanup(struct b43_wldev *dev) { - struct b43_txpower_lo_control *lo = dev->phy.lo_control; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; struct b43_lo_calib *cal, *tmp; if (!lo) @@ -1027,9 +1037,7 @@ void b43_lo_g_cleanup(struct b43_wldev *dev) /* LO Initialization */ void b43_lo_g_init(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - if (b43_has_hardware_pctl(phy)) { + if (b43_has_hardware_pctl(dev)) { lo_read_power_vector(dev); b43_gphy_dc_lt_init(dev, 1); } diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 1da321c..3b27e20 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -1,7 +1,9 @@ #ifndef B43_LO_H_ #define B43_LO_H_ -#include "phy.h" +/* G-PHY Local Oscillator */ + +#include "phy_g.h" struct b43_wldev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7205a93..af43f03 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -44,7 +44,8 @@ #include "b43.h" #include "main.h" #include "debugfs.h" -#include "phy.h" +#include "phy_common.h" +#include "phy_g.h" #include "nphy.h" #include "dma.h" #include "pio.h" @@ -1174,6 +1175,8 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) { /* Top half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; if (dev->noisecalc.calculation_running) return; dev->noisecalc.calculation_running = 1; @@ -1184,7 +1187,7 @@ static void b43_calculate_link_quality(struct b43_wldev *dev) static void handle_irq_noise(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *phy = dev->phy.g; u16 tmp; u8 noise[4]; u8 i, j; @@ -1192,6 +1195,9 @@ static void handle_irq_noise(struct b43_wldev *dev) /* Bottom half of Link Quality calculation. */ + if (dev->phy.type != B43_PHYTYPE_G) + return; + /* Possible race condition: It might be possible that the user * changed to a different channel in the meantime since we * started the calculation. We ignore that fact, since it's @@ -2688,9 +2694,7 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* This is the opposite of b43_chip_init() */ static void b43_chip_exit(struct b43_wldev *dev) { - b43_radio_turn_off(dev, 1); b43_gpio_cleanup(dev); - b43_lo_g_cleanup(dev); /* firmware is released later */ } @@ -2700,7 +2704,7 @@ static void b43_chip_exit(struct b43_wldev *dev) static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err, tmp; + int err; u32 value32, macctl; u16 value16; @@ -2725,19 +2729,19 @@ static int b43_chip_init(struct b43_wldev *dev) err = b43_upload_initvals(dev); if (err) goto err_gpio_clean; - b43_radio_turn_on(dev); b43_write16(dev, 0x03E6, 0x0000); err = b43_phy_init(dev); if (err) - goto err_radio_off; + goto err_gpio_clean; - /* Select initial Interference Mitigation. */ - tmp = phy->interfmode; - phy->interfmode = B43_INTERFMODE_NONE; - b43_radio_set_interference_mitigation(dev, tmp); + /* Disable Interference Mitigation. */ + if (phy->ops->interf_mitigation) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); - b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT); + /* Select the antennae */ + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, B43_ANTENNA_DEFAULT); b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT); if (phy->type == B43_PHYTYPE_B) { @@ -2790,8 +2794,6 @@ static int b43_chip_init(struct b43_wldev *dev) out: return err; -err_radio_off: - b43_radio_turn_off(dev, 1); err_gpio_clean: b43_gpio_cleanup(dev); return err; @@ -2799,25 +2801,10 @@ err_gpio_clean: static void b43_periodic_every60sec(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = dev->phy.ops; - if (phy->type != B43_PHYTYPE_G) - return; - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { - b43_mac_suspend(dev); - b43_calc_nrssi_slope(dev); - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { - u8 old_chan = phy->channel; - - /* VCO Calibration */ - if (old_chan >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - b43_radio_selectchannel(dev, old_chan, 0); - } - b43_mac_enable(dev); - } + if (ops->pwork_60sec) + ops->pwork_60sec(dev); } static void b43_periodic_every30sec(struct b43_wldev *dev) @@ -2845,32 +2832,10 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } } - if (phy->type == B43_PHYTYPE_G) { - //TODO: update_aci_moving_average - if (phy->aci_enable && phy->aci_wlan_automatic) { - b43_mac_suspend(dev); - if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) { - if (0 /*TODO: bunch of conditions */ ) { - b43_radio_set_interference_mitigation - (dev, B43_INTERFMODE_MANUALWLAN); - } - } else if (1 /*TODO*/) { - /* - if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) { - b43_radio_set_interference_mitigation(dev, - B43_INTERFMODE_NONE); - } - */ - } - b43_mac_enable(dev); - } else if (phy->interfmode == B43_INTERFMODE_NONWLAN && - phy->rev == 1) { - //TODO: implement rev1 workaround - } - } - b43_phy_xmitpower(dev); //FIXME: unless scanning? - b43_lo_g_maintanance_work(dev); - //TODO for APHY (temperature?) + if (phy->ops->pwork_15sec) + phy->ops->pwork_15sec(dev); + + phy->ops->xmitpower(dev); atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); wmb(); @@ -3401,7 +3366,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ if (conf->channel->hw_value != phy->channel) - b43_radio_selectchannel(dev, conf->channel->hw_value, 0); + b43_switch_channel(dev, conf->channel->hw_value); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -3419,7 +3384,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { phy->power_level = conf->power_level; - b43_phy_xmitpower(dev); + phy->ops->xmitpower(dev); } } @@ -3427,7 +3392,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); b43_mgmtframe_txantenna(dev, antenna); antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); - b43_set_rx_antenna(dev, antenna); + if (phy->ops->set_rx_antenna) + phy->ops->set_rx_antenna(dev, antenna); /* Update templates for AP/mesh mode. */ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) || @@ -3436,7 +3402,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) if (!!conf->radio_enabled != phy->radio_on) { if (conf->radio_enabled) { - b43_radio_turn_on(dev); + b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED); b43info(dev->wl, "Radio turned on by software\n"); if (!dev->radio_hw_enable) { b43info(dev->wl, "The hardware RF-kill button " @@ -3444,7 +3410,7 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) "Press the button to turn it on.\n"); } } else { - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); b43info(dev->wl, "Radio turned off by software\n"); } } @@ -3818,48 +3784,9 @@ static int b43_phy_versioning(struct b43_wldev *dev) static void setup_struct_phy_for_init(struct b43_wldev *dev, struct b43_phy *phy) { - struct b43_txpower_lo_control *lo; - int i; - - memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); - memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - - phy->aci_enable = 0; - phy->aci_wlan_automatic = 0; - phy->aci_hw_rssi = 0; - - phy->radio_off_context.valid = 0; - - lo = phy->lo_control; - if (lo) { - memset(lo, 0, sizeof(*(phy->lo_control))); - lo->tx_bias = 0xFF; - INIT_LIST_HEAD(&lo->calib_list); - } - phy->max_lb_gain = 0; - phy->trsw_rx_gain = 0; - phy->txpwr_offset = 0; - - /* NRSSI */ - phy->nrssislope = 0; - for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++) - phy->nrssi[i] = -1000; - for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++) - phy->nrssi_lt[i] = i; - - phy->lofcal = 0xFFFF; - phy->initval = 0xFFFF; - - phy->interfmode = B43_INTERFMODE_NONE; - phy->channel = 0xFF; - phy->hardware_power_control = !!modparam_hwpctl; - /* PHY TX errors counter. */ atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); - - /* OFDM-table address caching. */ - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; } static void setup_struct_wldev_for_init(struct b43_wldev *dev) @@ -3995,7 +3922,6 @@ static void b43_set_pretbtt(struct b43_wldev *dev) /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; u32 macctl; B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); @@ -4016,16 +3942,12 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) b43_dma_free(dev); b43_pio_free(dev); b43_chip_exit(dev); - b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - kfree(phy->lo_control); - phy->lo_control = NULL; if (dev->wl->current_beacon) { dev_kfree_skb_any(dev->wl->current_beacon); dev->wl->current_beacon = NULL; } + b43_phy_exit(dev); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); @@ -4052,29 +3974,24 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_wireless_core_reset(dev, tmp); } - if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) { - phy->lo_control = - kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL); - if (!phy->lo_control) { - err = -ENOMEM; - goto err_busdown; - } - } setup_struct_wldev_for_init(dev); - - err = b43_phy_init_tssi2dbm_table(dev); + err = b43_phy_operations_setup(dev); if (err) - goto err_kfree_lo_control; + goto err_busdown; /* Enable IRQ routing to this device. */ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev); b43_imcfglo_timeouts_workaround(dev); b43_bluetooth_coext_disable(dev); - b43_phy_early_init(dev); + if (phy->ops->prepare) { + err = phy->ops->prepare(dev); + if (err) + goto err_phy_exit; + } err = b43_chip_init(dev); if (err) - goto err_kfree_tssitbl; + goto err_phy_exit; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_WLCOREREV, dev->dev->id.revision); hf = b43_hf_read(dev); @@ -4140,15 +4057,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev) out: return err; - err_chip_exit: +err_chip_exit: b43_chip_exit(dev); - err_kfree_tssitbl: - if (phy->dyn_tssi_tbl) - kfree(phy->tssi2dbm); - err_kfree_lo_control: - kfree(phy->lo_control); - phy->lo_control = NULL; - err_busdown: +err_phy_exit: + b43_phy_exit(dev); +err_busdown: ssb_bus_may_powerdown(bus); B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT); return err; @@ -4511,7 +4424,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43_chip_reset); - b43_radio_turn_off(dev, 1); b43_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 644eed9..831986c 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -81,9 +81,8 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) //TODO } -/* Tune the hardware to a new channel. Don't call this directly. - * Use b43_radio_selectchannel() */ -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +/* Tune the hardware to a new channel. */ +static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel) { const struct b43_nphy_channeltab_entry *tabent; @@ -162,7 +161,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) msleep(1); b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); msleep(1); - b43_radio_selectchannel(dev, dev->phy.channel, 0); + nphy_channel_switch(dev, dev->phy.channel); b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); @@ -484,3 +483,139 @@ int b43_phy_initn(struct b43_wldev *dev) b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); return 0; } + +static int b43_nphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy; + + nphy = kzalloc(sizeof(*nphy), GFP_KERNEL); + if (!nphy) + return -ENOMEM; + dev->phy.n = nphy; + + //TODO init struct b43_phy_n + + return 0; +} + +static int b43_nphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + int err; + + err = b43_phy_initn(dev); + if (err) + return err; + nphy->initialised = 1; + + return 0; +} + +static void b43_nphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_n *nphy = dev->phy.n; + + if (nphy->initialised) { + //TODO + nphy->initialised = 0; + } + //TODO + kfree(nphy); + dev->phy.n = NULL; +} + +static inline void check_phyreg(struct b43_wldev *dev, u16 offset) +{ +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + /* OFDM registers are onnly available on A/G-PHYs */ + b43err(dev->wl, "Invalid OFDM PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on N-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ +} + +static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + check_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* N-PHY needs 0x100 for read access */ + reg |= 0x100; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static int b43_nphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + } else { + if (new_channel > 200) + return -EINVAL; + } + + return nphy_channel_switch(dev, new_channel); +} + +static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + +static void b43_nphy_op_xmitpower(struct b43_wldev *dev) +{//TODO +} + +const struct b43_phy_operations b43_phyops_n = { + .allocate = b43_nphy_op_allocate, + .init = b43_nphy_op_init, + .exit = b43_nphy_op_exit, + .phy_read = b43_nphy_op_read, + .phy_write = b43_nphy_op_write, + .radio_read = b43_nphy_op_radio_read, + .radio_write = b43_nphy_op_radio_write, + .software_rfkill = b43_nphy_op_software_rfkill, + .switch_channel = b43_nphy_op_switch_channel, + .get_default_chan = b43_nphy_op_get_default_chan, + .xmitpower = b43_nphy_op_xmitpower, +}; diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h index faf46b9..3d1f65e 100644 --- a/drivers/net/wireless/b43/nphy.h +++ b/drivers/net/wireless/b43/nphy.h @@ -1,7 +1,7 @@ #ifndef B43_NPHY_H_ #define B43_NPHY_H_ -#include "phy.h" +#include "phy_common.h" /* N-PHY registers. */ @@ -919,54 +919,14 @@ struct b43_wldev; +struct b43_phy_n { + bool initialised; -#ifdef CONFIG_B43_NPHY -/* N-PHY support enabled */ + //TODO lots of missing stuff +}; -int b43_phy_initn(struct b43_wldev *dev); -void b43_nphy_radio_turn_on(struct b43_wldev *dev); -void b43_nphy_radio_turn_off(struct b43_wldev *dev); +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_n; -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); - -void b43_nphy_xmitpower(struct b43_wldev *dev); -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); - - -#else /* CONFIG_B43_NPHY */ -/* N-PHY support disabled */ - - -static inline -int b43_phy_initn(struct b43_wldev *dev) -{ - return -EOPNOTSUPP; -} - -static inline -void b43_nphy_radio_turn_on(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_radio_turn_off(struct b43_wldev *dev) -{ -} - -static inline -int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) -{ - return -ENOSYS; -} - -static inline -void b43_nphy_xmitpower(struct b43_wldev *dev) -{ -} -static inline -void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) -{ -} - -#endif /* CONFIG_B43_NPHY */ #endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 305d4cd..02ae450 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -39,160 +39,6 @@ #include "wa.h" -static const s8 b43_tssi2dbm_b_table[] = { - 0x4D, 0x4C, 0x4B, 0x4A, - 0x4A, 0x49, 0x48, 0x47, - 0x47, 0x46, 0x45, 0x45, - 0x44, 0x43, 0x42, 0x42, - 0x41, 0x40, 0x3F, 0x3E, - 0x3D, 0x3C, 0x3B, 0x3A, - 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x32, 0x31, - 0x30, 0x2F, 0x2D, 0x2C, - 0x2B, 0x29, 0x28, 0x26, - 0x25, 0x23, 0x21, 0x1F, - 0x1D, 0x1A, 0x17, 0x14, - 0x10, 0x0C, 0x06, 0x00, - -7, -7, -7, -7, - -7, -7, -7, -7, - -7, -7, -7, -7, -}; - -static const s8 b43_tssi2dbm_g_table[] = { - 77, 77, 77, 76, - 76, 76, 75, 75, - 74, 74, 73, 73, - 73, 72, 72, 71, - 71, 70, 70, 69, - 68, 68, 67, 67, - 66, 65, 65, 64, - 63, 63, 62, 61, - 60, 59, 58, 57, - 56, 55, 54, 53, - 52, 50, 49, 47, - 45, 43, 40, 37, - 33, 28, 22, 14, - 5, -7, -20, -20, - -20, -20, -20, -20, - -20, -20, -20, -20, -}; - -const u8 b43_radio_channel_codes_bg[] = { - 12, 17, 22, 27, - 32, 37, 42, 47, - 52, 57, 62, 67, - 72, 84, -}; - -#define bitrev4(tmp) (bitrev8(tmp) >> 4) -static void b43_phy_initg(struct b43_wldev *dev); - -static void generate_rfatt_list(struct b43_wldev *dev, - struct b43_rfatt_list *list) -{ - struct b43_phy *phy = &dev->phy; - - /* APHY.rev < 5 || GPHY.rev < 6 */ - static const struct b43_rfatt rfatt_0[] = { - {.att = 3,.with_padmix = 0,}, - {.att = 1,.with_padmix = 0,}, - {.att = 5,.with_padmix = 0,}, - {.att = 7,.with_padmix = 0,}, - {.att = 9,.with_padmix = 0,}, - {.att = 2,.with_padmix = 0,}, - {.att = 0,.with_padmix = 0,}, - {.att = 4,.with_padmix = 0,}, - {.att = 6,.with_padmix = 0,}, - {.att = 8,.with_padmix = 0,}, - {.att = 1,.with_padmix = 1,}, - {.att = 2,.with_padmix = 1,}, - {.att = 3,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - }; - /* Radio.rev == 8 && Radio.version == 0x2050 */ - static const struct b43_rfatt rfatt_1[] = { - {.att = 2,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - {.att = 6,.with_padmix = 1,}, - {.att = 8,.with_padmix = 1,}, - {.att = 10,.with_padmix = 1,}, - {.att = 12,.with_padmix = 1,}, - {.att = 14,.with_padmix = 1,}, - }; - /* Otherwise */ - static const struct b43_rfatt rfatt_2[] = { - {.att = 0,.with_padmix = 1,}, - {.att = 2,.with_padmix = 1,}, - {.att = 4,.with_padmix = 1,}, - {.att = 6,.with_padmix = 1,}, - {.att = 8,.with_padmix = 1,}, - {.att = 9,.with_padmix = 1,}, - {.att = 9,.with_padmix = 1,}, - }; - - if (!b43_has_hardware_pctl(phy)) { - /* Software pctl */ - list->list = rfatt_0; - list->len = ARRAY_SIZE(rfatt_0); - list->min_val = 0; - list->max_val = 9; - return; - } - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - /* Hardware pctl */ - list->list = rfatt_1; - list->len = ARRAY_SIZE(rfatt_1); - list->min_val = 0; - list->max_val = 14; - return; - } - /* Hardware pctl */ - list->list = rfatt_2; - list->len = ARRAY_SIZE(rfatt_2); - list->min_val = 0; - list->max_val = 9; -} - -static void generate_bbatt_list(struct b43_wldev *dev, - struct b43_bbatt_list *list) -{ - static const struct b43_bbatt bbatt_0[] = { - {.att = 0,}, - {.att = 1,}, - {.att = 2,}, - {.att = 3,}, - {.att = 4,}, - {.att = 5,}, - {.att = 6,}, - {.att = 7,}, - {.att = 8,}, - }; - - list->list = bbatt_0; - list->len = ARRAY_SIZE(bbatt_0); - list->min_val = 0; - list->max_val = 8; -} - -bool b43_has_hardware_pctl(struct b43_phy *phy) -{ - if (!phy->hardware_power_control) - return 0; - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev >= 5) - return 1; - break; - case B43_PHYTYPE_G: - if (phy->rev >= 6) - return 1; - break; - default: - B43_WARN_ON(1); - } - return 0; -} - static void b43_shm_clear_tssi(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -212,1345 +58,109 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev) } } -/* Lock the PHY registers against concurrent access from the microcode. - * This lock is nonrecursive. */ -void b43_phy_lock(struct b43_wldev *dev) -{ -#if B43_DEBUG - B43_WARN_ON(dev->phy.phy_locked); - dev->phy.phy_locked = 1; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); - - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); -} - -void b43_phy_unlock(struct b43_wldev *dev) -{ -#if B43_DEBUG - B43_WARN_ON(!dev->phy.phy_locked); - dev->phy.phy_locked = 0; -#endif - B43_WARN_ON(dev->dev->id.revision < 3); - - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, 0); -} - -/* Different PHYs require different register routing flags. - * This adjusts (and does sanity checks on) the routing flags. +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 */ -static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, - u16 offset, struct b43_wldev *dev) -{ - if (phy->type == B43_PHYTYPE_A) { - /* OFDM registers are base-registers for the A-PHY. */ - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { - offset &= ~B43_PHYROUTE; - offset |= B43_PHYROUTE_BASE; - } - } - -#if B43_DEBUG - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { - /* Ext-G registers are only available on G-PHYs */ - if (phy->type != B43_PHYTYPE_G) { - b43err(dev->wl, "Invalid EXT-G PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } - } - if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { - /* N-BMODE registers are only available on N-PHYs */ - if (phy->type != B43_PHYTYPE_N) { - b43err(dev->wl, "Invalid N-BMODE PHY access at " - "0x%04X on PHY type %u\n", offset, phy->type); - dump_stack(); - } - } -#endif /* B43_DEBUG */ - - return offset; -} - -u16 b43_phy_read(struct b43_wldev * dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - return b43_read16(dev, B43_MMIO_PHY_DATA); -} - -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) -{ - struct b43_phy *phy = &dev->phy; - - offset = adjust_phyreg_for_phytype(phy, offset, dev); - b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - b43_write16(dev, B43_MMIO_PHY_DATA, val); -} - -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) & mask); -} - -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_phy_write(dev, offset, - b43_phy_read(dev, offset) | set); -} - -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_phy_write(dev, offset, - (b43_phy_read(dev, offset) & mask) | set); -} - -/* Adjust the transmission power output (G-PHY) */ -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control) +static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) { struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - u16 bb, rf; - u16 tx_bias, tx_magn; - - bb = bbatt->att; - rf = rfatt->att; - tx_bias = lo->tx_bias; - tx_magn = lo->tx_magn; - if (unlikely(tx_bias == 0xFF)) - tx_bias = 0; + s8 dbm = 0; + s32 tmp; - /* Save the values for later */ - phy->tx_control = tx_control; - memcpy(&phy->rfatt, rfatt, sizeof(*rfatt)); - phy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); - memcpy(&phy->bbatt, bbatt, sizeof(*bbatt)); + tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " - "rfatt(%u), tx_control(0x%02X), " - "tx_bias(0x%02X), tx_magn(0x%02X)\n", - bb, rf, tx_control, tx_bias, tx_magn); + switch (phy->type) { + case B43_PHYTYPE_A: + tmp += 0x80; + tmp = clamp_val(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + //TODO: There's a FIXME on the specs + break; + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + tmp = clamp_val(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + B43_WARN_ON(1); } - b43_phy_set_baseband_attenuation(dev, bb); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, - (rf & 0x000F) | (tx_control & 0x0070)); - } else { - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | (rf & 0x000F)); - b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) - & ~0x0070) | (tx_control & - 0x0070)); - } - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, tx_magn | tx_bias); - } else { - b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) - & 0xFFF0) | (tx_bias & 0x000F)); - } - if (phy->type == B43_PHYTYPE_G) - b43_lo_g_adjust(dev); + return dbm; } -static void default_baseband_attenuation(struct b43_wldev *dev, - struct b43_bbatt *bb) +void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) { - struct b43_phy *phy = &dev->phy; + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.lo_control; - if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) - bb->att = 0; - else - bb->att = 2; -} + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ -static void default_radio_attenuation(struct b43_wldev *dev, - struct b43_rfatt *rf) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; - rf->with_padmix = 0; + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && - bus->boardinfo.type == SSB_BOARD_BCM4309G) { - if (bus->boardinfo.rev < 0x43) { - rf->att = 2; - return; - } else if (bus->boardinfo.rev < 0x51) { - rf->att = 3; - return; + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; } - } - - if (phy->type == B43_PHYTYPE_A) { - rf->att = 0x60; - return; - } - - switch (phy->radio_ver) { - case 0x2053: - switch (phy->radio_rev) { - case 1: - rf->att = 6; - return; + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; } - break; - case 0x2050: - switch (phy->radio_rev) { - case 0: - rf->att = 5; - return; - case 1: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 3; - else - rf->att = 1; - } else { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 7; - else - rf->att = 6; - } - return; - case 2: - if (phy->type == B43_PHYTYPE_G) { - if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == SSB_BOARD_BCM4309G - && bus->boardinfo.rev >= 30) - rf->att = 3; - else if (bus->boardinfo.vendor == - SSB_BOARDVENDOR_BCM - && bus->boardinfo.type == - SSB_BOARD_BU4306) - rf->att = 5; - else if (bus->chip_id == 0x4320) - rf->att = 4; - else - rf->att = 3; - } else - rf->att = 6; - return; - case 3: - rf->att = 5; - return; - case 4: - case 5: - rf->att = 1; - return; - case 6: - case 7: - rf->att = 5; - return; - case 8: - rf->att = 0xA; - rf->with_padmix = 1; - return; - case 9: - default: - rf->att = 5; - return; + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; } - } - rf->att = 5; -} - -static u16 default_tx_control(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->radio_ver != 0x2050) - return 0; - if (phy->radio_rev == 1) - return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; - if (phy->radio_rev < 6) - return B43_TXCTL_PA2DB; - if (phy->radio_rev == 8) - return B43_TXCTL_TXMIX; - return 0; -} - -/* This func is called "PHY calibrate" in the specs... */ -void b43_phy_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - - default_baseband_attenuation(dev, &phy->bbatt); - default_radio_attenuation(dev, &phy->rfatt); - phy->tx_control = (default_tx_control(dev) << 4); - - /* Commit previous writes */ - b43_read32(dev, B43_MMIO_MACCTL); - - if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) { - generate_rfatt_list(dev, &lo->rfatt_list); - generate_bbatt_list(dev, &lo->bbatt_list); - } - if (phy->type == B43_PHYTYPE_G && phy->rev == 1) { - /* Workaround: Temporarly disable gmode through the early init - * phase, as the gmode stuff is not needed for phy rev 1 */ - phy->gmode = 0; - b43_wireless_core_reset(dev, 0); - b43_phy_initg(dev); - phy->gmode = 1; - b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); - } -} - -/* GPHY_TSSI_Power_Lookup_Table_Init */ -static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - int i; - u16 value; - - for (i = 0; i < 32; i++) - b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]); - for (i = 32; i < 64; i++) - b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]); - for (i = 0; i < 64; i += 2) { - value = (u16) phy->tssi2dbm[i]; - value |= ((u16) phy->tssi2dbm[i + 1]) << 8; - b43_phy_write(dev, 0x380 + (i / 2), value); - } -} - -/* GPHY_Gain_Lookup_Table_Init */ -static void b43_gphy_gain_lt_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct b43_txpower_lo_control *lo = phy->lo_control; - u16 nr_written = 0; - u16 tmp; - u8 rf, bb; - - for (rf = 0; rf < lo->rfatt_list.len; rf++) { - for (bb = 0; bb < lo->bbatt_list.len; bb++) { - if (nr_written >= 0x40) - return; - tmp = lo->bbatt_list.list[bb].att; - tmp <<= 8; - if (phy->radio_rev == 8) - tmp |= 0x50; - else - tmp |= 0x40; - tmp |= lo->rfatt_list.list[rf].att; - b43_phy_write(dev, 0x3C0 + nr_written, tmp); - nr_written++; + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; } - } -} - -static void hardware_pctl_init_aphy(struct b43_wldev *dev) -{ - //TODO -} - -static void hardware_pctl_init_gphy(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) - | (phy->tgt_idle_tssi - phy->cur_idle_tssi)); - b43_gphy_tssi_power_lt_init(dev); - b43_gphy_gain_lt_init(dev); - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); - b43_phy_write(dev, 0x0014, 0x0000); - - B43_WARN_ON(phy->rev < 6); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - | 0x0800); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) - & 0xFEFF); - b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) - & 0xFFBF); - - b43_gphy_dc_lt_init(dev, 1); -} - -/* HardwarePowerControl init for A and G PHY */ -static void b43_hardware_pctl_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - /* No hardware power control */ - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); - return; - } - /* Init the hwpctl related hardware */ - switch (phy->type) { - case B43_PHYTYPE_A: - hardware_pctl_init_aphy(dev); - break; - case B43_PHYTYPE_G: - hardware_pctl_init_gphy(dev); break; - default: - B43_WARN_ON(1); - } - /* Enable hardware pctl in firmware. */ - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); -} - -static void b43_hardware_pctl_early_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - - if (!b43_has_hardware_pctl(phy)) { - b43_phy_write(dev, 0x047A, 0xC111); - return; } - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); - b43_phy_write(dev, 0x002F, 0x0202); - b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); - b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); - if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - | 0x8000); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - } else { - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0200); - b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) - | 0x0400); - b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) - & 0x7FFF); - b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) - & 0xFFFE); - b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) - & 0xFFC0) | 0x0010); - b43_phy_write(dev, 0x002E, 0xC07F); - b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) - & 0xFF0F) | 0x0010); - } + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); } -/* Intialize B/G PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl - */ -static void b43_phy_init_pctl(struct b43_wldev *dev) +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void b43_phy_xmitpower(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; - struct b43_rfatt old_rfatt; - struct b43_bbatt old_bbatt; - u8 old_tx_control = 0; + if (phy->cur_idle_tssi == 0) + return; if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && (bus->boardinfo.type == SSB_BOARD_BU4306)) return; - - b43_phy_write(dev, 0x0028, 0x8018); - - /* This does something with the Analog... */ - b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) - & 0xFFDF); - - if (phy->type == B43_PHYTYPE_G && !phy->gmode) +#ifdef CONFIG_B43_DEBUG + if (phy->manual_txpower_control) return; - b43_hardware_pctl_early_init(dev); - if (phy->cur_idle_tssi == 0) { - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - (b43_radio_read16(dev, 0x0076) - & 0x00F7) | 0x0084); - } else { - struct b43_rfatt rfatt; - struct b43_bbatt bbatt; - - memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt)); - memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt)); - old_tx_control = phy->tx_control; - - bbatt.att = 11; - if (phy->radio_rev == 8) { - rfatt.att = 15; - rfatt.with_padmix = 1; - } else { - rfatt.att = 9; - rfatt.with_padmix = 0; - } - b43_set_txpower_g(dev, &bbatt, &rfatt, 0); - } - b43_dummy_transmission(dev); - phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); - if (B43_DEBUG) { - /* Current-Idle-TSSI sanity check. */ - if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) { - b43dbg(dev->wl, - "!WARNING! Idle-TSSI phy->cur_idle_tssi " - "measuring failed. (cur=%d, tgt=%d). Disabling TX power " - "adjustment.\n", phy->cur_idle_tssi, - phy->tgt_idle_tssi); - phy->cur_idle_tssi = 0; - } - } - if (phy->radio_ver == 0x2050 && phy->analog == 0) { - b43_radio_write16(dev, 0x0076, - b43_radio_read16(dev, 0x0076) - & 0xFF7B); - } else { - b43_set_txpower_g(dev, &old_bbatt, - &old_rfatt, old_tx_control); - } - } - b43_hardware_pctl_init(dev); - b43_shm_clear_tssi(dev); -} - -static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) -{ - int i; +#endif - if (dev->phy.rev < 3) { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0xFFF8); - } - else - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { - b43_ofdmtab_write16(dev, - B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); - } - } else { - if (enable) - for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, 0x0820); - else - for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) - b43_ofdmtab_write16(dev, - B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); - } -} + switch (phy->type) { + case B43_PHYTYPE_A:{ -static void b43_phy_ww(struct b43_wldev *dev) -{ - u16 b, curr_s, best_s = 0xFFFF; - int i; - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); - b43_phy_write(dev, B43_PHY_OFDM(0x82), - (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); - b43_radio_write16(dev, 0x0009, - b43_radio_read16(dev, 0x0009) | 0x0080); - b43_radio_write16(dev, 0x0012, - (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); - b43_wa_initgains(dev); - b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); - b = b43_phy_read(dev, B43_PHY_PWRDOWN); - b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) | 0x0004); - for (i = 0x10; i <= 0x20; i++) { - b43_radio_write16(dev, 0x0013, i); - curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; - if (!curr_s) { - best_s = 0x0000; - break; - } else if (curr_s >= 0x0080) - curr_s = 0x0100 - curr_s; - if (curr_s < best_s) - best_s = curr_s; - } - b43_phy_write(dev, B43_PHY_PWRDOWN, b); - b43_radio_write16(dev, 0x0004, - b43_radio_read16(dev, 0x0004) & 0xFFFB); - b43_radio_write16(dev, 0x0013, best_s); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); - b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); - b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); - b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); - b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); - b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); - b43_phy_write(dev, B43_PHY_OFDM(0xBB), - (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); - b43_phy_write(dev, B43_PHY_OFDM61, - (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); - b43_phy_write(dev, B43_PHY_OFDM(0x13), - (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); - b43_phy_write(dev, B43_PHY_OFDM(0x14), - (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); - for (i = 0; i < 6; i++) - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); - b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); - b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); -} - -/* Initialize APHY. This is also called for the GPHY in some cases. */ -static void b43_phy_inita(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->rev >= 6) { - if (phy->type == B43_PHYTYPE_A) - b43_phy_write(dev, B43_PHY_OFDM(0x1B), - b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); - if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); - else - b43_phy_write(dev, B43_PHY_ENCORE, - b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); - } - - b43_wa_all(dev); - - if (phy->type == B43_PHYTYPE_A) { - if (phy->gmode && (phy->rev < 3)) - b43_phy_write(dev, 0x0034, - b43_phy_read(dev, 0x0034) | 0x0001); - b43_phy_rssiagc(dev, 0); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); - - b43_radio_init2060(dev); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { - ; //TODO: A PHY LO - } - - if (phy->rev >= 3) - b43_phy_ww(dev); - - hardware_pctl_init_aphy(dev); - - //TODO: radar detection - } - - if ((phy->type == B43_PHYTYPE_G) && - (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { - b43_phy_write(dev, B43_PHY_OFDM(0x6E), - (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) - & 0xE000) | 0x3CF); - } -} - -static void b43_phy_initb5(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - u16 offset, value; - u8 old_channel; - - if (phy->analog == 1) { - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) - | 0x0050); - } - if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type != SSB_BOARD_BU4306)) { - value = 0x2120; - for (offset = 0x00A8; offset < 0x00C7; offset++) { - b43_phy_write(dev, offset, value); - value += 0x202; - } - } - b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) - | 0x0700); - if (phy->radio_ver == 0x2050) - b43_phy_write(dev, 0x0038, 0x0667); - - if (phy->gmode || phy->rev >= 2) { - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) - | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) - | 0x0004); - } - b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); - - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - - b43_phy_write(dev, 0x001C, 0x186A); - - b43_phy_write(dev, 0x0013, - (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); - b43_phy_write(dev, 0x0035, - (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); - b43_phy_write(dev, 0x005D, - (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); - } - - if (dev->bad_frames_preempt) { - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, - B43_PHY_RADIO_BITFIELD) | (1 << 11)); - } - - if (phy->analog == 1) { - b43_phy_write(dev, 0x0026, 0xCE00); - b43_phy_write(dev, 0x0021, 0x3763); - b43_phy_write(dev, 0x0022, 0x1BC3); - b43_phy_write(dev, 0x0023, 0x06F9); - b43_phy_write(dev, 0x0024, 0x037E); - } else - b43_phy_write(dev, 0x0026, 0xCC00); - b43_phy_write(dev, 0x0030, 0x00C6); - b43_write16(dev, 0x03EC, 0x3F22); - - if (phy->analog == 1) - b43_phy_write(dev, 0x0020, 0x3E1C); - else - b43_phy_write(dev, 0x0020, 0x301C); - - if (phy->analog == 0) - b43_write16(dev, 0x03E4, 0x3000); - - old_channel = phy->channel; - /* Force to channel 7, even if not supported. */ - b43_radio_selectchannel(dev, 7, 0); - - if (phy->radio_ver != 0x2050) { - b43_radio_write16(dev, 0x0075, 0x0080); - b43_radio_write16(dev, 0x0079, 0x0081); - } - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - - if (phy->radio_ver == 0x2050) { - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x005A, 0x0070); - } - - b43_radio_write16(dev, 0x005B, 0x007B); - b43_radio_write16(dev, 0x005C, 0x00B0); - - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0080); - b43_phy_write(dev, 0x0032, 0x00CA); - b43_phy_write(dev, 0x002A, 0x88A3); - - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - - if (phy->radio_ver == 0x2050) - b43_radio_write16(dev, 0x005D, 0x000D); - - b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); -} - -static void b43_phy_initb6(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset, val; - u8 old_channel; - - b43_phy_write(dev, 0x003E, 0x817A); - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) | 0x0058)); - if (phy->radio_rev == 4 || phy->radio_rev == 5) { - b43_radio_write16(dev, 0x51, 0x37); - b43_radio_write16(dev, 0x52, 0x70); - b43_radio_write16(dev, 0x53, 0xB3); - b43_radio_write16(dev, 0x54, 0x9B); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x88); - b43_radio_write16(dev, 0x5D, 0x88); - b43_radio_write16(dev, 0x5E, 0x88); - b43_radio_write16(dev, 0x7D, 0x88); - b43_hf_write(dev, b43_hf_read(dev) - | B43_HF_TSSIRPSMW); - } - B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x51, 0); - b43_radio_write16(dev, 0x52, 0x40); - b43_radio_write16(dev, 0x53, 0xB7); - b43_radio_write16(dev, 0x54, 0x98); - b43_radio_write16(dev, 0x5A, 0x88); - b43_radio_write16(dev, 0x5B, 0x6B); - b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { - b43_radio_write16(dev, 0x5D, 0xFA); - b43_radio_write16(dev, 0x5E, 0xD8); - } else { - b43_radio_write16(dev, 0x5D, 0xF5); - b43_radio_write16(dev, 0x5E, 0xB8); - } - b43_radio_write16(dev, 0x0073, 0x0003); - b43_radio_write16(dev, 0x007D, 0x00A8); - b43_radio_write16(dev, 0x007C, 0x0001); - b43_radio_write16(dev, 0x007E, 0x0008); - } - val = 0x1E1F; - for (offset = 0x0088; offset < 0x0098; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x3E3F; - for (offset = 0x0098; offset < 0x00A8; offset++) { - b43_phy_write(dev, offset, val); - val -= 0x0202; - } - val = 0x2120; - for (offset = 0x00A8; offset < 0x00C8; offset++) { - b43_phy_write(dev, offset, (val & 0x3F3F)); - val += 0x0202; - } - if (phy->type == B43_PHYTYPE_G) { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0020); - b43_radio_write16(dev, 0x0051, - b43_radio_read16(dev, 0x0051) | 0x0004); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); - b43_phy_write(dev, 0x5B, 0); - b43_phy_write(dev, 0x5C, 0); - } - - old_channel = phy->channel; - if (old_channel >= 8) - b43_radio_selectchannel(dev, 1, 0); - else - b43_radio_selectchannel(dev, 13, 0); - - b43_radio_write16(dev, 0x0050, 0x0020); - b43_radio_write16(dev, 0x0050, 0x0023); - udelay(40); - if (phy->radio_rev < 6 || phy->radio_rev == 8) { - b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) - | 0x0002)); - b43_radio_write16(dev, 0x50, 0x20); - } - if (phy->radio_rev <= 2) { - b43_radio_write16(dev, 0x7C, 0x20); - b43_radio_write16(dev, 0x5A, 0x70); - b43_radio_write16(dev, 0x5B, 0x7B); - b43_radio_write16(dev, 0x5C, 0xB0); - } - b43_radio_write16(dev, 0x007A, - (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); - - b43_radio_selectchannel(dev, old_channel, 0); - - b43_phy_write(dev, 0x0014, 0x0200); - if (phy->radio_rev >= 6) - b43_phy_write(dev, 0x2A, 0x88C2); - else - b43_phy_write(dev, 0x2A, 0x8AC0); - b43_phy_write(dev, 0x0038, 0x0668); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (phy->radio_rev <= 5) { - b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) - & 0xFF80) | 0x0003); - } - if (phy->radio_rev <= 2) - b43_radio_write16(dev, 0x005D, 0x000D); - - if (phy->analog == 4) { - b43_write16(dev, 0x3E4, 9); - b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) - & 0x0FFF); - } else { - b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) - | 0x0004); - } - if (phy->type == B43_PHYTYPE_B) - B43_WARN_ON(1); - else if (phy->type == B43_PHYTYPE_G) - b43_write16(dev, 0x03E6, 0x0); -} - -static void b43_calc_loopback_gain(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup_phy[16] = { 0 }; - u16 backup_radio[3]; - u16 backup_bband; - u16 i, j, loop_i_max; - u16 trsw_rx; - u16 loop1_outer_done, loop1_inner_done; - - backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); - backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); - backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); - backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); - } - backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); - backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); - backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); - backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); - backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); - backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); - backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); - backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); - backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); - backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - backup_bband = phy->bbatt.att; - backup_radio[0] = b43_radio_read16(dev, 0x52); - backup_radio[1] = b43_radio_read16(dev, 0x43); - backup_radio[2] = b43_radio_read16(dev, 0x7A); - - b43_phy_write(dev, B43_PHY_CRS0, - b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, - b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFE); - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFD); - } - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xFFCF) | 0x10); - - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - - b43_phy_write(dev, B43_PHY_CCK(0x0A), - b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, - B43_PHY_ANALOGOVERVAL) & 0xFFFB); - } - b43_phy_write(dev, B43_PHY_CCK(0x03), - (b43_phy_read(dev, B43_PHY_CCK(0x03)) - & 0xFF9F) | 0x40); - - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, 0x000F); - } else { - b43_radio_write16(dev, 0x52, 0); - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | 0x9); - } - b43_phy_set_baseband_attenuation(dev, 11); - - if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); - else - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); - b43_phy_write(dev, B43_PHY_LO_CTL, 0); - - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xFFC0) | 0x01); - b43_phy_write(dev, B43_PHY_CCK(0x2B), - (b43_phy_read(dev, B43_PHY_CCK(0x2B)) - & 0xC0FF) | 0x800); - - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); - - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { - if (phy->rev >= 7) { - b43_phy_write(dev, B43_PHY_RFOVER, - b43_phy_read(dev, B43_PHY_RFOVER) - | 0x0800); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x8000); - } - } - b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) - & 0x00F7); - - j = 0; - loop_i_max = (phy->radio_rev == 8) ? 15 : 9; - for (i = 0; i < loop_i_max; i++) { - for (j = 0; j < 16; j++) { - b43_radio_write16(dev, 0x43, i); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop1; - } - } - exit_loop1: - loop1_outer_done = i; - loop1_inner_done = j; - if (j >= 8) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - b43_phy_read(dev, B43_PHY_RFOVERVAL) - | 0x30); - trsw_rx = 0x1B; - for (j = j - 8; j < 16; j++) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - (b43_phy_read(dev, B43_PHY_RFOVERVAL) - & 0xF0FF) | (j << 8)); - b43_phy_write(dev, B43_PHY_PGACTL, - (b43_phy_read(dev, B43_PHY_PGACTL) - & 0x0FFF) | 0xA000); - b43_phy_write(dev, B43_PHY_PGACTL, - b43_phy_read(dev, B43_PHY_PGACTL) - | 0xF000); - udelay(20); - trsw_rx -= 3; - if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) - goto exit_loop2; - } - } else - trsw_rx = 0x18; - exit_loop2: - - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); - } - b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); - b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); - b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); - b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); - b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); - b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); - b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); - b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); - b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); - - b43_phy_set_baseband_attenuation(dev, backup_bband); - - b43_radio_write16(dev, 0x52, backup_radio[0]); - b43_radio_write16(dev, 0x43, backup_radio[1]); - b43_radio_write16(dev, 0x7A, backup_radio[2]); - - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); - udelay(10); - b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); - b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); - b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); - - phy->max_lb_gain = - ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; - phy->trsw_rx_gain = trsw_rx * 2; -} - -static void b43_phy_initg(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp; - - if (phy->rev == 1) - b43_phy_initb5(dev); - else - b43_phy_initb6(dev); - - if (phy->rev >= 2 || phy->gmode) - b43_phy_inita(dev); - - if (phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); - } - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_RFOVER, 0); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->rev > 5) { - b43_phy_write(dev, B43_PHY_RFOVER, 0x400); - b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); - } - if (phy->gmode || phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); - tmp &= B43_PHYVER_VERSION; - if (tmp == 3 || tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); - } - if (tmp == 5) { - b43_phy_write(dev, B43_PHY_OFDM(0xCC), - (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) - & 0x00FF) | 0x1F00); - } - } - if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) - b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); - if (phy->radio_rev == 8) { - b43_phy_write(dev, B43_PHY_EXTG(0x01), - b43_phy_read(dev, B43_PHY_EXTG(0x01)) - | 0x80); - b43_phy_write(dev, B43_PHY_OFDM(0x3E), - b43_phy_read(dev, B43_PHY_OFDM(0x3E)) - | 0x4); - } - if (has_loopback_gain(phy)) - b43_calc_loopback_gain(dev); - - if (phy->radio_rev != 8) { - if (phy->initval == 0xFFFF) - phy->initval = b43_radio_init2050(dev); - else - b43_radio_write16(dev, 0x0078, phy->initval); - } - b43_lo_g_init(dev); - if (has_tx_magnification(phy)) { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFF00) - | phy->lo_control->tx_bias | phy-> - lo_control->tx_magn); - } else { - b43_radio_write16(dev, 0x52, - (b43_radio_read16(dev, 0x52) & 0xFFF0) - | phy->lo_control->tx_bias); - } - if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_CCK(0x36), - (b43_phy_read(dev, B43_PHY_CCK(0x36)) - & 0x0FFF) | (phy->lo_control-> - tx_bias << 12)); - } - if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); - else - b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); - if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); - else - b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); - if (phy->gmode || phy->rev >= 2) { - b43_lo_g_adjust(dev); - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); - } - - if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - /* The specs state to update the NRSSI LT with - * the value 0x7FFFFFFF here. I think that is some weird - * compiler optimization in the original driver. - * Essentially, what we do here is resetting all NRSSI LT - * entries to -32 (see the clamp_val() in nrssi_hw_update()) - */ - b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? - b43_calc_nrssi_threshold(dev); - } else if (phy->gmode || phy->rev >= 2) { - if (phy->nrssi[0] == -1000) { - B43_WARN_ON(phy->nrssi[1] != -1000); - b43_calc_nrssi_slope(dev); - } else - b43_calc_nrssi_threshold(dev); - } - if (phy->radio_rev == 8) - b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); - b43_phy_init_pctl(dev); - /* FIXME: The spec says in the following if, the 0 should be replaced - 'if OFDM may not be used in the current locale' - but OFDM is legal everywhere */ - if ((dev->dev->bus->chip_id == 0x4306 - && dev->dev->bus->chip_package == 2) || 0) { - b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) - & 0xBFFF); - b43_phy_write(dev, B43_PHY_OFDM(0xC3), - b43_phy_read(dev, B43_PHY_OFDM(0xC3)) - & 0x7FFF); - } -} - -/* Set the baseband attenuation value on chip. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation) -{ - struct b43_phy *phy = &dev->phy; - - if (phy->analog == 0) { - b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) - & 0xFFF0) | - baseband_attenuation); - } else if (phy->analog > 1) { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFFC3) | (baseband_attenuation << 2)); - } else { - b43_phy_write(dev, B43_PHY_DACCTL, - (b43_phy_read(dev, B43_PHY_DACCTL) - & 0xFF87) | (baseband_attenuation << 3)); - } -} - -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut - * This function converts a TSSI value to dBm in Q5.2 - */ -static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi) -{ - struct b43_phy *phy = &dev->phy; - s8 dbm = 0; - s32 tmp; - - tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi); - - switch (phy->type) { - case B43_PHYTYPE_A: - tmp += 0x80; - tmp = clamp_val(tmp, 0x00, 0xFF); - dbm = phy->tssi2dbm[tmp]; - //TODO: There's a FIXME on the specs - break; - case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - tmp = clamp_val(tmp, 0x00, 0x3F); - dbm = phy->tssi2dbm[tmp]; - break; - default: - B43_WARN_ON(1); - } - - return dbm; -} - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt) -{ - int rfatt = *_rfatt; - int bbatt = *_bbatt; - struct b43_txpower_lo_control *lo = dev->phy.lo_control; - - /* Get baseband and radio attenuation values into their permitted ranges. - * Radio attenuation affects power level 4 times as much as baseband. */ - - /* Range constants */ - const int rf_min = lo->rfatt_list.min_val; - const int rf_max = lo->rfatt_list.max_val; - const int bb_min = lo->bbatt_list.min_val; - const int bb_max = lo->bbatt_list.max_val; - - while (1) { - if (rfatt > rf_max && bbatt > bb_max - 4) - break; /* Can not get it into ranges */ - if (rfatt < rf_min && bbatt < bb_min + 4) - break; /* Can not get it into ranges */ - if (bbatt > bb_max && rfatt > rf_max - 1) - break; /* Can not get it into ranges */ - if (bbatt < bb_min && rfatt < rf_min + 1) - break; /* Can not get it into ranges */ - - if (bbatt > bb_max) { - bbatt -= 4; - rfatt += 1; - continue; - } - if (bbatt < bb_min) { - bbatt += 4; - rfatt -= 1; - continue; - } - if (rfatt > rf_max) { - rfatt -= 1; - bbatt += 4; - continue; - } - if (rfatt < rf_min) { - rfatt += 1; - bbatt -= 4; - continue; - } - break; - } - - *_rfatt = clamp_val(rfatt, rf_min, rf_max); - *_bbatt = clamp_val(bbatt, bb_min, bb_max); -} - -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ -void b43_phy_xmitpower(struct b43_wldev *dev) -{ - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - - if (phy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; -#ifdef CONFIG_B43_DEBUG - if (phy->manual_txpower_control) - return; -#endif - - switch (phy->type) { - case B43_PHYTYPE_A:{ - - //TODO: Nothing for A PHYs yet :-/ + //TODO: Nothing for A PHYs yet :-/ break; } @@ -1591,2235 +201,232 @@ void b43_phy_xmitpower(struct b43_wldev *dev) v2 = (v2 + 0x20) & 0x3F; v3 = (v3 + 0x20) & 0x3F; tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp - && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & - 0x8)) - average -= 13; - - estimated_pwr = - b43_phy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; - - /* Calculate the new attenuation values. */ - bbatt = phy->bbatt.att; - bbatt += bbatt_delta; - rfatt = phy->rfatt.att; - rfatt += rfatt_delta; - - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - tx_control = phy->tx_control; - if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { - if (rfatt <= 1) { - if (tx_control == 0) { - tx_control = - B43_TXCTL_PA2DB | - B43_TXCTL_TXMIX; - rfatt += 2; - bbatt += 2; - } else if (dev->dev->bus->sprom. - boardflags_lo & - B43_BFL_PACTRL) { - bbatt += 4 * (rfatt - 2); - rfatt = 2; - } - } else if (rfatt > 4 && tx_control) { - tx_control = 0; - if (bbatt < 3) { - rfatt -= 3; - bbatt += 2; - } else { - rfatt -= 2; - bbatt -= 2; - } - } - } - /* Save the control values */ - phy->tx_control = tx_control; - b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); - phy->rfatt.att = rfatt; - phy->bbatt.att = bbatt; - - /* Adjust the hardware */ - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, - phy->tx_control); - b43_radio_unlock(dev); - b43_phy_unlock(dev); - break; - } - case B43_PHYTYPE_N: - b43_nphy_xmitpower(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) -{ - if (num < 0) - return num / den; - else - return (num + den / 2) / den; -} - -static inline - s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) -{ - s32 m1, m2, f = 256, q, delta; - s8 i = 0; - - m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); - m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); - do { - if (i > 15) - return -EINVAL; - q = b43_tssi2dbm_ad(f * 4096 - - b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); - delta = abs(q - f); - f = q; - i++; - } while (delta >= 2); - entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 pab0, pab1, pab2; - u8 idx; - s8 *dyn_tssi2dbm; - - if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.pa1b2); - } else { - pab0 = (s16) (dev->dev->bus->sprom.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.pa0b2); - } - - if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - return 0; - } - - if (pab0 != 0 && pab1 != 0 && pab2 != 0 && - pab0 != -1 && pab1 != -1 && pab2 != -1) { - /* The pabX values are set in SPROM. Use them. */ - if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.itssi_a != 0 && - (s8) dev->dev->bus->sprom.itssi_a != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_a); - else - phy->tgt_idle_tssi = 62; - } else { - if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.itssi_bg != -1) - phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.itssi_bg); - else - phy->tgt_idle_tssi = 62; - } - dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); - if (dyn_tssi2dbm == NULL) { - b43err(dev->wl, "Could not allocate memory " - "for tssi2dbm table\n"); - return -ENOMEM; - } - for (idx = 0; idx < 64; idx++) - if (b43_tssi2dbm_entry - (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate " - "tssi2dBm table\n"); - kfree(dyn_tssi2dbm); - return -ENODEV; - } - phy->tssi2dbm = dyn_tssi2dbm; - phy->dyn_tssi_tbl = 1; - } else { - /* pabX values not set in SPROM. */ - switch (phy->type) { - case B43_PHYTYPE_A: - /* APHY needs a generated table. */ - phy->tssi2dbm = NULL; - b43err(dev->wl, "Could not generate tssi2dBm " - "table (wrong SPROM info)!\n"); - return -ENODEV; - case B43_PHYTYPE_B: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_b_table; - break; - case B43_PHYTYPE_G: - phy->tgt_idle_tssi = 0x34; - phy->tssi2dbm = b43_tssi2dbm_g_table; - break; - } - } - - return 0; -} - -int b43_phy_init(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - bool unsupported = 0; - int err = 0; - - switch (phy->type) { - case B43_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) - b43_phy_inita(dev); - else - unsupported = 1; - break; - case B43_PHYTYPE_G: - b43_phy_initg(dev); - break; - case B43_PHYTYPE_N: - err = b43_phy_initn(dev); - break; - default: - unsupported = 1; - } - if (unsupported) - b43err(dev->wl, "Unknown PHYTYPE found\n"); - - return err; -} - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) -{ - struct b43_phy *phy = &dev->phy; - u64 hf; - u16 tmp; - int autodiv = 0; - - if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) - autodiv = 1; - - hf = b43_hf_read(dev); - hf &= ~B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); - - switch (phy->type) { - case B43_PHYTYPE_A: - case B43_PHYTYPE_G: - tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); - - if (autodiv) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - if (antenna == B43_ANTENNA_AUTO0) - tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; - else - tmp |= B43_PHY_ANTDWELL_AUTODIV1; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } - if (phy->type == B43_PHYTYPE_G) { - tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); - if (autodiv) - tmp |= B43_PHY_ANTWRSETT_ARXDIV; - else - tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; - b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); - if (phy->rev >= 2) { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= B43_PHY_OFDM61_10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - - tmp = - b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); - tmp = (tmp & 0xFF00) | 0x15; - b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, - tmp); - - if (phy->rev == 2) { - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - if (phy->rev >= 6) - b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); - } else { - if (phy->rev < 3) { - tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); - tmp = (tmp & 0xFF00) | 0x24; - b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); - } else { - tmp = b43_phy_read(dev, B43_PHY_OFDM61); - tmp |= 0x10; - b43_phy_write(dev, B43_PHY_OFDM61, tmp); - if (phy->analog == 3) { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x1D); - b43_phy_write(dev, B43_PHY_ADIVRELATED, - 8); - } else { - b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, - 0x3A); - tmp = - b43_phy_read(dev, - B43_PHY_ADIVRELATED); - tmp = (tmp & 0xFF00) | 8; - b43_phy_write(dev, B43_PHY_ADIVRELATED, - tmp); - } - } - } - break; - case B43_PHYTYPE_B: - tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); - tmp &= ~B43_PHY_BBANDCFG_RXANT; - tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) - << B43_PHY_BBANDCFG_RXANT_SHIFT; - b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); - break; - case B43_PHYTYPE_N: - b43_nphy_set_rxantenna(dev, antenna); - break; - default: - B43_WARN_ON(1); - } - - hf |= B43_HF_ANTDIVHELP; - b43_hf_write(dev, hf); -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_bg(u8 channel) -{ - B43_WARN_ON(!(channel >= 1 && channel <= 14)); - - return b43_radio_channel_codes_bg[channel - 1]; -} - -/* Get the freq, as it has to be written to the device. */ -static inline u16 channel2freq_a(u8 channel) -{ - B43_WARN_ON(channel > 200); - - return (5000 + 5 * channel); -} - -void b43_radio_lock(struct b43_wldev *dev) -{ - u32 macctl; - - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); - macctl |= B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); - /* Commit the write and wait for the device - * to exit any radio register access. */ - b43_read32(dev, B43_MMIO_MACCTL); - udelay(10); -} - -void b43_radio_unlock(struct b43_wldev *dev) -{ - u32 macctl; - - /* Commit any write */ - b43_read16(dev, B43_MMIO_PHY_VER); - /* unlock */ - macctl = b43_read32(dev, B43_MMIO_MACCTL); - B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); - macctl &= ~B43_MACCTL_RADIOLOCK; - b43_write32(dev, B43_MMIO_MACCTL, macctl); -} - -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) -{ - struct b43_phy *phy = &dev->phy; - - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - switch (phy->type) { - case B43_PHYTYPE_A: - offset |= 0x40; - break; - case B43_PHYTYPE_B: - if (phy->radio_ver == 0x2053) { - if (offset < 0x70) - offset += 0x80; - else if (offset < 0x80) - offset += 0x70; - } else if (phy->radio_ver == 0x2050) { - offset |= 0x80; - } else - B43_WARN_ON(1); - break; - case B43_PHYTYPE_G: - offset |= 0x80; - break; - case B43_PHYTYPE_N: - offset |= 0x100; - break; - case B43_PHYTYPE_LP: - /* No adjustment required. */ - break; - default: - B43_WARN_ON(1); - } - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); -} - -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) -{ - /* Offset 1 is a 32-bit register. */ - B43_WARN_ON(offset == 1); - - b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); -} - -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) & mask); -} - -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) -{ - b43_radio_write16(dev, offset, - b43_radio_read16(dev, offset) | set); -} - -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) -{ - b43_radio_write16(dev, offset, - (b43_radio_read16(dev, offset) & mask) | set); -} - -static void b43_set_all_gains(struct b43_wldev *dev, - s16 first, s16 second, s16 third) -{ - struct b43_phy *phy = &dev->phy; - u16 i; - u16 start = 0x08, end = 0x18; - u16 tmp; - u16 table; - - if (phy->rev <= 1) { - start = 0x10; - end = 0x20; - } - - table = B43_OFDMTAB_GAINX; - if (phy->rev <= 1) - table = B43_OFDMTAB_GAINX_R1; - for (i = 0; i < 4; i++) - b43_ofdmtab_write16(dev, table, i, first); - - for (i = start; i < end; i++) - b43_ofdmtab_write16(dev, table, i, second); - - if (third != -1) { - tmp = ((u16) third << 14) | ((u16) third << 6); - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); - } - b43_dummy_transmission(dev); -} - -static void b43_set_original_gains(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 i, tmp; - u16 table; - u16 start = 0x0008, end = 0x0018; - - if (phy->rev <= 1) { - start = 0x0010; - end = 0x0020; - } - - table = B43_OFDMTAB_GAINX; - if (phy->rev <= 1) - table = B43_OFDMTAB_GAINX_R1; - for (i = 0; i < 4; i++) { - tmp = (i & 0xFFFC); - tmp |= (i & 0x0001) << 1; - tmp |= (i & 0x0002) >> 1; - - b43_ofdmtab_write16(dev, table, i, tmp); - } - - for (i = start; i < end; i++) - b43_ofdmtab_write16(dev, table, i, i - start); - - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); - b43_dummy_transmission(dev); -} - -/* Synthetic PU workaround */ -static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - - might_sleep(); - - if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { - /* We do not need the workaround. */ - return; - } - - if (channel <= 10) { - b43_write16(dev, B43_MMIO_CHANNEL, - channel2freq_bg(channel + 4)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); - } - msleep(1); - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); -} - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel) -{ - struct b43_phy *phy = &dev->phy; - u8 ret = 0; - u16 saved, rssi, temp; - int i, j = 0; - - saved = b43_phy_read(dev, 0x0403); - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); - if (phy->aci_hw_rssi) - rssi = b43_phy_read(dev, 0x048A) & 0x3F; - else - rssi = saved & 0x3F; - /* clamp temp to signed 5bit */ - if (rssi > 32) - rssi -= 64; - for (i = 0; i < 100; i++) { - temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; - if (temp > 32) - temp -= 64; - if (temp < rssi) - j++; - if (j >= 20) - ret = 1; - } - b43_phy_write(dev, 0x0403, saved); - - return ret; -} - -u8 b43_radio_aci_scan(struct b43_wldev * dev) -{ - struct b43_phy *phy = &dev->phy; - u8 ret[13]; - unsigned int channel = phy->channel; - unsigned int i, j, start, end; - - if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) - return 0; - - b43_phy_lock(dev); - b43_radio_lock(dev); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_set_all_gains(dev, 3, 8, 1); - - start = (channel - 5 > 0) ? channel - 5 : 1; - end = (channel + 5 < 14) ? channel + 5 : 13; - - for (i = start; i <= end; i++) { - if (abs(channel - i) > 2) - ret[i - 1] = b43_radio_aci_detect(dev, i); - } - b43_radio_selectchannel(dev, channel, 0); - b43_phy_write(dev, 0x0802, - (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); - b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - b43_set_original_gains(dev); - for (i = 0; i < 13; i++) { - if (!ret[i]) - continue; - end = (i + 5 < 13) ? i + 5 : 13; - for (j = i; j < end; j++) - ret[j] = 1; - } - b43_radio_unlock(dev); - b43_phy_unlock(dev); - - return ret[channel - 1]; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) -{ - b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - mmiowb(); - b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) -{ - u16 val; - - b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); - val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); - - return (s16) val; -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) -{ - u16 i; - s16 tmp; - - for (i = 0; i < 64; i++) { - tmp = b43_nrssi_hw_read(dev, i); - tmp -= val; - tmp = clamp_val(tmp, -32, 31); - b43_nrssi_hw_write(dev, i, tmp); - } -} - -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_mem_update(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s16 i, delta; - s32 tmp; - - delta = 0x1F - phy->nrssi[0]; - for (i = 0; i < 64; i++) { - tmp = (i - delta) * phy->nrssislope; - tmp /= 0x10000; - tmp += 0x3A; - tmp = clamp_val(tmp, 0, 0x3F); - phy->nrssi_lt[i] = tmp; - } -} - -static void b43_calc_nrssi_offset(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup[20] = { 0 }; - s16 v47F; - u16 i; - u16 saved = 0xFFFF; - - backup[0] = b43_phy_read(dev, 0x0001); - backup[1] = b43_phy_read(dev, 0x0811); - backup[2] = b43_phy_read(dev, 0x0812); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - backup[3] = b43_phy_read(dev, 0x0814); - backup[4] = b43_phy_read(dev, 0x0815); - } - backup[5] = b43_phy_read(dev, 0x005A); - backup[6] = b43_phy_read(dev, 0x0059); - backup[7] = b43_phy_read(dev, 0x0058); - backup[8] = b43_phy_read(dev, 0x000A); - backup[9] = b43_phy_read(dev, 0x0003); - backup[10] = b43_radio_read16(dev, 0x007A); - backup[11] = b43_radio_read16(dev, 0x0043); - - b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); - b43_phy_write(dev, 0x0001, - (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); - if (phy->rev >= 6) { - backup[12] = b43_phy_read(dev, 0x002E); - backup[13] = b43_phy_read(dev, 0x002F); - backup[14] = b43_phy_read(dev, 0x080F); - backup[15] = b43_phy_read(dev, 0x0810); - backup[16] = b43_phy_read(dev, 0x0801); - backup[17] = b43_phy_read(dev, 0x0060); - backup[18] = b43_phy_read(dev, 0x0014); - backup[19] = b43_phy_read(dev, 0x0478); - - b43_phy_write(dev, 0x002E, 0); - b43_phy_write(dev, 0x002F, 0); - b43_phy_write(dev, 0x080F, 0); - b43_phy_write(dev, 0x0810, 0); - b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); - b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); - b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); - } - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); - udelay(30); - - v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == 31) { - for (i = 7; i >= 4; i--) { - b43_radio_write16(dev, 0x007B, i); - udelay(20); - v47F = - (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F < 31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 4; - } else { - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, - b43_phy_read(dev, 0x0814) | 0x0001); - b43_phy_write(dev, 0x0815, - b43_phy_read(dev, 0x0815) & 0xFFFE); - } - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); - b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); - b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - if (phy->rev == 0) { - b43_phy_write(dev, 0x0003, 0x0122); - } else { - b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) - | 0x2000); - } - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, - b43_phy_read(dev, 0x0814) | 0x0004); - b43_phy_write(dev, 0x0815, - b43_phy_read(dev, 0x0815) & 0xFFFB); - } - b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) - | 0x0040); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x000F); - b43_set_all_gains(dev, 3, 0, 1); - b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) - & 0x00F0) | 0x000F); - udelay(30); - v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F == -32) { - for (i = 0; i < 4; i++) { - b43_radio_write16(dev, 0x007B, i); - udelay(20); - v47F = - (s16) ((b43_phy_read(dev, 0x047F) >> 8) & - 0x003F); - if (v47F >= 0x20) - v47F -= 0x40; - if (v47F > -31 && saved == 0xFFFF) - saved = i; - } - if (saved == 0xFFFF) - saved = 3; - } else - saved = 0; - } - b43_radio_write16(dev, 0x007B, saved); - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x002E, backup[12]); - b43_phy_write(dev, 0x002F, backup[13]); - b43_phy_write(dev, 0x080F, backup[14]); - b43_phy_write(dev, 0x0810, backup[15]); - } - if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ - b43_phy_write(dev, 0x0814, backup[3]); - b43_phy_write(dev, 0x0815, backup[4]); - } - b43_phy_write(dev, 0x005A, backup[5]); - b43_phy_write(dev, 0x0059, backup[6]); - b43_phy_write(dev, 0x0058, backup[7]); - b43_phy_write(dev, 0x000A, backup[8]); - b43_phy_write(dev, 0x0003, backup[9]); - b43_radio_write16(dev, 0x0043, backup[11]); - b43_radio_write16(dev, 0x007A, backup[10]); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); - b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); - b43_set_original_gains(dev); - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0801, backup[16]); - b43_phy_write(dev, 0x0060, backup[17]); - b43_phy_write(dev, 0x0014, backup[18]); - b43_phy_write(dev, 0x0478, backup[19]); - } - b43_phy_write(dev, 0x0001, backup[0]); - b43_phy_write(dev, 0x0812, backup[2]); - b43_phy_write(dev, 0x0811, backup[1]); -} - -void b43_calc_nrssi_slope(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 backup[18] = { 0 }; - u16 tmp; - s16 nrssi0, nrssi1; - - switch (phy->type) { - case B43_PHYTYPE_B: - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0030); - backup[4] = b43_phy_read(dev, 0x0026); - backup[5] = b43_phy_read(dev, 0x0015); - backup[6] = b43_phy_read(dev, 0x002A); - backup[7] = b43_phy_read(dev, 0x0020); - backup[8] = b43_phy_read(dev, 0x005A); - backup[9] = b43_phy_read(dev, 0x0059); - backup[10] = b43_phy_read(dev, 0x0058); - backup[11] = b43_read16(dev, 0x03E2); - backup[12] = b43_read16(dev, 0x03E6); - backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - - tmp = b43_radio_read16(dev, 0x007A); - tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; - b43_radio_write16(dev, 0x007A, tmp); - b43_phy_write(dev, 0x0030, 0x00FF); - b43_write16(dev, 0x03EC, 0x7F7F); - b43_phy_write(dev, 0x0026, 0x0000); - b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020); - b43_phy_write(dev, 0x002A, 0x08A3); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); - - nrssi0 = (s16) b43_phy_read(dev, 0x0027); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_write16(dev, 0x03E6, 0x0040); - } else if (phy->rev == 0) { - b43_write16(dev, 0x03E6, 0x0122); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, - B43_MMIO_CHANNEL_EXT) & 0x2000); - } - b43_phy_write(dev, 0x0020, 0x3F3F); - b43_phy_write(dev, 0x0015, 0xF330); - b43_radio_write16(dev, 0x005A, 0x0060); - b43_radio_write16(dev, 0x0043, - b43_radio_read16(dev, 0x0043) & 0x00F0); - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - - nrssi1 = (s16) b43_phy_read(dev, 0x0027); - b43_phy_write(dev, 0x0030, backup[3]); - b43_radio_write16(dev, 0x007A, backup[0]); - b43_write16(dev, 0x03E2, backup[11]); - b43_phy_write(dev, 0x0026, backup[4]); - b43_phy_write(dev, 0x0015, backup[5]); - b43_phy_write(dev, 0x002A, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - if (phy->rev != 0) - b43_write16(dev, 0x03F4, backup[13]); - - b43_phy_write(dev, 0x0020, backup[7]); - b43_phy_write(dev, 0x005A, backup[8]); - b43_phy_write(dev, 0x0059, backup[9]); - b43_phy_write(dev, 0x0058, backup[10]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - - if (nrssi0 <= -4) { - phy->nrssi[0] = nrssi0; - phy->nrssi[1] = nrssi1; - } - break; - case B43_PHYTYPE_G: - if (phy->radio_rev >= 9) - return; - if (phy->radio_rev == 8) - b43_calc_nrssi_offset(dev); - - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); - b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); - backup[7] = b43_read16(dev, 0x03E2); - b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); - backup[0] = b43_radio_read16(dev, 0x007A); - backup[1] = b43_radio_read16(dev, 0x0052); - backup[2] = b43_radio_read16(dev, 0x0043); - backup[3] = b43_phy_read(dev, 0x0015); - backup[4] = b43_phy_read(dev, 0x005A); - backup[5] = b43_phy_read(dev, 0x0059); - backup[6] = b43_phy_read(dev, 0x0058); - backup[8] = b43_read16(dev, 0x03E6); - backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); - if (phy->rev >= 3) { - backup[10] = b43_phy_read(dev, 0x002E); - backup[11] = b43_phy_read(dev, 0x002F); - backup[12] = b43_phy_read(dev, 0x080F); - backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); - backup[14] = b43_phy_read(dev, 0x0801); - backup[15] = b43_phy_read(dev, 0x0060); - backup[16] = b43_phy_read(dev, 0x0014); - backup[17] = b43_phy_read(dev, 0x0478); - b43_phy_write(dev, 0x002E, 0); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); - switch (phy->rev) { - case 4: - case 6: - case 7: - b43_phy_write(dev, 0x0478, - b43_phy_read(dev, 0x0478) - | 0x0100); - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - | 0x0040); - break; - case 3: - case 5: - b43_phy_write(dev, 0x0801, - b43_phy_read(dev, 0x0801) - & 0xFFBF); - break; - } - b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) - | 0x0040); - b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) - | 0x0200); - } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0070); - b43_set_all_gains(dev, 0, 8, 0); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x00F7); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0030); - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0010); - } - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x0080); - udelay(20); - - nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi0 >= 0x0020) - nrssi0 -= 0x0040; - - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) & 0x007F); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) - & 0xFF9F) | 0x0040); - } - - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | 0x2000); - b43_radio_write16(dev, 0x007A, - b43_radio_read16(dev, 0x007A) | 0x000F); - b43_phy_write(dev, 0x0015, 0xF330); - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - (b43_phy_read(dev, 0x0812) & 0xFFCF) | - 0x0020); - b43_phy_write(dev, 0x0811, - (b43_phy_read(dev, 0x0811) & 0xFFCF) | - 0x0020); - } - - b43_set_all_gains(dev, 3, 0, 1); - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x0043, 0x001F); - } else { - tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; - b43_radio_write16(dev, 0x0052, tmp | 0x0060); - tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; - b43_radio_write16(dev, 0x0043, tmp | 0x0009); - } - b43_phy_write(dev, 0x005A, 0x0480); - b43_phy_write(dev, 0x0059, 0x0810); - b43_phy_write(dev, 0x0058, 0x000D); - udelay(20); - nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); - if (nrssi1 >= 0x0020) - nrssi1 -= 0x0040; - if (nrssi0 == nrssi1) - phy->nrssislope = 0x00010000; - else - phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); - if (nrssi0 >= -4) { - phy->nrssi[0] = nrssi1; - phy->nrssi[1] = nrssi0; - } - if (phy->rev >= 3) { - b43_phy_write(dev, 0x002E, backup[10]); - b43_phy_write(dev, 0x002F, backup[11]); - b43_phy_write(dev, 0x080F, backup[12]); - b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); - } - if (phy->rev >= 2) { - b43_phy_write(dev, 0x0812, - b43_phy_read(dev, 0x0812) & 0xFFCF); - b43_phy_write(dev, 0x0811, - b43_phy_read(dev, 0x0811) & 0xFFCF); - } - - b43_radio_write16(dev, 0x007A, backup[0]); - b43_radio_write16(dev, 0x0052, backup[1]); - b43_radio_write16(dev, 0x0043, backup[2]); - b43_write16(dev, 0x03E2, backup[7]); - b43_write16(dev, 0x03E6, backup[8]); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); - b43_phy_write(dev, 0x0015, backup[3]); - b43_phy_write(dev, 0x005A, backup[4]); - b43_phy_write(dev, 0x0059, backup[5]); - b43_phy_write(dev, 0x0058, backup[6]); - b43_synth_pu_workaround(dev, phy->channel); - b43_phy_write(dev, 0x0802, - b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); - b43_set_original_gains(dev); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); - if (phy->rev >= 3) { - b43_phy_write(dev, 0x0801, backup[14]); - b43_phy_write(dev, 0x0060, backup[15]); - b43_phy_write(dev, 0x0014, backup[16]); - b43_phy_write(dev, 0x0478, backup[17]); - } - b43_nrssi_mem_update(dev); - b43_calc_nrssi_threshold(dev); - break; - default: - B43_WARN_ON(1); - } -} - -void b43_calc_nrssi_threshold(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - s32 threshold; - s32 a, b; - s16 tmp16; - u16 tmp_u16; - - switch (phy->type) { - case B43_PHYTYPE_B:{ - if (phy->radio_ver != 0x2050) - return; - if (! - (dev->dev->bus->sprom. - boardflags_lo & B43_BFL_RSSI)) - return; - - if (phy->radio_rev >= 6) { - threshold = - (phy->nrssi[1] - phy->nrssi[0]) * 32; - threshold += 20 * (phy->nrssi[0] + 1); - threshold /= 40; - } else - threshold = phy->nrssi[1] - 5; - - threshold = clamp_val(threshold, 0, 0x3E); - b43_phy_read(dev, 0x0020); /* dummy read */ - b43_phy_write(dev, 0x0020, - (((u16) threshold) << 8) | 0x001C); - - if (phy->radio_rev >= 6) { - b43_phy_write(dev, 0x0087, 0x0E0D); - b43_phy_write(dev, 0x0086, 0x0C0B); - b43_phy_write(dev, 0x0085, 0x0A09); - b43_phy_write(dev, 0x0084, 0x0808); - b43_phy_write(dev, 0x0083, 0x0808); - b43_phy_write(dev, 0x0082, 0x0604); - b43_phy_write(dev, 0x0081, 0x0302); - b43_phy_write(dev, 0x0080, 0x0100); - } - break; - } - case B43_PHYTYPE_G: - if (!phy->gmode || - !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { - tmp16 = b43_nrssi_hw_read(dev, 0x20); - if (tmp16 >= 0x20) - tmp16 -= 0x40; - if (tmp16 < 3) { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x09EB); - } else { - b43_phy_write(dev, 0x048A, - (b43_phy_read(dev, 0x048A) - & 0xF000) | 0x0AED); - } - } else { - if (phy->interfmode == B43_INTERFMODE_NONWLAN) { - a = 0xE; - b = 0xA; - } else if (!phy->aci_wlan_automatic && phy->aci_enable) { - a = 0x13; - b = 0x12; - } else { - a = 0xE; - b = 0x11; - } - - a = a * (phy->nrssi[1] - phy->nrssi[0]); - a += (phy->nrssi[0] << 6); - if (a < 32) - a += 31; - else - a += 32; - a = a >> 6; - a = clamp_val(a, -31, 31); - - b = b * (phy->nrssi[1] - phy->nrssi[0]); - b += (phy->nrssi[0] << 6); - if (b < 32) - b += 31; - else - b += 32; - b = b >> 6; - b = clamp_val(b, -31, 31); - - tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; - tmp_u16 |= ((u32) b & 0x0000003F); - tmp_u16 |= (((u32) a & 0x0000003F) << 6); - b43_phy_write(dev, 0x048A, tmp_u16); - } - break; - default: - B43_WARN_ON(1); - } -} - -/* Stack implementation to save/restore values from the - * interference mitigation code. - * It is save to restore values in random order. - */ -static void _stack_save(u32 * _stackptr, size_t * stackidx, - u8 id, u16 offset, u16 value) -{ - u32 *stackptr = &(_stackptr[*stackidx]); - - B43_WARN_ON(offset & 0xF000); - B43_WARN_ON(id & 0xF0); - *stackptr = offset; - *stackptr |= ((u32) id) << 12; - *stackptr |= ((u32) value) << 16; - (*stackidx)++; - B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); -} - -static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) -{ - size_t i; - - B43_WARN_ON(offset & 0xF000); - B43_WARN_ON(id & 0xF0); - for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { - if ((*stackptr & 0x00000FFF) != offset) - continue; - if (((*stackptr & 0x0000F000) >> 12) != id) - continue; - return ((*stackptr & 0xFFFF0000) >> 16); - } - B43_WARN_ON(1); - - return 0; -} - -#define phy_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x1, (offset), \ - b43_phy_read(dev, (offset))); \ - } while (0) -#define phy_stackrestore(offset) \ - do { \ - b43_phy_write(dev, (offset), \ - _stack_restore(stack, 0x1, \ - (offset))); \ - } while (0) -#define radio_stacksave(offset) \ - do { \ - _stack_save(stack, &stackidx, 0x2, (offset), \ - b43_radio_read16(dev, (offset))); \ - } while (0) -#define radio_stackrestore(offset) \ - do { \ - b43_radio_write16(dev, (offset), \ - _stack_restore(stack, 0x2, \ - (offset))); \ - } while (0) -#define ofdmtab_stacksave(table, offset) \ - do { \ - _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ - b43_ofdmtab_read16(dev, (table), (offset))); \ - } while (0) -#define ofdmtab_stackrestore(table, offset) \ - do { \ - b43_ofdmtab_write16(dev, (table), (offset), \ - _stack_restore(stack, 0x3, \ - (offset)|(table))); \ - } while (0) - -static void -b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - u16 tmp, flipped; - size_t stackidx = 0; - u32 *stack = phy->interfstack; - - switch (mode) { - case B43_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - b43_phy_write(dev, 0x042B, - b43_phy_read(dev, 0x042B) | 0x0800); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, - B43_PHY_G_CRS) & ~0x4000); - break; - } - radio_stacksave(0x0078); - tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); - B43_WARN_ON(tmp > 15); - flipped = bitrev4(tmp); - if (flipped < 10 && flipped >= 8) - flipped = 7; - else if (flipped >= 10) - flipped -= 3; - flipped = (bitrev4(flipped) << 1) | 0x0020; - b43_radio_write16(dev, 0x0078, flipped); - - b43_calc_nrssi_threshold(dev); - - phy_stacksave(0x0406); - b43_phy_write(dev, 0x0406, 0x7E28); - - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, - B43_PHY_RADIO_BITFIELD) | 0x1000); - - phy_stacksave(0x04A0); - b43_phy_write(dev, 0x04A0, - (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); - phy_stacksave(0x04A1); - b43_phy_write(dev, 0x04A1, - (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); - phy_stacksave(0x04A2); - b43_phy_write(dev, 0x04A2, - (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); - phy_stacksave(0x04A8); - b43_phy_write(dev, 0x04A8, - (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); - phy_stacksave(0x04AB); - b43_phy_write(dev, 0x04AB, - (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); - - phy_stacksave(0x04A7); - b43_phy_write(dev, 0x04A7, 0x0002); - phy_stacksave(0x04A3); - b43_phy_write(dev, 0x04A3, 0x287A); - phy_stacksave(0x04A9); - b43_phy_write(dev, 0x04A9, 0x2027); - phy_stacksave(0x0493); - b43_phy_write(dev, 0x0493, 0x32F5); - phy_stacksave(0x04AA); - b43_phy_write(dev, 0x04AA, 0x2027); - phy_stacksave(0x04AC); - b43_phy_write(dev, 0x04AC, 0x32F5); - break; - case B43_INTERFMODE_MANUALWLAN: - if (b43_phy_read(dev, 0x0033) & 0x0800) - break; - - phy->aci_enable = 1; - - phy_stacksave(B43_PHY_RADIO_BITFIELD); - phy_stacksave(B43_PHY_G_CRS); - if (phy->rev < 2) { - phy_stacksave(0x0406); - } else { - phy_stacksave(0x04C0); - phy_stacksave(0x04C1); - } - phy_stacksave(0x0033); - phy_stacksave(0x04A7); - phy_stacksave(0x04A3); - phy_stacksave(0x04A9); - phy_stacksave(0x04AA); - phy_stacksave(0x04AC); - phy_stacksave(0x0493); - phy_stacksave(0x04A1); - phy_stacksave(0x04A0); - phy_stacksave(0x04A2); - phy_stacksave(0x048A); - phy_stacksave(0x04A8); - phy_stacksave(0x04AB); - if (phy->rev == 2) { - phy_stacksave(0x04AD); - phy_stacksave(0x04AE); - } else if (phy->rev >= 3) { - phy_stacksave(0x04AD); - phy_stacksave(0x0415); - phy_stacksave(0x0416); - phy_stacksave(0x0417); - ofdmtab_stacksave(0x1A00, 0x2); - ofdmtab_stacksave(0x1A00, 0x3); - } - phy_stacksave(0x042B); - phy_stacksave(0x048C); - - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) - & ~0x1000); - b43_phy_write(dev, B43_PHY_G_CRS, - (b43_phy_read(dev, B43_PHY_G_CRS) - & 0xFFFC) | 0x0002); - - b43_phy_write(dev, 0x0033, 0x0800); - b43_phy_write(dev, 0x04A3, 0x2027); - b43_phy_write(dev, 0x04A9, 0x1CA8); - b43_phy_write(dev, 0x0493, 0x287A); - b43_phy_write(dev, 0x04AA, 0x1CA8); - b43_phy_write(dev, 0x04AC, 0x287A); - - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xFFC0) | 0x001A); - b43_phy_write(dev, 0x04A7, 0x000D); - - if (phy->rev < 2) { - b43_phy_write(dev, 0x0406, 0xFF0D); - } else if (phy->rev == 2) { - b43_phy_write(dev, 0x04C0, 0xFFFF); - b43_phy_write(dev, 0x04C1, 0x00A9); - } else { - b43_phy_write(dev, 0x04C0, 0x00C1); - b43_phy_write(dev, 0x04C1, 0x0059); - } - - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xC0FF) | 0x1800); - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xFFC0) | 0x0015); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xCFFF) | 0x1000); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xF0FF) | 0x0A00); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xCFFF) | 0x1000); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xF0FF) | 0x0800); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xFFCF) | 0x0010); - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xFFF0) | 0x0005); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xFFCF) | 0x0010); - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0xFFF0) | 0x0006); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xF0FF) | 0x0800); - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xF0FF) | 0x0500); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xFFF0) | 0x000B); - - if (phy->rev >= 3) { - b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) - & ~0x8000); - b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) - & 0x8000) | 0x36D8); - b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) - & 0x8000) | 0x36D8); - b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) - & 0xFE00) | 0x016D); - } else { - b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) - | 0x1000); - b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) - & 0x9FFF) | 0x2000); - b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); - } - if (phy->rev >= 2) { - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) - | 0x0800); - } - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xF0FF) | 0x0200); - if (phy->rev == 2) { - b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) - & 0xFF00) | 0x007F); - b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) - & 0x00FF) | 0x1300); - } else if (phy->rev >= 6) { - b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); - b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); - b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) - & 0x00FF); - } - b43_calc_nrssi_slope(dev); - break; - default: - B43_WARN_ON(1); - } -} - -static void -b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - u32 *stack = phy->interfstack; - - switch (mode) { - case B43_INTERFMODE_NONWLAN: - if (phy->rev != 1) { - b43_phy_write(dev, 0x042B, - b43_phy_read(dev, 0x042B) & ~0x0800); - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, - B43_PHY_G_CRS) | 0x4000); - break; - } - radio_stackrestore(0x0078); - b43_calc_nrssi_threshold(dev); - phy_stackrestore(0x0406); - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); - if (!dev->bad_frames_preempt) { - b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, - b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) - & ~(1 << 11)); - } - b43_phy_write(dev, B43_PHY_G_CRS, - b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04A2); - phy_stackrestore(0x04A8); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A7); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - break; - case B43_INTERFMODE_MANUALWLAN: - if (!(b43_phy_read(dev, 0x0033) & 0x0800)) - break; - - phy->aci_enable = 0; - - phy_stackrestore(B43_PHY_RADIO_BITFIELD); - phy_stackrestore(B43_PHY_G_CRS); - phy_stackrestore(0x0033); - phy_stackrestore(0x04A3); - phy_stackrestore(0x04A9); - phy_stackrestore(0x0493); - phy_stackrestore(0x04AA); - phy_stackrestore(0x04AC); - phy_stackrestore(0x04A0); - phy_stackrestore(0x04A7); - if (phy->rev >= 2) { - phy_stackrestore(0x04C0); - phy_stackrestore(0x04C1); - } else - phy_stackrestore(0x0406); - phy_stackrestore(0x04A1); - phy_stackrestore(0x04AB); - phy_stackrestore(0x04A8); - if (phy->rev == 2) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x04AE); - } else if (phy->rev >= 3) { - phy_stackrestore(0x04AD); - phy_stackrestore(0x0415); - phy_stackrestore(0x0416); - phy_stackrestore(0x0417); - ofdmtab_stackrestore(0x1A00, 0x2); - ofdmtab_stackrestore(0x1A00, 0x3); - } - phy_stackrestore(0x04A2); - phy_stackrestore(0x048A); - phy_stackrestore(0x042B); - phy_stackrestore(0x048C); - b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); - b43_calc_nrssi_slope(dev); - break; - default: - B43_WARN_ON(1); - } -} - -#undef phy_stacksave -#undef phy_stackrestore -#undef radio_stacksave -#undef radio_stackrestore -#undef ofdmtab_stacksave -#undef ofdmtab_stackrestore - -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode) -{ - struct b43_phy *phy = &dev->phy; - int currentmode; - - if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode)) - return -ENODEV; - - phy->aci_wlan_automatic = 0; - switch (mode) { - case B43_INTERFMODE_AUTOWLAN: - phy->aci_wlan_automatic = 1; - if (phy->aci_enable) - mode = B43_INTERFMODE_MANUALWLAN; - else - mode = B43_INTERFMODE_NONE; - break; - case B43_INTERFMODE_NONE: - case B43_INTERFMODE_NONWLAN: - case B43_INTERFMODE_MANUALWLAN: - break; - default: - return -EINVAL; - } - - currentmode = phy->interfmode; - if (currentmode == mode) - return 0; - if (currentmode != B43_INTERFMODE_NONE) - b43_radio_interference_mitigation_disable(dev, currentmode); - - if (mode == B43_INTERFMODE_NONE) { - phy->aci_enable = 0; - phy->aci_hw_rssi = 0; - } else - b43_radio_interference_mitigation_enable(dev, mode); - phy->interfmode = mode; - - return 0; -} - -static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) -{ - u16 reg, index, ret; - - static const u8 rcc_table[] = { - 0x02, 0x03, 0x01, 0x0F, - 0x06, 0x07, 0x05, 0x0F, - 0x0A, 0x0B, 0x09, 0x0F, - 0x0E, 0x0F, 0x0D, 0x0F, - }; - - reg = b43_radio_read16(dev, 0x60); - index = (reg & 0x001E) >> 1; - ret = rcc_table[index] << 1; - ret |= (reg & 0x0001); - ret |= 0x0020; - - return ret; -} - -#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) -static u16 radio2050_rfover_val(struct b43_wldev *dev, - u16 phy_register, unsigned int lpd) -{ - struct b43_phy *phy = &dev->phy; - struct ssb_sprom *sprom = &(dev->dev->bus->sprom); - - if (!phy->gmode) - return 0; - - if (has_loopback_gain(phy)) { - int max_lb_gain = phy->max_lb_gain; - u16 extlna; - u16 i; - - if (phy->radio_rev == 8) - max_lb_gain += 0x3E; - else - max_lb_gain += 0x26; - if (max_lb_gain >= 0x46) { - extlna = 0x3000; - max_lb_gain -= 0x46; - } else if (max_lb_gain >= 0x3A) { - extlna = 0x1000; - max_lb_gain -= 0x3A; - } else if (max_lb_gain >= 0x2E) { - extlna = 0x2000; - max_lb_gain -= 0x2E; - } else { - extlna = 0; - max_lb_gain -= 0x10; - } - - for (i = 0; i < 16; i++) { - max_lb_gain -= (i * 6); - if (max_lb_gain < 6) - break; - } - - if ((phy->rev < 7) || - !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { - if (phy_register == B43_PHY_RFOVER) { - return 0x1B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - extlna |= (i << 8); - switch (lpd) { - case LPD(0, 1, 1): - return 0x0F92; - case LPD(0, 0, 1): - case LPD(1, 0, 1): - return (0x0092 | extlna); - case LPD(1, 0, 0): - return (0x0093 | extlna); - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } else { - if (phy_register == B43_PHY_RFOVER) { - return 0x9B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - if (extlna) - extlna |= 0x8000; - extlna |= (i << 8); - switch (lpd) { - case LPD(0, 1, 1): - return 0x8F92; - case LPD(0, 0, 1): - return (0x8092 | extlna); - case LPD(1, 0, 1): - return (0x2092 | extlna); - case LPD(1, 0, 0): - return (0x2093 | extlna); - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } - } else { - if ((phy->rev < 7) || - !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { - if (phy_register == B43_PHY_RFOVER) { - return 0x1B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x0FB2; - case LPD(0, 0, 1): - return 0x00B2; - case LPD(1, 0, 1): - return 0x30B2; - case LPD(1, 0, 0): - return 0x30B3; - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } else { - if (phy_register == B43_PHY_RFOVER) { - return 0x9B3; - } else if (phy_register == B43_PHY_RFOVERVAL) { - switch (lpd) { - case LPD(0, 1, 1): - return 0x8FB2; - case LPD(0, 0, 1): - return 0x80B2; - case LPD(1, 0, 1): - return 0x20B2; - case LPD(1, 0, 0): - return 0x20B3; - } - B43_WARN_ON(1); - } - B43_WARN_ON(1); - } - } - return 0; -} - -struct init2050_saved_values { - /* Core registers */ - u16 reg_3EC; - u16 reg_3E6; - u16 reg_3F4; - /* Radio registers */ - u16 radio_43; - u16 radio_51; - u16 radio_52; - /* PHY registers */ - u16 phy_pgactl; - u16 phy_cck_5A; - u16 phy_cck_59; - u16 phy_cck_58; - u16 phy_cck_30; - u16 phy_rfover; - u16 phy_rfoverval; - u16 phy_analogover; - u16 phy_analogoverval; - u16 phy_crs0; - u16 phy_classctl; - u16 phy_lo_mask; - u16 phy_lo_ctl; - u16 phy_syncctl; -}; - -u16 b43_radio_init2050(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - struct init2050_saved_values sav; - u16 rcc; - u16 radio78; - u16 ret; - u16 i, j; - u32 tmp1 = 0, tmp2 = 0; - - memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ - - sav.radio_43 = b43_radio_read16(dev, 0x43); - sav.radio_51 = b43_radio_read16(dev, 0x51); - sav.radio_52 = b43_radio_read16(dev, 0x52); - sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); - sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); - sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); + } + b43_shm_clear_tssi(dev); - if (phy->type == B43_PHYTYPE_B) { - sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); - sav.reg_3EC = b43_read16(dev, 0x3EC); + average = (v0 + v1 + v2 + v3 + 2) / 4; - b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); - b43_write16(dev, 0x3EC, 0x3F3F); - } else if (phy->gmode || phy->rev >= 2) { - sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); - sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); - sav.phy_analogoverval = - b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); - sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); - sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + if (tmp + && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & + 0x8)) + average -= 13; - b43_phy_write(dev, B43_PHY_ANALOGOVER, - b43_phy_read(dev, B43_PHY_ANALOGOVER) - | 0x0003); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) - & 0xFFFC); - b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) - & 0x7FFF); - b43_phy_write(dev, B43_PHY_CLASSCTL, - b43_phy_read(dev, B43_PHY_CLASSCTL) - & 0xFFFC); - if (has_loopback_gain(phy)) { - sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); - sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + estimated_pwr = + b43_phy_estimate_power_out(dev, average); - if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); - else - b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); - b43_phy_write(dev, B43_PHY_LO_CTL, 0); - } + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 1, 1))); - b43_phy_write(dev, B43_PHY_RFOVER, - radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); - } - b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ - sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); - b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) - & 0xFF7F); - sav.reg_3E6 = b43_read16(dev, 0x3E6); - sav.reg_3F4 = b43_read16(dev, 0x3F4); + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } - if (phy->analog == 0) { - b43_write16(dev, 0x03E6, 0x0122); - } else { - if (phy->analog >= 2) { - b43_phy_write(dev, B43_PHY_CCK(0x03), - (b43_phy_read(dev, B43_PHY_CCK(0x03)) - & 0xFFBF) | 0x40); - } - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); - } + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; - rcc = b43_radio_core_calibration_value(dev); + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; - if (phy->type == B43_PHYTYPE_B) - b43_radio_write16(dev, 0x78, 0x26); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 1, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); - b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, - LPD(0, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); - b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) - | 0x0004); - if (phy->radio_rev == 8) { - b43_radio_write16(dev, 0x43, 0x1F); - } else { - b43_radio_write16(dev, 0x52, 0); - b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) - & 0xFFF0) | 0x0009); - } - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; - for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 0))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); - udelay(20); - tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - } - udelay(10); + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + return; - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - tmp1++; - tmp1 >>= 9; + /* Calculate the new attenuation values. */ + bbatt = phy->bbatt.att; + bbatt += bbatt_delta; + rfatt = phy->rfatt.att; + rfatt += rfatt_delta; - for (i = 0; i < 16; i++) { - radio78 = (bitrev4(i) << 1) | 0x0020; - b43_radio_write16(dev, 0x78, radio78); - udelay(10); - for (j = 0; j < 16; j++) { - b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); - b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); - udelay(10); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 0))); - } - b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); - udelay(10); - tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_CCK(0x58), 0); - if (phy->gmode || phy->rev >= 2) { - b43_phy_write(dev, B43_PHY_RFOVERVAL, - radio2050_rfover_val(dev, - B43_PHY_RFOVERVAL, - LPD(1, 0, - 1))); + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = phy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } } - b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); - } - tmp2++; - tmp2 >>= 8; - if (tmp1 < tmp2) - break; - } + /* Save the control values */ + phy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + phy->rfatt.att = rfatt; + phy->bbatt.att = bbatt; - /* Restore the registers */ - b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); - b43_radio_write16(dev, 0x51, sav.radio_51); - b43_radio_write16(dev, 0x52, sav.radio_52); - b43_radio_write16(dev, 0x43, sav.radio_43); - b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); - b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); - b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); - b43_write16(dev, 0x3E6, sav.reg_3E6); - if (phy->analog != 0) - b43_write16(dev, 0x3F4, sav.reg_3F4); - b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); - b43_synth_pu_workaround(dev, phy->channel); - if (phy->type == B43_PHYTYPE_B) { - b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); - b43_write16(dev, 0x3EC, sav.reg_3EC); - } else if (phy->gmode) { - b43_write16(dev, B43_MMIO_PHY_RADIO, - b43_read16(dev, B43_MMIO_PHY_RADIO) - & 0x7FFF); - b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); - b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); - b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); - b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, - sav.phy_analogoverval); - b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); - b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); - if (has_loopback_gain(phy)) { - b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); - b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + /* Adjust the hardware */ + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, + phy->tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev); + break; } + case B43_PHYTYPE_N: + b43_nphy_xmitpower(dev); + break; + default: + B43_WARN_ON(1); } - if (i > 15) - ret = radio78; - else - ret = rcc; - - return ret; } -void b43_radio_init2060(struct b43_wldev *dev) +static inline s32 b43_tssi2dbm_ad(s32 num, s32 den) { - int err; - - b43_radio_write16(dev, 0x0004, 0x00C0); - b43_radio_write16(dev, 0x0005, 0x0008); - b43_radio_write16(dev, 0x0009, 0x0040); - b43_radio_write16(dev, 0x0005, 0x00AA); - b43_radio_write16(dev, 0x0032, 0x008F); - b43_radio_write16(dev, 0x0006, 0x008F); - b43_radio_write16(dev, 0x0034, 0x008F); - b43_radio_write16(dev, 0x002C, 0x0007); - b43_radio_write16(dev, 0x0082, 0x0080); - b43_radio_write16(dev, 0x0080, 0x0000); - b43_radio_write16(dev, 0x003F, 0x00DA); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); - msleep(1); /* delay 400usec */ - - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); - b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); - b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); - b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); - b43_radio_write16(dev, 0x0081, - (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); - b43_radio_write16(dev, 0x0005, - (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); - b43_phy_write(dev, 0x0063, 0xDDC6); - b43_phy_write(dev, 0x0069, 0x07BE); - b43_phy_write(dev, 0x006A, 0x0000); - - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0); - B43_WARN_ON(err); - - msleep(1); + if (num < 0) + return num / den; + else + return (num + den / 2) / den; } -static inline u16 freq_r3A_value(u16 frequency) +static inline + s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2) { - u16 value; - - if (frequency < 5091) - value = 0x0040; - else if (frequency < 5321) - value = 0x0000; - else if (frequency < 5806) - value = 0x0080; - else - value = 0x0040; + s32 m1, m2, f = 256, q, delta; + s8 i = 0; - return value; + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; } -void b43_radio_set_tx_iq(struct b43_wldev *dev) +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) { - static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; - static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; - u16 tmp = b43_radio_read16(dev, 0x001E); - int i, j; + struct b43_phy *phy = &dev->phy; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; - for (i = 0; i < 5; i++) { - for (j = 0; j < 5; j++) { - if (tmp == (data_high[i] << 4 | data_low[j])) { - b43_phy_write(dev, 0x0069, - (i - j) << 8 | 0x00C0); - return; - } - } + if (phy->type == B43_PHYTYPE_A) { + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); + } else { + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); } -} -int b43_radio_selectchannel(struct b43_wldev *dev, - u8 channel, int synthetic_pu_workaround) -{ - struct b43_phy *phy = &dev->phy; - u16 r8, tmp; - u16 freq; - u16 channelcookie, savedcookie; - int err = 0; + if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; + return 0; + } - if (channel == 0xFF) { + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == B43_PHYTYPE_A) { + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_a); + else + phy->tgt_idle_tssi = 62; + } else { + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) + phy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_bg); + else + phy->tgt_idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + b43err(dev->wl, "Could not allocate memory " + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (b43_tssi2dbm_entry + (dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(dyn_tssi2dbm); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ switch (phy->type) { case B43_PHYTYPE_A: - channel = B43_DEFAULT_CHANNEL_A; - break; + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + b43err(dev->wl, "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; case B43_PHYTYPE_B: - case B43_PHYTYPE_G: - channel = B43_DEFAULT_CHANNEL_BG; + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_b_table; break; - case B43_PHYTYPE_N: - //FIXME check if we are on 2.4GHz or 5GHz and set a default channel. - channel = 1; + case B43_PHYTYPE_G: + phy->tgt_idle_tssi = 0x34; + phy->tssi2dbm = b43_tssi2dbm_g_table; break; - default: - B43_WARN_ON(1); - } - } - - /* First we set the channel radio code to prevent the - * firmware from sending ghost packets. - */ - channelcookie = channel; - if (0 /*FIXME on 5Ghz */) - channelcookie |= 0x100; - //FIXME set 40Mhz flag if required - savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); - b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); - - switch (phy->type) { - case B43_PHYTYPE_A: - if (channel > 200) { - err = -EINVAL; - goto out; - } - freq = channel2freq_a(channel); - - r8 = b43_radio_read16(dev, 0x0008); - b43_write16(dev, 0x03F0, freq); - b43_radio_write16(dev, 0x0008, r8); - - //TODO: write max channel TX power? to Radio 0x2D - tmp = b43_radio_read16(dev, 0x002E); - tmp &= 0x0080; - //TODO: OR tmp with the Power out estimation for this channel? - b43_radio_write16(dev, 0x002E, tmp); - - if (freq >= 4920 && freq <= 5500) { - /* - * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; - * = (freq * 0.025862069 - */ - r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ - } - b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); - b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) - & 0x000F) | (r8 << 4)); - b43_radio_write16(dev, 0x002A, (r8 << 4)); - b43_radio_write16(dev, 0x002B, (r8 << 4)); - b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) - & 0x00F0) | (r8 << 4)); - b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) - & 0xFF0F) | 0x00B0); - b43_radio_write16(dev, 0x0035, 0x00AA); - b43_radio_write16(dev, 0x0036, 0x0085); - b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) - & 0xFF20) | - freq_r3A_value(freq)); - b43_radio_write16(dev, 0x003D, - b43_radio_read16(dev, 0x003D) & 0x00FF); - b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) - & 0xFF7F) | 0x0080); - b43_radio_write16(dev, 0x0035, - b43_radio_read16(dev, 0x0035) & 0xFFEF); - b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) - & 0xFFEF) | 0x0010); - b43_radio_set_tx_iq(dev); - //TODO: TSSI2dbm workaround - b43_phy_xmitpower(dev); //FIXME correct? - break; - case B43_PHYTYPE_G: - if ((channel < 1) || (channel > 14)) { - err = -EINVAL; - goto out; } - - if (synthetic_pu_workaround) - b43_synth_pu_workaround(dev, channel); - - b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); - - if (channel == 14) { - if (dev->dev->bus->sprom.country_code == - SSB_SPROM1CCODE_JAPAN) - b43_hf_write(dev, - b43_hf_read(dev) & ~B43_HF_ACPR); - else - b43_hf_write(dev, - b43_hf_read(dev) | B43_HF_ACPR); - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - | (1 << 11)); - } else { - b43_write16(dev, B43_MMIO_CHANNEL_EXT, - b43_read16(dev, B43_MMIO_CHANNEL_EXT) - & 0xF7BF); - } - break; - case B43_PHYTYPE_N: - err = b43_nphy_selectchannel(dev, channel); - if (err) - goto out; - break; - default: - B43_WARN_ON(1); } - phy->channel = channel; - /* Wait for the radio to tune to the channel and stabilize. */ - msleep(8); -out: - if (err) { - b43_shm_write16(dev, B43_SHM_SHARED, - B43_SHM_SH_CHAN, savedcookie); - } - return err; + return 0; } void b43_radio_turn_on(struct b43_wldev *dev) @@ -3843,21 +450,7 @@ void b43_radio_turn_on(struct b43_wldev *dev) break; case B43_PHYTYPE_B: case B43_PHYTYPE_G: - b43_phy_write(dev, 0x0015, 0x8000); - b43_phy_write(dev, 0x0015, 0xCC00); - b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); - if (phy->radio_off_context.valid) { - /* Restore the RFover values. */ - b43_phy_write(dev, B43_PHY_RFOVER, - phy->radio_off_context.rfover); - b43_phy_write(dev, B43_PHY_RFOVERVAL, - phy->radio_off_context.rfoverval); - phy->radio_off_context.valid = 0; - } - channel = phy->channel; - err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1); - err |= b43_radio_selectchannel(dev, channel, 0); - B43_WARN_ON(err); + //XXX break; case B43_PHYTYPE_N: b43_nphy_radio_turn_on(dev); @@ -3886,17 +479,7 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); break; case B43_PHYTYPE_G: { - u16 rfover, rfoverval; - - rfover = b43_phy_read(dev, B43_PHY_RFOVER); - rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); - if (!force) { - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; - } - b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); - b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); + //XXX break; } default: diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h deleted file mode 100644 index 4aab109..0000000 --- a/drivers/net/wireless/b43/phy.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef B43_PHY_H_ -#define B43_PHY_H_ - -#include - -struct b43_wldev; -struct b43_phy; - -/*** PHY Registers ***/ - -/* Routing */ -#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ -#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ -#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ -#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ -#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ - -/* CCK (B-PHY) registers. */ -#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY registers. */ -#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) -/* N-PHY BMODE registers. */ -#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) -/* OFDM (A-PHY) registers. */ -#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) -/* Extended G-PHY registers. */ -#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) - -/* OFDM (A) PHY Registers */ -#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ -#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ -#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ -#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 -#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ -#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ -#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ -#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ -#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ -#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) -#define B43_PHY_CRS0_EN 0x4000 -#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) -#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ -#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ -#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ -#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ -#define B43_PHY_LMS B43_PHY_OFDM(0x55) -#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ -#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ -#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ -#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ -#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ -#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ -#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ -#define B43_PHY_OTABLENR_SHIFT 10 -#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ -#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ -#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ -#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ -#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) -#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ -#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ -#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ -#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ -#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ -#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ -#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) -#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) -#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) -#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) -#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) -#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ -#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ -#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ -#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) -#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) -#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) -#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ -#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ -#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ -#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ -#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ -#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ -#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ - -/* CCK (B) PHY Registers */ -#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ -#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ -#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ -#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ -#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ -#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 -#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ -#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ -#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ -#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ -#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) -#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ -#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ -#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ - -/* Extended G-PHY Registers */ -#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ -#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ -#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ -#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ -#define B43_PHY_GTABNR_SHIFT 10 -#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ -#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ -#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ -#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ -#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ -#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 -#define B43_PHY_RFOVERVAL_LNA 0x7000 -#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 -#define B43_PHY_RFOVERVAL_PGA 0x0F00 -#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 -#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ -#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 -#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ -#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ -#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ -#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ -#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ - -/*** OFDM table numbers ***/ -#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) -#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) -#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename -#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) -#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) -#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) -#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) -#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) -#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) -#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) -#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) -#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) -#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) -#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) -#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) -#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) -#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename -#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename -#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) -#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) -#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename -#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) -#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! -#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) -#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) -#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) -#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) -#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) -#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) - -u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, - u16 offset, u16 value); -u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); -void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, - u16 offset, u32 value); - -/*** G-PHY table numbers */ -#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) -#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) -#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) -#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) - -u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement -void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement - -#define B43_DEFAULT_CHANNEL_A 36 -#define B43_DEFAULT_CHANNEL_BG 6 - -enum { - B43_ANTENNA0, /* Antenna 0 */ - B43_ANTENNA1, /* Antenna 0 */ - B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ - B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ - B43_ANTENNA2, - B43_ANTENNA3 = 8, - - B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, - B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, -}; - -enum { - B43_INTERFMODE_NONE, - B43_INTERFMODE_NONWLAN, - B43_INTERFMODE_MANUALWLAN, - B43_INTERFMODE_AUTOWLAN, -}; - -/* Masks for the different PHY versioning registers. */ -#define B43_PHYVER_ANALOG 0xF000 -#define B43_PHYVER_ANALOG_SHIFT 12 -#define B43_PHYVER_TYPE 0x0F00 -#define B43_PHYVER_TYPE_SHIFT 8 -#define B43_PHYVER_VERSION 0x00FF - -void b43_phy_lock(struct b43_wldev *dev); -void b43_phy_unlock(struct b43_wldev *dev); - - -/* Read a value from a PHY register */ -u16 b43_phy_read(struct b43_wldev *dev, u16 offset); -/* Write a value to a PHY register */ -void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a PHY register with a mask */ -void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a PHY register with a bitmap */ -void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); - -void b43_phy_early_init(struct b43_wldev *dev); -int b43_phy_init(struct b43_wldev *dev); - -void b43_set_rx_antenna(struct b43_wldev *dev, int antenna); - -void b43_phy_xmitpower(struct b43_wldev *dev); - -/* Returns the boolean whether the board has HardwarePowerControl */ -bool b43_has_hardware_pctl(struct b43_phy *phy); -/* Returns the boolean whether "TX Magnification" is enabled. */ -#define has_tx_magnification(phy) \ - (((phy)->rev >= 2) && \ - ((phy)->radio_ver == 0x2050) && \ - ((phy)->radio_rev == 8)) -/* Card uses the loopback gain stuff */ -#define has_loopback_gain(phy) \ - (((phy)->rev > 1) || ((phy)->gmode)) - -/* Radio Attenuation (RF Attenuation) */ -struct b43_rfatt { - u8 att; /* Attenuation value */ - bool with_padmix; /* Flag, PAD Mixer enabled. */ -}; -struct b43_rfatt_list { - /* Attenuation values list */ - const struct b43_rfatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_rfatt(const struct b43_rfatt *a, - const struct b43_rfatt *b) -{ - return ((a->att == b->att) && - (a->with_padmix == b->with_padmix)); -} - -/* Baseband Attenuation */ -struct b43_bbatt { - u8 att; /* Attenuation value */ -}; -struct b43_bbatt_list { - /* Attenuation values list */ - const struct b43_bbatt *list; - u8 len; - /* Minimum/Maximum attenuation values */ - u8 min_val; - u8 max_val; -}; - -/* Returns true, if the values are the same. */ -static inline bool b43_compare_bbatt(const struct b43_bbatt *a, - const struct b43_bbatt *b) -{ - return (a->att == b->att); -} - -/* tx_control bits. */ -#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ -#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ -#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ - -/* Write BasebandAttenuation value to the device. */ -void b43_phy_set_baseband_attenuation(struct b43_wldev *dev, - u16 baseband_attenuation); - -extern const u8 b43_radio_channel_codes_bg[]; - -void b43_radio_lock(struct b43_wldev *dev); -void b43_radio_unlock(struct b43_wldev *dev); - - -/* Read a value from a 16bit radio register */ -u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); -/* Write a value to a 16bit radio register */ -void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); -/* Mask a 16bit radio register with a mask */ -void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); -/* OR a 16bit radio register with a bitmap */ -void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); -/* Mask and OR a PHY register with a mask and bitmap */ -void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); - - -u16 b43_radio_init2050(struct b43_wldev *dev); -void b43_radio_init2060(struct b43_wldev *dev); - -void b43_radio_turn_on(struct b43_wldev *dev); -void b43_radio_turn_off(struct b43_wldev *dev, bool force); - -int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel, - int synthetic_pu_workaround); - -u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel); -u8 b43_radio_aci_scan(struct b43_wldev *dev); - -int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode); - -void b43_calc_nrssi_slope(struct b43_wldev *dev); -void b43_calc_nrssi_threshold(struct b43_wldev *dev); -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset); -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val); -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val); -void b43_nrssi_mem_update(struct b43_wldev *dev); - -void b43_radio_set_tx_iq(struct b43_wldev *dev); -u16 b43_radio_calibrationvalue(struct b43_wldev *dev); - -void b43_put_attenuation_into_ranges(struct b43_wldev *dev, - int *_bbatt, int *_rfatt); - -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control); - -#endif /* B43_PHY_H_ */ diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c new file mode 100644 index 0000000..dd34731 --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.c @@ -0,0 +1,536 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11a PHY driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_a.h" +#include "phy_common.h" +#include "wa.h" +#include "tables.h" +#include "main.h" + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_a(u8 channel) +{ + B43_WARN_ON(channel > 200); + + return (5000 + 5 * channel); +} + +static inline u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void b43_radio_set_tx_iq(struct b43_wldev *dev) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = b43_radio_read16(dev, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + b43_phy_write(dev, 0x0069, + (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) +{ + u16 freq, r8, tmp; + + freq = channel2freq_a(channel); + + r8 = b43_radio_read16(dev, 0x0008); + b43_write16(dev, 0x03F0, freq); + b43_radio_write16(dev, 0x0008, r8); + + //TODO: write max channel TX power? to Radio 0x2D + tmp = b43_radio_read16(dev, 0x002E); + tmp &= 0x0080; + //TODO: OR tmp with the Power out estimation for this channel? + b43_radio_write16(dev, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); + b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) + & 0x000F) | (r8 << 4)); + b43_radio_write16(dev, 0x002A, (r8 << 4)); + b43_radio_write16(dev, 0x002B, (r8 << 4)); + b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) + & 0x00F0) | (r8 << 4)); + b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) + & 0xFF0F) | 0x00B0); + b43_radio_write16(dev, 0x0035, 0x00AA); + b43_radio_write16(dev, 0x0036, 0x0085); + b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) + & 0xFF20) | + freq_r3A_value(freq)); + b43_radio_write16(dev, 0x003D, + b43_radio_read16(dev, 0x003D) & 0x00FF); + b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) + & 0xFF7F) | 0x0080); + b43_radio_write16(dev, 0x0035, + b43_radio_read16(dev, 0x0035) & 0xFFEF); + b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) + & 0xFFEF) | 0x0010); + b43_radio_set_tx_iq(dev); + //TODO: TSSI2dbm workaround +//FIXME b43_phy_xmitpower(dev); +} + +void b43_radio_init2060(struct b43_wldev *dev) +{ + b43_radio_write16(dev, 0x0004, 0x00C0); + b43_radio_write16(dev, 0x0005, 0x0008); + b43_radio_write16(dev, 0x0009, 0x0040); + b43_radio_write16(dev, 0x0005, 0x00AA); + b43_radio_write16(dev, 0x0032, 0x008F); + b43_radio_write16(dev, 0x0006, 0x008F); + b43_radio_write16(dev, 0x0034, 0x008F); + b43_radio_write16(dev, 0x002C, 0x0007); + b43_radio_write16(dev, 0x0082, 0x0080); + b43_radio_write16(dev, 0x0080, 0x0000); + b43_radio_write16(dev, 0x003F, 0x00DA); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); + msleep(1); /* delay 400usec */ + + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); + b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); + b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); + b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); + b43_radio_write16(dev, 0x0081, + (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); + b43_radio_write16(dev, 0x0005, + (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); + b43_phy_write(dev, 0x0063, 0xDDC6); + b43_phy_write(dev, 0x0069, 0x07BE); + b43_phy_write(dev, 0x006A, 0x0000); + + aphy_channel_switch(dev, dev->phy.ops->get_default_chan(dev)); + + msleep(1); +} + +static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) +{ + int i; + + if (dev->phy.rev < 3) { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0xFFF8); + } + else + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); + } + } else { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0x0820); + else + for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); + } +} + +static void b43_phy_ww(struct b43_wldev *dev) +{ + u16 b, curr_s, best_s = 0xFFFF; + int i; + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x0009, + b43_radio_read16(dev, 0x0009) | 0x0080); + b43_radio_write16(dev, 0x0012, + (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); + b43_wa_initgains(dev); + b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); + b = b43_phy_read(dev, B43_PHY_PWRDOWN); + b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) | 0x0004); + for (i = 0x10; i <= 0x20; i++) { + b43_radio_write16(dev, 0x0013, i); + curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; + if (!curr_s) { + best_s = 0x0000; + break; + } else if (curr_s >= 0x0080) + curr_s = 0x0100 - curr_s; + if (curr_s < best_s) + best_s = curr_s; + } + b43_phy_write(dev, B43_PHY_PWRDOWN, b); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) & 0xFFFB); + b43_radio_write16(dev, 0x0013, best_s); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); + b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); + b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); + b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); + b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); + b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); + b43_phy_write(dev, B43_PHY_OFDM(0xBB), + (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); + b43_phy_write(dev, B43_PHY_OFDM61, + (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); + b43_phy_write(dev, B43_PHY_OFDM(0x13), + (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); + b43_phy_write(dev, B43_PHY_OFDM(0x14), + (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); + for (i = 0; i < 6; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); + b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); +} + +static void hardware_pctl_init_aphy(struct b43_wldev *dev) +{ + //TODO +} + +void b43_phy_inita(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + /* This lowlevel A-PHY init is also called from G-PHY init. + * So we must not access phy->a, if called from G-PHY code. + */ + B43_WARN_ON((phy->type != B43_PHYTYPE_A) && + (phy->type != B43_PHYTYPE_G)); + + might_sleep(); + + if (phy->rev >= 6) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); + else + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); + } + + b43_wa_all(dev); + + if (phy->type == B43_PHYTYPE_A) { + if (phy->gmode && (phy->rev < 3)) + b43_phy_write(dev, 0x0034, + b43_phy_read(dev, 0x0034) | 0x0001); + b43_phy_rssiagc(dev, 0); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); + + b43_radio_init2060(dev); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + ; //TODO: A PHY LO + } + + if (phy->rev >= 3) + b43_phy_ww(dev); + + hardware_pctl_init_aphy(dev); + + //TODO: radar detection + } + + if ((phy->type == B43_PHYTYPE_G) && + (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + b43_phy_write(dev, B43_PHY_OFDM(0x6E), + (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) + & 0xE000) | 0x3CF); + } +} + +static int b43_aphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy; + + aphy = kzalloc(sizeof(*aphy), GFP_KERNEL); + if (!aphy) + return -ENOMEM; + dev->phy.a = aphy; + + //TODO init struct b43_phy_a + + return 0; +} + +static int b43_aphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy = dev->phy.a; + + b43_phy_inita(dev); + aphy->initialised = 1; + + return 0; +} + +static void b43_aphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_a *aphy = dev->phy.a; + + if (aphy->initialised) { + //TODO + aphy->initialised = 0; + } + //TODO + kfree(aphy); + dev->phy.a = NULL; +} + +static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset) +{ + /* OFDM registers are base-registers for the A-PHY. */ + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + offset &= ~B43_PHYROUTE; + offset |= B43_PHYROUTE_BASE; + } + +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { + /* Ext-G registers are only available on G-PHYs */ + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { + /* N-BMODE registers are only available on N-PHYs */ + b43err(dev->wl, "Invalid N-BMODE PHY access at " + "0x%04X on A-PHY\n", offset); + dump_stack(); + } +#endif /* B43_DEBUG */ + + return offset; +} + +static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + reg = adjust_phyreg(dev, reg); + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_aphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* A-PHY needs 0x40 for read access */ + reg |= 0x40; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_aphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 5); +} + +static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{//TODO +} + +static int b43_aphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if (new_channel > 200) + return -EINVAL; + aphy_channel_switch(dev, new_channel); + + return 0; +} + +static unsigned int b43_aphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 36; /* Default to channel 36 */ +} + +static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{//TODO + struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + if (phy->rev < 3) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + tmp = (tmp & 0xFF00) | 0x24; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } else { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= 0x10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + if (phy->analog == 3) { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x1D); + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT, + 0x3A); + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +static void b43_aphy_op_xmitpower(struct b43_wldev *dev) +{//TODO +} + +static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) +{//TODO +} + +static void b43_aphy_op_pwork_60sec(struct b43_wldev *dev) +{//TODO +} + +const struct b43_phy_operations b43_phyops_a = { + .allocate = b43_aphy_op_allocate, + .init = b43_aphy_op_init, + .exit = b43_aphy_op_exit, + .phy_read = b43_aphy_op_read, + .phy_write = b43_aphy_op_write, + .radio_read = b43_aphy_op_radio_read, + .radio_write = b43_aphy_op_radio_write, + .supports_hwpctl = b43_aphy_op_supports_hwpctl, + .software_rfkill = b43_aphy_op_software_rfkill, + .switch_channel = b43_aphy_op_switch_channel, + .get_default_chan = b43_aphy_op_get_default_chan, + .set_rx_antenna = b43_aphy_op_set_rx_antenna, + .xmitpower = b43_aphy_op_xmitpower, + .pwork_15sec = b43_aphy_op_pwork_15sec, + .pwork_60sec = b43_aphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_a.h b/drivers/net/wireless/b43/phy_a.h new file mode 100644 index 0000000..e8640f7 --- /dev/null +++ b/drivers/net/wireless/b43/phy_a.h @@ -0,0 +1,124 @@ +#ifndef LINUX_B43_PHY_A_H_ +#define LINUX_B43_PHY_A_H_ + +#include "phy_common.h" + + +/* OFDM (A) PHY Registers */ +#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */ +#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */ +#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ +#define B43_PHY_BBANDCFG_RXANT_SHIFT 7 +#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ +#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ +#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ +#define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_CRS0_EN 0x4000 +#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) +#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ +#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ +#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ +#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */ +#define B43_PHY_LMS B43_PHY_OFDM(0x55) +#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ +#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ +#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ +#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ +#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ +#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ +#define B43_PHY_OTABLENR_SHIFT 10 +#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ +#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ +#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ +#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) +#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ +#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ +#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ +#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ +#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */ +#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */ +#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0) +#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1) +#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) +#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) +#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ +#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ +#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ +#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) +#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) +#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) +#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ +#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ +#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ +#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ +#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ +#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ + +/*** OFDM table numbers ***/ +#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset)) +#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0) +#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename +#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4) +#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0) +#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3) +#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0) +#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0) +#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0) +#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0) +#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0) +#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0) +#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0) +#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) +#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) +#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) +#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename +#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename +#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) +#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) +#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename +#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) +#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) +#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) +#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0) +#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0) +#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0) + +u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, + u16 offset, u16 value); +u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset); +void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, + u16 offset, u32 value); + + +struct b43_phy_a { + bool initialised; + + /* A-PHY TX Power control value. */ + u16 txpwr_offset; + + //TODO lots of missing stuff +}; + +/** + * b43_phy_inita - Lowlevel A-PHY init routine. + * This is _only_ used by the G-PHY code. + */ +void b43_phy_inita(struct b43_wldev *dev); + + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_a; + +#endif /* LINUX_B43_PHY_A_H_ */ diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c new file mode 100644 index 0000000..45074c0 --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.c @@ -0,0 +1,276 @@ +/* + + Broadcom B43 wireless driver + Common PHY routines + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "phy_common.h" +#include "phy_g.h" +#include "phy_a.h" +#include "nphy.h" +#include "b43.h" +#include "main.h" + + +int b43_phy_operations_setup(struct b43_wldev *dev) +{ + struct b43_phy *phy = &(dev->phy); + int err; + + phy->ops = NULL; + + switch (phy->type) { + case B43_PHYTYPE_A: + phy->ops = &b43_phyops_a; + break; + case B43_PHYTYPE_G: + phy->ops = &b43_phyops_g; + break; + case B43_PHYTYPE_N: +#ifdef CONFIG_B43_NPHY + phy->ops = &b43_phyops_n; +#endif + break; + case B43_PHYTYPE_LP: + /* FIXME: Not yet */ + break; + } + if (B43_WARN_ON(!phy->ops)) + return -ENODEV; + + err = phy->ops->allocate(dev); + if (err) + phy->ops = NULL; + + return err; +} + +int b43_phy_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + const struct b43_phy_operations *ops = phy->ops; + int err; + + phy->channel = ops->get_default_chan(dev); + + ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); + err = ops->init(dev); + if (err) { + b43err(dev->wl, "PHY init failed\n"); + goto err_block_rf; + } + /* Make sure to switch hardware and firmware (SHM) to + * the default channel. */ + err = b43_switch_channel(dev, ops->get_default_chan(dev)); + if (err) { + b43err(dev->wl, "PHY init: Channel switch to default failed\n"); + goto err_phy_exit; + } + + return 0; + +err_phy_exit: + if (ops->exit) + ops->exit(dev); +err_block_rf: + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + + return err; +} + +void b43_phy_exit(struct b43_wldev *dev) +{ + const struct b43_phy_operations *ops = dev->phy.ops; + + ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); + if (ops->exit) + ops->exit(dev); +} + +bool b43_has_hardware_pctl(struct b43_wldev *dev) +{ + if (!dev->phy.hardware_power_control) + return 0; + if (!dev->phy.ops->supports_hwpctl) + return 0; + return dev->phy.ops->supports_hwpctl(dev); +} + +void b43_radio_lock(struct b43_wldev *dev) +{ + u32 macctl; + + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); + macctl |= B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Commit the write and wait for the device + * to exit any radio register access. */ + b43_read32(dev, B43_MMIO_MACCTL); + udelay(10); +} + +void b43_radio_unlock(struct b43_wldev *dev) +{ + u32 macctl; + + /* Commit any write */ + b43_read16(dev, B43_MMIO_PHY_VER); + /* unlock */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); + macctl &= ~B43_MACCTL_RADIOLOCK; + b43_write32(dev, B43_MMIO_MACCTL, macctl); +} + +void b43_phy_lock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); +} + +void b43_phy_unlock(struct b43_wldev *dev) +{ +#if B43_DEBUG + B43_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); + + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); +} + +u16 b43_radio_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->radio_read(dev, reg); +} + +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->radio_write(dev, reg, value); +} + +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) & mask); +} + +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) | set); +} + +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_radio_write16(dev, offset, + (b43_radio_read16(dev, offset) & mask) | set); +} + +u16 b43_phy_read(struct b43_wldev *dev, u16 reg) +{ + return dev->phy.ops->phy_read(dev, reg); +} + +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + dev->phy.ops->phy_write(dev, reg, value); +} + +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); +} + +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); +} + +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); +} + +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) +{ + struct b43_phy *phy = &(dev->phy); + u16 channelcookie, savedcookie; + int err; + + if (new_channel == B43_DEFAULT_CHANNEL) + new_channel = phy->ops->get_default_chan(dev); + + /* First we set the channel radio code to prevent the + * firmware from sending ghost packets. + */ + channelcookie = new_channel; + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + channelcookie |= 0x100; + //FIXME set 40Mhz flag if required + savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); + + /* Now try to switch the PHY hardware channel. */ + err = phy->ops->switch_channel(dev, new_channel); + if (err) + goto err_restore_cookie; + + dev->phy.channel = new_channel; + /* Wait for the radio to tune to the channel and stabilize. */ + msleep(8); + + return 0; + +err_restore_cookie: + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_CHAN, savedcookie); + + return err; +} + +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + + if (state == RFKILL_STATE_HARD_BLOCKED) { + /* We cannot hardware-block the device */ + state = RFKILL_STATE_SOFT_BLOCKED; + } + + phy->ops->software_rfkill(dev, state); + phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h new file mode 100644 index 0000000..9b9635e --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.h @@ -0,0 +1,312 @@ +#ifndef LINUX_B43_PHY_COMMON_H_ +#define LINUX_B43_PHY_COMMON_H_ + +#include + +struct b43_wldev; + + +/* PHY register routing bits */ +#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ +#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ +#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ +#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ +#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ + +/* CCK (B-PHY) registers. */ +#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY registers. */ +#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY BMODE registers. */ +#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) +/* OFDM (A-PHY) registers. */ +#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) +/* Extended G-PHY registers. */ +#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) + + +/* Masks for the PHY versioning registers. */ +#define B43_PHYVER_ANALOG 0xF000 +#define B43_PHYVER_ANALOG_SHIFT 12 +#define B43_PHYVER_TYPE 0x0F00 +#define B43_PHYVER_TYPE_SHIFT 8 +#define B43_PHYVER_VERSION 0x00FF + +/** + * enum b43_interference_mitigation - Interference Mitigation mode + * + * @B43_INTERFMODE_NONE: Disabled + * @B43_INTERFMODE_NONWLAN: Non-WLAN Interference Mitigation + * @B43_INTERFMODE_MANUALWLAN: WLAN Interference Mitigation + * @B43_INTERFMODE_AUTOWLAN: Automatic WLAN Interference Mitigation + */ +enum b43_interference_mitigation { + B43_INTERFMODE_NONE, + B43_INTERFMODE_NONWLAN, + B43_INTERFMODE_MANUALWLAN, + B43_INTERFMODE_AUTOWLAN, +}; + +/* Antenna identifiers */ +enum { + B43_ANTENNA0, /* Antenna 0 */ + B43_ANTENNA1, /* Antenna 0 */ + B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ + B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + B43_ANTENNA2, + B43_ANTENNA3 = 8, + + B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, + B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, +}; + +/** + * struct b43_phy_operations - Function pointers for PHY ops. + * + * @prepare: Prepare the PHY. This is called before @init. + * Can be NULL, if not required. + * @init: Initialize the PHY. + * Must not be NULL. + * @exit: Shutdown the PHY and free all data structures. + * Can be NULL, if not required. + * + * @phy_read: Read from a PHY register. + * Must not be NULL. + * @phy_write: Write to a PHY register. + * Must not be NULL. + * @radio_read: Read from a Radio register. + * Must not be NULL. + * @radio_write: Write to a Radio register. + * Must not be NULL. + * + * @supports_hwpctl: Returns a boolean whether Hardware Power Control + * is supported or not. + * If NULL, hwpctl is assumed to be never supported. + * @software_rfkill: Turn the radio ON or OFF. + * Possible state values are + * RFKILL_STATE_SOFT_BLOCKED or + * RFKILL_STATE_UNBLOCKED + * Must not be NULL. + * @switch_channel: Switch the radio to another channel. + * Must not be NULL. + * @get_default_chan: Just returns the default channel number. + * Must not be NULL. + * @set_rx_antenna: Set the antenna used for RX. + * Can be NULL, if not supported. + * @interf_mitigation: Switch the Interference Mitigation mode. + * Can be NULL, if not supported. + * + * @xmitpower: FIXME REMOVEME + * Must not be NULL. + * + * @pwork_15sec: Periodic work. Called every 15 seconds. + * Can be NULL, if not required. + * @pwork_60sec: Periodic work. Called every 60 seconds. + * Can be NULL, if not required. + */ +struct b43_phy_operations { + /* Initialisation */ + int (*allocate)(struct b43_wldev *dev); + int (*prepare)(struct b43_wldev *dev); + int (*init)(struct b43_wldev *dev); + void (*exit)(struct b43_wldev *dev); + + /* Register access */ + u16 (*phy_read)(struct b43_wldev *dev, u16 reg); + void (*phy_write)(struct b43_wldev *dev, u16 reg, u16 value); + u16 (*radio_read)(struct b43_wldev *dev, u16 reg); + void (*radio_write)(struct b43_wldev *dev, u16 reg, u16 value); + + /* Radio */ + bool (*supports_hwpctl)(struct b43_wldev *dev); + void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state); + int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel); + unsigned int (*get_default_chan)(struct b43_wldev *dev); + void (*set_rx_antenna)(struct b43_wldev *dev, int antenna); + int (*interf_mitigation)(struct b43_wldev *dev, + enum b43_interference_mitigation new_mode); + + /* Transmission power adjustment */ + void (*xmitpower)(struct b43_wldev *dev); + + /* Misc */ + void (*pwork_15sec)(struct b43_wldev *dev); + void (*pwork_60sec)(struct b43_wldev *dev); +}; + +struct b43_phy_a; +struct b43_phy_g; +struct b43_phy_n; + +struct b43_phy { + /* Hardware operation callbacks. */ + const struct b43_phy_operations *ops; + + /* Most hardware context information is stored in the standard- + * specific data structures pointed to by the pointers below. + * Only one of them is valid (the currently enabled PHY). */ +#ifdef CONFIG_B43_DEBUG + /* No union for debug build to force NULL derefs in buggy code. */ + struct { +#else + union { +#endif + /* A-PHY specific information */ + struct b43_phy_a *a; + /* G-PHY specific information */ + struct b43_phy_g *g; + /* N-PHY specific information */ + struct b43_phy_n *n; + }; + + /* Band support flags. */ + bool supports_2ghz; + bool supports_5ghz; + + /* GMODE bit enabled? */ + bool gmode; + + /* Analog Type */ + u8 analog; + /* B43_PHYTYPE_ */ + u8 type; + /* PHY revision number. */ + u8 rev; + + /* Radio versioning */ + u16 radio_manuf; /* Radio manufacturer */ + u16 radio_ver; /* Radio version */ + u8 radio_rev; /* Radio revision */ + + /* Software state of the radio */ + bool radio_on; + + /* Desired TX power level (in dBm). + * This is set by the user and adjusted in b43_phy_xmitpower(). */ + u8 power_level; + + /* Hardware Power Control enabled? */ + bool hardware_power_control; + + /* current channel */ + unsigned int channel; + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + +#ifdef CONFIG_B43_DEBUG + /* PHY registers locked by b43_phy_lock()? */ + bool phy_locked; +#endif /* B43_DEBUG */ +}; + + +/** + * b43_phy_operations_setup - Initialize the PHY operations datastructure + * based on the current PHY type. + */ +int b43_phy_operations_setup(struct b43_wldev *dev); + +/** + * b43_phy_init - Initialise the PHY + */ +int b43_phy_init(struct b43_wldev *dev); + +/** + * b43_phy_exit - Cleanup PHY + */ +void b43_phy_exit(struct b43_wldev *dev); + +/** + * b43_has_hardware_pctl - Hardware Power Control supported? + * Returns a boolean, whether hardware power control is supported. + */ +bool b43_has_hardware_pctl(struct b43_wldev *dev); + +/** + * b43_phy_read - 16bit PHY register read access + */ +u16 b43_phy_read(struct b43_wldev *dev, u16 reg); + +/** + * b43_phy_write - 16bit PHY register write access + */ +void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value); + +/** + * b43_phy_mask - Mask a PHY register with a mask + */ +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_phy_set - OR a PHY register with a bitmap + */ +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_phy_maskset - Mask and OR a PHY register with a mask and bitmap + */ +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_read - 16bit Radio register read access + */ +u16 b43_radio_read(struct b43_wldev *dev, u16 reg); +#define b43_radio_read16 b43_radio_read /* DEPRECATED */ + +/** + * b43_radio_write - 16bit Radio register write access + */ +void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value); +#define b43_radio_write16 b43_radio_write /* DEPRECATED */ + +/** + * b43_radio_mask - Mask a 16bit radio register with a mask + */ +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); + +/** + * b43_radio_set - OR a 16bit radio register with a bitmap + */ +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); + +/** + * b43_radio_maskset - Mask and OR a radio register with a mask and bitmap + */ +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + +/** + * b43_radio_lock - Lock firmware radio register access + */ +void b43_radio_lock(struct b43_wldev *dev); + +/** + * b43_radio_unlock - Unlock firmware radio register access + */ +void b43_radio_unlock(struct b43_wldev *dev); + +/** + * b43_phy_lock - Lock firmware PHY register access + */ +void b43_phy_lock(struct b43_wldev *dev); + +/** + * b43_phy_unlock - Unlock firmware PHY register access + */ +void b43_phy_unlock(struct b43_wldev *dev); + +/** + * b43_switch_channel - Switch to another channel + */ +int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); +/** + * B43_DEFAULT_CHANNEL - Switch to the default channel. + */ +#define B43_DEFAULT_CHANNEL UINT_MAX + +/** + * b43_software_rfkill - Turn the radio ON or OFF in software. + */ +void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); + +#endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c new file mode 100644 index 0000000..bb95c54 --- /dev/null +++ b/drivers/net/wireless/b43/phy_g.c @@ -0,0 +1,3229 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11g PHY driver + + Copyright (c) 2005 Martin Langer , + Copyright (c) 2005-2007 Stefano Brivio + Copyright (c) 2005-2008 Michael Buesch + Copyright (c) 2005, 2006 Danny van Dyk + Copyright (c) 2005, 2006 Andreas Jaggi + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "phy_g.h" +#include "phy_common.h" +#include "lo.h" +#include "main.h" + +#include + + +static const s8 b43_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +const u8 b43_radio_channel_codes_bg[] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, +}; + + +static void b43_calc_nrssi_threshold(struct b43_wldev *dev); + + +#define bitrev4(tmp) (bitrev8(tmp) >> 4) + + +/* Get the freq, as it has to be written to the device. */ +static inline u16 channel2freq_bg(u8 channel) +{ + B43_WARN_ON(!(channel >= 1 && channel <= 14)); + + return b43_radio_channel_codes_bg[channel - 1]; +} + +static void generate_rfatt_list(struct b43_wldev *dev, + struct b43_rfatt_list *list) +{ + struct b43_phy *phy = &dev->phy; + + /* APHY.rev < 5 || GPHY.rev < 6 */ + static const struct b43_rfatt rfatt_0[] = { + {.att = 3,.with_padmix = 0,}, + {.att = 1,.with_padmix = 0,}, + {.att = 5,.with_padmix = 0,}, + {.att = 7,.with_padmix = 0,}, + {.att = 9,.with_padmix = 0,}, + {.att = 2,.with_padmix = 0,}, + {.att = 0,.with_padmix = 0,}, + {.att = 4,.with_padmix = 0,}, + {.att = 6,.with_padmix = 0,}, + {.att = 8,.with_padmix = 0,}, + {.att = 1,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 3,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + }; + /* Radio.rev == 8 && Radio.version == 0x2050 */ + static const struct b43_rfatt rfatt_1[] = { + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 10,.with_padmix = 1,}, + {.att = 12,.with_padmix = 1,}, + {.att = 14,.with_padmix = 1,}, + }; + /* Otherwise */ + static const struct b43_rfatt rfatt_2[] = { + {.att = 0,.with_padmix = 1,}, + {.att = 2,.with_padmix = 1,}, + {.att = 4,.with_padmix = 1,}, + {.att = 6,.with_padmix = 1,}, + {.att = 8,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + {.att = 9,.with_padmix = 1,}, + }; + + if (!b43_has_hardware_pctl(dev)) { + /* Software pctl */ + list->list = rfatt_0; + list->len = ARRAY_SIZE(rfatt_0); + list->min_val = 0; + list->max_val = 9; + return; + } + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + /* Hardware pctl */ + list->list = rfatt_1; + list->len = ARRAY_SIZE(rfatt_1); + list->min_val = 0; + list->max_val = 14; + return; + } + /* Hardware pctl */ + list->list = rfatt_2; + list->len = ARRAY_SIZE(rfatt_2); + list->min_val = 0; + list->max_val = 9; +} + +static void generate_bbatt_list(struct b43_wldev *dev, + struct b43_bbatt_list *list) +{ + static const struct b43_bbatt bbatt_0[] = { + {.att = 0,}, + {.att = 1,}, + {.att = 2,}, + {.att = 3,}, + {.att = 4,}, + {.att = 5,}, + {.att = 6,}, + {.att = 7,}, + {.att = 8,}, + }; + + list->list = bbatt_0; + list->len = ARRAY_SIZE(bbatt_0); + list->min_val = 0; + list->max_val = 8; +} + +static void b43_shm_clear_tssi(struct b43_wldev *dev) +{ + b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F); + b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F); +} + +/* Synthetic PU workaround */ +static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + + might_sleep(); + + if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + b43_write16(dev, B43_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1)); + } + msleep(1); + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); +} + +/* Set the baseband attenuation value on chip. */ +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->analog == 0) { + b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0) + & 0xFFF0) | + baseband_attenuation); + } else if (phy->analog > 1) { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFFC3) | (baseband_attenuation << 2)); + } else { + b43_phy_write(dev, B43_PHY_DACCTL, + (b43_phy_read(dev, B43_PHY_DACCTL) + & 0xFF87) | (baseband_attenuation << 3)); + } +} + +/* Adjust the transmission power output (G-PHY) */ +void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + u16 bb, rf; + u16 tx_bias, tx_magn; + + bb = bbatt->att; + rf = rfatt->att; + tx_bias = lo->tx_bias; + tx_magn = lo->tx_magn; + if (unlikely(tx_bias == 0xFF)) + tx_bias = 0; + + /* Save the values for later */ + gphy->tx_control = tx_control; + memcpy(&gphy->rfatt, rfatt, sizeof(*rfatt)); + gphy->rfatt.with_padmix = !!(tx_control & B43_TXCTL_TXMIX); + memcpy(&gphy->bbatt, bbatt, sizeof(*bbatt)); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), " + "rfatt(%u), tx_control(0x%02X), " + "tx_bias(0x%02X), tx_magn(0x%02X)\n", + bb, rf, tx_control, tx_bias, tx_magn); + } + + b43_gphy_set_baseband_attenuation(dev, bb); + b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, + (rf & 0x000F) | (tx_control & 0x0070)); + } else { + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | (rf & 0x000F)); + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & ~0x0070) | (tx_control & + 0x0070)); + } + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, tx_magn | tx_bias); + } else { + b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) + & 0xFFF0) | (tx_bias & 0x000F)); + } + b43_lo_g_adjust(dev); +} + +/* GPHY_TSSI_Power_Lookup_Table_Init */ +static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + int i; + u16 value; + + for (i = 0; i < 32; i++) + b43_ofdmtab_write16(dev, 0x3C20, i, gphy->tssi2dbm[i]); + for (i = 32; i < 64; i++) + b43_ofdmtab_write16(dev, 0x3C00, i - 32, gphy->tssi2dbm[i]); + for (i = 0; i < 64; i += 2) { + value = (u16) gphy->tssi2dbm[i]; + value |= ((u16) gphy->tssi2dbm[i + 1]) << 8; + b43_phy_write(dev, 0x380 + (i / 2), value); + } +} + +/* GPHY_Gain_Lookup_Table_Init */ +static void b43_gphy_gain_lt_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + u16 nr_written = 0; + u16 tmp; + u8 rf, bb; + + for (rf = 0; rf < lo->rfatt_list.len; rf++) { + for (bb = 0; bb < lo->bbatt_list.len; bb++) { + if (nr_written >= 0x40) + return; + tmp = lo->bbatt_list.list[bb].att; + tmp <<= 8; + if (phy->radio_rev == 8) + tmp |= 0x50; + else + tmp |= 0x40; + tmp |= lo->rfatt_list.list[rf].att; + b43_phy_write(dev, 0x3C0 + nr_written, tmp); + nr_written++; + } + } +} + +static void b43_set_all_gains(struct b43_wldev *dev, + s16 first, s16 second, s16 third) +{ + struct b43_phy *phy = &dev->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 tmp; + u16 table; + + if (phy->rev <= 1) { + start = 0x10; + end = 0x20; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) + b43_ofdmtab_write16(dev, table, i, first); + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, second); + + if (third != -1) { + tmp = ((u16) third << 14) | ((u16) third << 6); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); + } + b43_dummy_transmission(dev); +} + +static void b43_set_original_gains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 i, tmp; + u16 table; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + start = 0x0010; + end = 0x0020; + } + + table = B43_OFDMTAB_GAINX; + if (phy->rev <= 1) + table = B43_OFDMTAB_GAINX_R1; + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + b43_ofdmtab_write16(dev, table, i, tmp); + } + + for (i = start; i < end; i++) + b43_ofdmtab_write16(dev, table, i, i - start); + + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); + b43_dummy_transmission(dev); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +{ + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + mmiowb(); + b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +{ + u16 val; + + b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); + val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA); + + return (s16) val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = b43_nrssi_hw_read(dev, i); + tmp -= val; + tmp = clamp_val(tmp, -32, 31); + b43_nrssi_hw_write(dev, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void b43_nrssi_mem_update(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + s16 i, delta; + s32 tmp; + + delta = 0x1F - gphy->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * gphy->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = clamp_val(tmp, 0, 0x3F); + gphy->nrssi_lt[i] = tmp; + } +} + +static void b43_calc_nrssi_offset(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = b43_phy_read(dev, 0x0001); + backup[1] = b43_phy_read(dev, 0x0811); + backup[2] = b43_phy_read(dev, 0x0812); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup[3] = b43_phy_read(dev, 0x0814); + backup[4] = b43_phy_read(dev, 0x0815); + } + backup[5] = b43_phy_read(dev, 0x005A); + backup[6] = b43_phy_read(dev, 0x0059); + backup[7] = b43_phy_read(dev, 0x0058); + backup[8] = b43_phy_read(dev, 0x000A); + backup[9] = b43_phy_read(dev, 0x0003); + backup[10] = b43_radio_read16(dev, 0x007A); + backup[11] = b43_radio_read16(dev, 0x0043); + + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); + b43_phy_write(dev, 0x0001, + (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = b43_phy_read(dev, 0x002E); + backup[13] = b43_phy_read(dev, 0x002F); + backup[14] = b43_phy_read(dev, 0x080F); + backup[15] = b43_phy_read(dev, 0x0810); + backup[16] = b43_phy_read(dev, 0x0801); + backup[17] = b43_phy_read(dev, 0x0060); + backup[18] = b43_phy_read(dev, 0x0014); + backup[19] = b43_phy_read(dev, 0x0478); + + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, 0x002F, 0); + b43_phy_write(dev, 0x080F, 0); + b43_phy_write(dev, 0x0810, 0); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); + } + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0001); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFE); + } + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); + b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); + b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + if (phy->rev == 0) { + b43_phy_write(dev, 0x0003, 0x0122); + } else { + b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) + | 0x2000); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, + b43_phy_read(dev, 0x0814) | 0x0004); + b43_phy_write(dev, 0x0815, + b43_phy_read(dev, 0x0815) & 0xFFFB); + } + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) + | 0x0040); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_set_all_gains(dev, 3, 0, 1); + b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + b43_radio_write16(dev, 0x007B, i); + udelay(20); + v47F = + (s16) ((b43_phy_read(dev, 0x047F) >> 8) & + 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + b43_radio_write16(dev, 0x007B, saved); + + if (phy->rev >= 6) { + b43_phy_write(dev, 0x002E, backup[12]); + b43_phy_write(dev, 0x002F, backup[13]); + b43_phy_write(dev, 0x080F, backup[14]); + b43_phy_write(dev, 0x0810, backup[15]); + } + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, 0x0814, backup[3]); + b43_phy_write(dev, 0x0815, backup[4]); + } + b43_phy_write(dev, 0x005A, backup[5]); + b43_phy_write(dev, 0x0059, backup[6]); + b43_phy_write(dev, 0x0058, backup[7]); + b43_phy_write(dev, 0x000A, backup[8]); + b43_phy_write(dev, 0x0003, backup[9]); + b43_radio_write16(dev, 0x0043, backup[11]); + b43_radio_write16(dev, 0x007A, backup[10]); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); + b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); + b43_set_original_gains(dev); + if (phy->rev >= 6) { + b43_phy_write(dev, 0x0801, backup[16]); + b43_phy_write(dev, 0x0060, backup[17]); + b43_phy_write(dev, 0x0014, backup[18]); + b43_phy_write(dev, 0x0478, backup[19]); + } + b43_phy_write(dev, 0x0001, backup[0]); + b43_phy_write(dev, 0x0812, backup[2]); + b43_phy_write(dev, 0x0811, backup[1]); +} + +void b43_calc_nrssi_slope(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if (phy->radio_rev >= 9) + return; + if (phy->radio_rev == 8) + b43_calc_nrssi_offset(dev); + + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + backup[7] = b43_read16(dev, 0x03E2); + b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); + backup[0] = b43_radio_read16(dev, 0x007A); + backup[1] = b43_radio_read16(dev, 0x0052); + backup[2] = b43_radio_read16(dev, 0x0043); + backup[3] = b43_phy_read(dev, 0x0015); + backup[4] = b43_phy_read(dev, 0x005A); + backup[5] = b43_phy_read(dev, 0x0059); + backup[6] = b43_phy_read(dev, 0x0058); + backup[8] = b43_read16(dev, 0x03E6); + backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = b43_phy_read(dev, 0x002E); + backup[11] = b43_phy_read(dev, 0x002F); + backup[12] = b43_phy_read(dev, 0x080F); + backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL); + backup[14] = b43_phy_read(dev, 0x0801); + backup[15] = b43_phy_read(dev, 0x0060); + backup[16] = b43_phy_read(dev, 0x0014); + backup[17] = b43_phy_read(dev, 0x0478); + b43_phy_write(dev, 0x002E, 0); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: + case 6: + case 7: + b43_phy_write(dev, 0x0478, + b43_phy_read(dev, 0x0478) + | 0x0100); + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + | 0x0040); + break; + case 3: + case 5: + b43_phy_write(dev, 0x0801, + b43_phy_read(dev, 0x0801) + & 0xFFBF); + break; + } + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) + | 0x0040); + b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) + | 0x0200); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0070); + b43_set_all_gains(dev, 0, 8, 0); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0030); + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0010); + } + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) & 0x007F); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) + & 0xFF9F) | 0x0040); + } + + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | 0x2000); + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x000F); + b43_phy_write(dev, 0x0015, 0xF330); + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + (b43_phy_read(dev, 0x0812) & 0xFFCF) | + 0x0020); + b43_phy_write(dev, 0x0811, + (b43_phy_read(dev, 0x0811) & 0xFFCF) | + 0x0020); + } + + b43_set_all_gains(dev, 3, 0, 1); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x0043, 0x001F); + } else { + tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F; + b43_radio_write16(dev, 0x0052, tmp | 0x0060); + tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0; + b43_radio_write16(dev, 0x0043, tmp | 0x0009); + } + b43_phy_write(dev, 0x005A, 0x0480); + b43_phy_write(dev, 0x0059, 0x0810); + b43_phy_write(dev, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + gphy->nrssislope = 0x00010000; + else + gphy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + gphy->nrssi[0] = nrssi1; + gphy->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + b43_phy_write(dev, 0x002E, backup[10]); + b43_phy_write(dev, 0x002F, backup[11]); + b43_phy_write(dev, 0x080F, backup[12]); + b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x0812, + b43_phy_read(dev, 0x0812) & 0xFFCF); + b43_phy_write(dev, 0x0811, + b43_phy_read(dev, 0x0811) & 0xFFCF); + } + + b43_radio_write16(dev, 0x007A, backup[0]); + b43_radio_write16(dev, 0x0052, backup[1]); + b43_radio_write16(dev, 0x0043, backup[2]); + b43_write16(dev, 0x03E2, backup[7]); + b43_write16(dev, 0x03E6, backup[8]); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]); + b43_phy_write(dev, 0x0015, backup[3]); + b43_phy_write(dev, 0x005A, backup[4]); + b43_phy_write(dev, 0x0059, backup[5]); + b43_phy_write(dev, 0x0058, backup[6]); + b43_synth_pu_workaround(dev, phy->channel); + b43_phy_write(dev, 0x0802, + b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); + b43_set_original_gains(dev); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + b43_phy_write(dev, 0x0801, backup[14]); + b43_phy_write(dev, 0x0060, backup[15]); + b43_phy_write(dev, 0x0014, backup[16]); + b43_phy_write(dev, 0x0478, backup[17]); + } + b43_nrssi_mem_update(dev); + b43_calc_nrssi_threshold(dev); +} + +static void b43_calc_nrssi_threshold(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + s32 a, b; + s16 tmp16; + u16 tmp_u16; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if (!phy->gmode || + !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + tmp16 = b43_nrssi_hw_read(dev, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x09EB); + } else { + b43_phy_write(dev, 0x048A, + (b43_phy_read(dev, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + if (gphy->interfmode == B43_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!gphy->aci_wlan_automatic && gphy->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (gphy->nrssi[1] - gphy->nrssi[0]); + a += (gphy->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = clamp_val(a, -31, 31); + + b = b * (gphy->nrssi[1] - gphy->nrssi[0]); + b += (gphy->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = clamp_val(b, -31, 31); + + tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000; + tmp_u16 |= ((u32) b & 0x0000003F); + tmp_u16 |= (((u32) a & 0x0000003F) << 6); + b43_phy_write(dev, 0x048A, tmp_u16); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 * _stackptr, size_t * stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + *stackptr = offset; + *stackptr |= ((u32) id) << 12; + *stackptr |= ((u32) value) << 16; + (*stackidx)++; + B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) +{ + size_t i; + + B43_WARN_ON(offset & 0xF000); + B43_WARN_ON(id & 0xF0); + for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + B43_WARN_ON(1); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + b43_phy_read(dev, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + b43_phy_write(dev, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + b43_radio_read16(dev, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + b43_radio_write16(dev, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ofdmtab_stacksave(table, offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset)|(table), \ + b43_ofdmtab_read16(dev, (table), (offset))); \ + } while (0) +#define ofdmtab_stackrestore(table, offset) \ + do { \ + b43_ofdmtab_write16(dev, (table), (offset), \ + _stack_restore(stack, 0x3, \ + (offset)|(table))); \ + } while (0) + +static void +b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp, flipped; + size_t stackidx = 0; + u32 *stack = gphy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (b43_radio_read16(dev, 0x0078) & 0x001E); + B43_WARN_ON(tmp > 15); + flipped = bitrev4(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = (bitrev4(flipped) << 1) | 0x0020; + b43_radio_write16(dev, 0x0078, flipped); + + b43_calc_nrssi_threshold(dev); + + phy_stacksave(0x0406); + b43_phy_write(dev, 0x0406, 0x7E28); + + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + b43_phy_write(dev, 0x04A0, + (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); + phy_stacksave(0x04A1); + b43_phy_write(dev, 0x04A1, + (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); + phy_stacksave(0x04A2); + b43_phy_write(dev, 0x04A2, + (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); + phy_stacksave(0x04A8); + b43_phy_write(dev, 0x04A8, + (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); + b43_phy_write(dev, 0x04AB, + (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); + + phy_stacksave(0x04A7); + b43_phy_write(dev, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + b43_phy_write(dev, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + b43_phy_write(dev, 0x04A9, 0x2027); + phy_stacksave(0x0493); + b43_phy_write(dev, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + b43_phy_write(dev, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + b43_phy_write(dev, 0x04AC, 0x32F5); + break; + case B43_INTERFMODE_MANUALWLAN: + if (b43_phy_read(dev, 0x0033) & 0x0800) + break; + + gphy->aci_enable = 1; + + phy_stacksave(B43_PHY_RADIO_BITFIELD); + phy_stacksave(B43_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); + } else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ofdmtab_stacksave(0x1A00, 0x2); + ofdmtab_stacksave(0x1A00, 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~0x1000); + b43_phy_write(dev, B43_PHY_G_CRS, + (b43_phy_read(dev, B43_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + b43_phy_write(dev, 0x0033, 0x0800); + b43_phy_write(dev, 0x04A3, 0x2027); + b43_phy_write(dev, 0x04A9, 0x1CA8); + b43_phy_write(dev, 0x0493, 0x287A); + b43_phy_write(dev, 0x04AA, 0x1CA8); + b43_phy_write(dev, 0x04AC, 0x287A); + + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xFFC0) | 0x001A); + b43_phy_write(dev, 0x04A7, 0x000D); + + if (phy->rev < 2) { + b43_phy_write(dev, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + b43_phy_write(dev, 0x04C0, 0xFFFF); + b43_phy_write(dev, 0x04C1, 0x00A9); + } else { + b43_phy_write(dev, 0x04C0, 0x00C1); + b43_phy_write(dev, 0x04C1, 0x0059); + } + + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xC0FF) | 0x1800); + b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) + & 0xFFC0) | 0x0015); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xF0FF) | 0x0A00); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xCFFF) | 0x1000); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) + & 0xFFF0) | 0x0005); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFCF) | 0x0010); + b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) + & 0xFFF0) | 0x0006); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xF0FF) | 0x0800); + b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) + & 0xF0FF) | 0x0500); + b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + & ~0x8000); + b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) + & 0x8000) | 0x36D8); + b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) + & 0xFE00) | 0x016D); + } else { + b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) + | 0x1000); + b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) + & 0x9FFF) | 0x2000); + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); + } + if (phy->rev >= 2) { + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) + | 0x0800); + } + b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) + & 0xFF00) | 0x007F); + b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); + b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); + b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) + & 0x00FF); + } + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +static void +b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u32 *stack = gphy->interfstack; + + switch (mode) { + case B43_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + b43_phy_write(dev, 0x042B, + b43_phy_read(dev, 0x042B) & ~0x0800); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, + B43_PHY_G_CRS) | 0x4000); + break; + } + radio_stackrestore(0x0078); + b43_calc_nrssi_threshold(dev); + phy_stackrestore(0x0406); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); + if (!dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case B43_INTERFMODE_MANUALWLAN: + if (!(b43_phy_read(dev, 0x0033) & 0x0800)) + break; + + gphy->aci_enable = 0; + + phy_stackrestore(B43_PHY_RADIO_BITFIELD); + phy_stackrestore(B43_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ofdmtab_stackrestore(0x1A00, 0x2); + ofdmtab_stackrestore(0x1A00, 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x048A); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW); + b43_calc_nrssi_slope(dev); + break; + default: + B43_WARN_ON(1); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ofdmtab_stacksave +#undef ofdmtab_stackrestore + +static u16 b43_radio_core_calibration_value(struct b43_wldev *dev) +{ + u16 reg, index, ret; + + static const u8 rcc_table[] = { + 0x02, 0x03, 0x01, 0x0F, + 0x06, 0x07, 0x05, 0x0F, + 0x0A, 0x0B, 0x09, 0x0F, + 0x0E, 0x0F, 0x0D, 0x0F, + }; + + reg = b43_radio_read16(dev, 0x60); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) +static u16 radio2050_rfover_val(struct b43_wldev *dev, + u16 phy_register, unsigned int lpd) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + + if (!phy->gmode) + return 0; + + if (has_loopback_gain(phy)) { + int max_lb_gain = gphy->max_lb_gain; + u16 extlna; + u16 i; + + if (phy->radio_rev == 8) + max_lb_gain += 0x3E; + else + max_lb_gain += 0x26; + if (max_lb_gain >= 0x46) { + extlna = 0x3000; + max_lb_gain -= 0x46; + } else if (max_lb_gain >= 0x3A) { + extlna = 0x1000; + max_lb_gain -= 0x3A; + } else if (max_lb_gain >= 0x2E) { + extlna = 0x2000; + max_lb_gain -= 0x2E; + } else { + extlna = 0; + max_lb_gain -= 0x10; + } + + for (i = 0; i < 16; i++) { + max_lb_gain -= (i * 6); + if (max_lb_gain < 6) + break; + } + + if ((phy->rev < 7) || + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x0F92; + case LPD(0, 0, 1): + case LPD(1, 0, 1): + return (0x0092 | extlna); + case LPD(1, 0, 0): + return (0x0093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + if (extlna) + extlna |= 0x8000; + extlna |= (i << 8); + switch (lpd) { + case LPD(0, 1, 1): + return 0x8F92; + case LPD(0, 0, 1): + return (0x8092 | extlna); + case LPD(1, 0, 1): + return (0x2092 | extlna); + case LPD(1, 0, 0): + return (0x2093 | extlna); + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } else { + if ((phy->rev < 7) || + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { + if (phy_register == B43_PHY_RFOVER) { + return 0x1B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x0FB2; + case LPD(0, 0, 1): + return 0x00B2; + case LPD(1, 0, 1): + return 0x30B2; + case LPD(1, 0, 0): + return 0x30B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } else { + if (phy_register == B43_PHY_RFOVER) { + return 0x9B3; + } else if (phy_register == B43_PHY_RFOVERVAL) { + switch (lpd) { + case LPD(0, 1, 1): + return 0x8FB2; + case LPD(0, 0, 1): + return 0x80B2; + case LPD(1, 0, 1): + return 0x20B2; + case LPD(1, 0, 0): + return 0x20B3; + } + B43_WARN_ON(1); + } + B43_WARN_ON(1); + } + } + return 0; +} + +struct init2050_saved_values { + /* Core registers */ + u16 reg_3EC; + u16 reg_3E6; + u16 reg_3F4; + /* Radio registers */ + u16 radio_43; + u16 radio_51; + u16 radio_52; + /* PHY registers */ + u16 phy_pgactl; + u16 phy_cck_5A; + u16 phy_cck_59; + u16 phy_cck_58; + u16 phy_cck_30; + u16 phy_rfover; + u16 phy_rfoverval; + u16 phy_analogover; + u16 phy_analogoverval; + u16 phy_crs0; + u16 phy_classctl; + u16 phy_lo_mask; + u16 phy_lo_ctl; + u16 phy_syncctl; +}; + +u16 b43_radio_init2050(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct init2050_saved_values sav; + u16 rcc; + u16 radio78; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */ + + sav.radio_43 = b43_radio_read16(dev, 0x43); + sav.radio_51 = b43_radio_read16(dev, 0x51); + sav.radio_52 = b43_radio_read16(dev, 0x52); + sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); + sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); + sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); + + if (phy->type == B43_PHYTYPE_B) { + sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); + sav.reg_3EC = b43_read16(dev, 0x3EC); + + b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); + b43_write16(dev, 0x3EC, 0x3F3F); + } else if (phy->gmode || phy->rev >= 2) { + sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); + sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER); + sav.phy_analogoverval = + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); + sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); + + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) + | 0x0003); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) + & 0xFFFC); + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_CLASSCTL, + b43_phy_read(dev, B43_PHY_CLASSCTL) + & 0xFFFC); + if (has_loopback_gain(phy)) { + sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); + sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + } + + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + b43_phy_write(dev, B43_PHY_RFOVER, + radio2050_rfover_val(dev, B43_PHY_RFOVER, 0)); + } + b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); + + sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); + b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) + & 0xFF7F); + sav.reg_3E6 = b43_read16(dev, 0x3E6); + sav.reg_3F4 = b43_read16(dev, 0x3F4); + + if (phy->analog == 0) { + b43_write16(dev, 0x03E6, 0x0122); + } else { + if (phy->analog >= 2) { + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) + & 0xFFBF) | 0x40); + } + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); + } + + rcc = b43_radio_core_calibration_value(dev); + + if (phy->type == B43_PHYTYPE_B) + b43_radio_write16(dev, 0x78, 0x26); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 1, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, + LPD(0, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); + b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) + | 0x0004); + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x1F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x0009); + } + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(20); + tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + udelay(10); + + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + tmp1++; + tmp1 >>= 9; + + for (i = 0; i < 16; i++) { + radio78 = (bitrev4(i) << 1) | 0x0020; + b43_radio_write16(dev, 0x78, radio78); + udelay(10); + for (j = 0; j < 16; j++) { + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0); + udelay(10); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 0))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); + udelay(10); + tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); + if (phy->gmode || phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + radio2050_rfover_val(dev, + B43_PHY_RFOVERVAL, + LPD(1, 0, + 1))); + } + b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl); + b43_radio_write16(dev, 0x51, sav.radio_51); + b43_radio_write16(dev, 0x52, sav.radio_52); + b43_radio_write16(dev, 0x43, sav.radio_43); + b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); + b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); + b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); + b43_write16(dev, 0x3E6, sav.reg_3E6); + if (phy->analog != 0) + b43_write16(dev, 0x3F4, sav.reg_3F4); + b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); + b43_synth_pu_workaround(dev, phy->channel); + if (phy->type == B43_PHYTYPE_B) { + b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); + b43_write16(dev, 0x3EC, sav.reg_3EC); + } else if (phy->gmode) { + b43_write16(dev, B43_MMIO_PHY_RADIO, + b43_read16(dev, B43_MMIO_PHY_RADIO) + & 0x7FFF); + b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval); + b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + sav.phy_analogoverval); + b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0); + b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl); + if (has_loopback_gain(phy)) { + b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask); + b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl); + } + } + if (i > 15) + ret = radio78; + else + ret = rcc; + + return ret; +} + +static void b43_phy_initb5(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, value; + u8 old_channel; + + if (phy->analog == 1) { + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) + | 0x0050); + } + if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type != SSB_BOARD_BU4306)) { + value = 0x2120; + for (offset = 0x00A8; offset < 0x00C7; offset++) { + b43_phy_write(dev, offset, value); + value += 0x202; + } + } + b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) + | 0x0700); + if (phy->radio_ver == 0x2050) + b43_phy_write(dev, 0x0038, 0x0667); + + if (phy->gmode || phy->rev >= 2) { + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) + | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) + | 0x0004); + } + b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); + + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + + b43_phy_write(dev, 0x001C, 0x186A); + + b43_phy_write(dev, 0x0013, + (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); + b43_phy_write(dev, 0x0035, + (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); + b43_phy_write(dev, 0x005D, + (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); + } + + if (dev->bad_frames_preempt) { + b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, + b43_phy_read(dev, + B43_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->analog == 1) { + b43_phy_write(dev, 0x0026, 0xCE00); + b43_phy_write(dev, 0x0021, 0x3763); + b43_phy_write(dev, 0x0022, 0x1BC3); + b43_phy_write(dev, 0x0023, 0x06F9); + b43_phy_write(dev, 0x0024, 0x037E); + } else + b43_phy_write(dev, 0x0026, 0xCC00); + b43_phy_write(dev, 0x0030, 0x00C6); + b43_write16(dev, 0x03EC, 0x3F22); + + if (phy->analog == 1) + b43_phy_write(dev, 0x0020, 0x3E1C); + else + b43_phy_write(dev, 0x0020, 0x301C); + + if (phy->analog == 0) + b43_write16(dev, 0x03E4, 0x3000); + + old_channel = phy->channel; + /* Force to channel 7, even if not supported. */ + b43_gphy_channel_switch(dev, 7, 0); + + if (phy->radio_ver != 0x2050) { + b43_radio_write16(dev, 0x0075, 0x0080); + b43_radio_write16(dev, 0x0079, 0x0081); + } + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + + if (phy->radio_ver == 0x2050) { + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x005A, 0x0070); + } + + b43_radio_write16(dev, 0x005B, 0x007B); + b43_radio_write16(dev, 0x005C, 0x00B0); + + b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0080); + b43_phy_write(dev, 0x0032, 0x00CA); + b43_phy_write(dev, 0x002A, 0x88A3); + + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + + if (phy->radio_ver == 0x2050) + b43_radio_write16(dev, 0x005D, 0x000D); + + b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void b43_phy_initb6(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 offset, val; + u8 old_channel; + + b43_phy_write(dev, 0x003E, 0x817A); + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) | 0x0058)); + if (phy->radio_rev == 4 || phy->radio_rev == 5) { + b43_radio_write16(dev, 0x51, 0x37); + b43_radio_write16(dev, 0x52, 0x70); + b43_radio_write16(dev, 0x53, 0xB3); + b43_radio_write16(dev, 0x54, 0x9B); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x88); + b43_radio_write16(dev, 0x5D, 0x88); + b43_radio_write16(dev, 0x5E, 0x88); + b43_radio_write16(dev, 0x7D, 0x88); + b43_hf_write(dev, b43_hf_read(dev) + | B43_HF_TSSIRPSMW); + } + B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */ + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x51, 0); + b43_radio_write16(dev, 0x52, 0x40); + b43_radio_write16(dev, 0x53, 0xB7); + b43_radio_write16(dev, 0x54, 0x98); + b43_radio_write16(dev, 0x5A, 0x88); + b43_radio_write16(dev, 0x5B, 0x6B); + b43_radio_write16(dev, 0x5C, 0x0F); + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { + b43_radio_write16(dev, 0x5D, 0xFA); + b43_radio_write16(dev, 0x5E, 0xD8); + } else { + b43_radio_write16(dev, 0x5D, 0xF5); + b43_radio_write16(dev, 0x5E, 0xB8); + } + b43_radio_write16(dev, 0x0073, 0x0003); + b43_radio_write16(dev, 0x007D, 0x00A8); + b43_radio_write16(dev, 0x007C, 0x0001); + b43_radio_write16(dev, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + b43_phy_write(dev, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + b43_phy_write(dev, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == B43_PHYTYPE_G) { + b43_radio_write16(dev, 0x007A, + b43_radio_read16(dev, 0x007A) | 0x0020); + b43_radio_write16(dev, 0x0051, + b43_radio_read16(dev, 0x0051) | 0x0004); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); + b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); + b43_phy_write(dev, 0x5B, 0); + b43_phy_write(dev, 0x5C, 0); + } + + old_channel = phy->channel; + if (old_channel >= 8) + b43_gphy_channel_switch(dev, 1, 0); + else + b43_gphy_channel_switch(dev, 13, 0); + + b43_radio_write16(dev, 0x0050, 0x0020); + b43_radio_write16(dev, 0x0050, 0x0023); + udelay(40); + if (phy->radio_rev < 6 || phy->radio_rev == 8) { + b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C) + | 0x0002)); + b43_radio_write16(dev, 0x50, 0x20); + } + if (phy->radio_rev <= 2) { + b43_radio_write16(dev, 0x7C, 0x20); + b43_radio_write16(dev, 0x5A, 0x70); + b43_radio_write16(dev, 0x5B, 0x7B); + b43_radio_write16(dev, 0x5C, 0xB0); + } + b43_radio_write16(dev, 0x007A, + (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); + + b43_gphy_channel_switch(dev, old_channel, 0); + + b43_phy_write(dev, 0x0014, 0x0200); + if (phy->radio_rev >= 6) + b43_phy_write(dev, 0x2A, 0x88C2); + else + b43_phy_write(dev, 0x2A, 0x8AC0); + b43_phy_write(dev, 0x0038, 0x0668); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); + if (phy->radio_rev <= 5) { + b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) + & 0xFF80) | 0x0003); + } + if (phy->radio_rev <= 2) + b43_radio_write16(dev, 0x005D, 0x000D); + + if (phy->analog == 4) { + b43_write16(dev, 0x3E4, 9); + b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) + & 0x0FFF); + } else { + b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) + | 0x0004); + } + if (phy->type == B43_PHYTYPE_B) + B43_WARN_ON(1); + else if (phy->type == B43_PHYTYPE_G) + b43_write16(dev, 0x03E6, 0x0); +} + +static void b43_calc_loopback_gain(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 backup_phy[16] = { 0 }; + u16 backup_radio[3]; + u16 backup_bband; + u16 i, j, loop_i_max; + u16 trsw_rx; + u16 loop1_outer_done, loop1_inner_done; + + backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0); + backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG); + backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER); + backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); + backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); + } + backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); + backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); + backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); + backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); + backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); + backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); + backup_bband = gphy->bbatt.att; + backup_radio[0] = b43_radio_read16(dev, 0x52); + backup_radio[1] = b43_radio_read16(dev, 0x43); + backup_radio[2] = b43_radio_read16(dev, 0x7A); + + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, + b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFE); + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFD); + } + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xFFCF) | 0x10); + + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); + + b43_phy_write(dev, B43_PHY_CCK(0x0A), + b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, + b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, + b43_phy_read(dev, + B43_PHY_ANALOGOVERVAL) & 0xFFFB); + } + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) + & 0xFF9F) | 0x40); + + if (phy->radio_rev == 8) { + b43_radio_write16(dev, 0x43, 0x000F); + } else { + b43_radio_write16(dev, 0x52, 0); + b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) + & 0xFFF0) | 0x9); + } + b43_gphy_set_baseband_attenuation(dev, 11); + + if (phy->rev >= 3) + b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020); + else + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); + b43_phy_write(dev, B43_PHY_LO_CTL, 0); + + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xFFC0) | 0x01); + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) + & 0xC0FF) | 0x800); + + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); + + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { + if (phy->rev >= 7) { + b43_phy_write(dev, B43_PHY_RFOVER, + b43_phy_read(dev, B43_PHY_RFOVER) + | 0x0800); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x8000); + } + } + b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) + & 0x00F7); + + j = 0; + loop_i_max = (phy->radio_rev == 8) ? 15 : 9; + for (i = 0; i < loop_i_max; i++) { + for (j = 0; j < 16; j++) { + b43_radio_write16(dev, 0x43, i); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop1; + } + } + exit_loop1: + loop1_outer_done = i; + loop1_inner_done = j; + if (j >= 8) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + b43_phy_read(dev, B43_PHY_RFOVERVAL) + | 0x30); + trsw_rx = 0x1B; + for (j = j - 8; j < 16; j++) { + b43_phy_write(dev, B43_PHY_RFOVERVAL, + (b43_phy_read(dev, B43_PHY_RFOVERVAL) + & 0xF0FF) | (j << 8)); + b43_phy_write(dev, B43_PHY_PGACTL, + (b43_phy_read(dev, B43_PHY_PGACTL) + & 0x0FFF) | 0xA000); + b43_phy_write(dev, B43_PHY_PGACTL, + b43_phy_read(dev, B43_PHY_PGACTL) + | 0xF000); + udelay(20); + trsw_rx -= 3; + if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) + goto exit_loop2; + } + } else + trsw_rx = 0x18; + exit_loop2: + + if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ + b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); + } + b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); + b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); + b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); + + b43_gphy_set_baseband_attenuation(dev, backup_bband); + + b43_radio_write16(dev, 0x52, backup_radio[0]); + b43_radio_write16(dev, 0x43, backup_radio[1]); + b43_radio_write16(dev, 0x7A, backup_radio[2]); + + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003); + udelay(10); + b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]); + b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]); + b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]); + b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]); + + gphy->max_lb_gain = + ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11; + gphy->trsw_rx_gain = trsw_rx * 2; +} + +static void b43_hardware_pctl_early_init(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!b43_has_hardware_pctl(dev)) { + b43_phy_write(dev, 0x047A, 0xC111); + return; + } + + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); + b43_phy_write(dev, 0x002F, 0x0202); + b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); + b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); + if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + | 0x8000); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + } else { + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0200); + b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) + | 0x0400); + b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) + & 0x7FFF); + b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) + & 0xFFFE); + b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) + & 0xFFC0) | 0x0010); + b43_phy_write(dev, 0x002E, 0xC07F); + b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) + & 0xFF0F) | 0x0010); + } +} + +/* Hardware power control for G-PHY */ +static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + if (!b43_has_hardware_pctl(dev)) { + /* No hardware power control */ + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL); + return; + } + + b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) + | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); + b43_gphy_tssi_power_lt_init(dev); + b43_gphy_gain_lt_init(dev); + b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); + b43_phy_write(dev, 0x0014, 0x0000); + + B43_WARN_ON(phy->rev < 6); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + | 0x0800); + b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) + & 0xFEFF); + b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) + & 0xFFBF); + + b43_gphy_dc_lt_init(dev, 1); + + /* Enable hardware pctl in firmware. */ + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL); +} + +/* Intialize B/G PHY power control */ +static void b43_phy_init_pctl(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_rfatt old_rfatt; + struct b43_bbatt old_bbatt; + u8 old_tx_control = 0; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + b43_phy_write(dev, 0x0028, 0x8018); + + /* This does something with the Analog... */ + b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0) + & 0xFFDF); + + if (!phy->gmode) + return; + b43_hardware_pctl_early_init(dev); + if (gphy->cur_idle_tssi == 0) { + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + (b43_radio_read16(dev, 0x0076) + & 0x00F7) | 0x0084); + } else { + struct b43_rfatt rfatt; + struct b43_bbatt bbatt; + + memcpy(&old_rfatt, &gphy->rfatt, sizeof(old_rfatt)); + memcpy(&old_bbatt, &gphy->bbatt, sizeof(old_bbatt)); + old_tx_control = gphy->tx_control; + + bbatt.att = 11; + if (phy->radio_rev == 8) { + rfatt.att = 15; + rfatt.with_padmix = 1; + } else { + rfatt.att = 9; + rfatt.with_padmix = 0; + } + b43_set_txpower_g(dev, &bbatt, &rfatt, 0); + } + b43_dummy_transmission(dev); + gphy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI); + if (B43_DEBUG) { + /* Current-Idle-TSSI sanity check. */ + if (abs(gphy->cur_idle_tssi - gphy->tgt_idle_tssi) >= 20) { + b43dbg(dev->wl, + "!WARNING! Idle-TSSI phy->cur_idle_tssi " + "measuring failed. (cur=%d, tgt=%d). Disabling TX power " + "adjustment.\n", gphy->cur_idle_tssi, + gphy->tgt_idle_tssi); + gphy->cur_idle_tssi = 0; + } + } + if (phy->radio_ver == 0x2050 && phy->analog == 0) { + b43_radio_write16(dev, 0x0076, + b43_radio_read16(dev, 0x0076) + & 0xFF7B); + } else { + b43_set_txpower_g(dev, &old_bbatt, + &old_rfatt, old_tx_control); + } + } + b43_hardware_pctl_init_gphy(dev); + b43_shm_clear_tssi(dev); +} + +static void b43_phy_initg(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp; + + if (phy->rev == 1) + b43_phy_initb5(dev); + else + b43_phy_initb6(dev); + + if (phy->rev >= 2 || phy->gmode) + b43_phy_inita(dev); + + if (phy->rev >= 2) { + b43_phy_write(dev, B43_PHY_ANALOGOVER, 0); + b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0); + } + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_RFOVER, 0); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->rev > 5) { + b43_phy_write(dev, B43_PHY_RFOVER, 0x400); + b43_phy_write(dev, B43_PHY_PGACTL, 0xC0); + } + if (phy->gmode || phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM); + tmp &= B43_PHYVER_VERSION; + if (tmp == 3 || tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); + } + if (tmp == 5) { + b43_phy_write(dev, B43_PHY_OFDM(0xCC), + (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) + & 0x00FF) | 0x1F00); + } + } + if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) + b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); + if (phy->radio_rev == 8) { + b43_phy_write(dev, B43_PHY_EXTG(0x01), + b43_phy_read(dev, B43_PHY_EXTG(0x01)) + | 0x80); + b43_phy_write(dev, B43_PHY_OFDM(0x3E), + b43_phy_read(dev, B43_PHY_OFDM(0x3E)) + | 0x4); + } + if (has_loopback_gain(phy)) + b43_calc_loopback_gain(dev); + + if (phy->radio_rev != 8) { + if (gphy->initval == 0xFFFF) + gphy->initval = b43_radio_init2050(dev); + else + b43_radio_write16(dev, 0x0078, gphy->initval); + } + b43_lo_g_init(dev); + if (has_tx_magnification(phy)) { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFF00) + | gphy->lo_control->tx_bias | gphy-> + lo_control->tx_magn); + } else { + b43_radio_write16(dev, 0x52, + (b43_radio_read16(dev, 0x52) & 0xFFF0) + | gphy->lo_control->tx_bias); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) + & 0x0FFF) | (gphy->lo_control-> + tx_bias << 12)); + } + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); + else + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); + if (phy->rev < 2) + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); + else + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); + if (phy->gmode || phy->rev >= 2) { + b43_lo_g_adjust(dev); + b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); + } + + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the clamp_val() in nrssi_hw_update()) + */ + b43_nrssi_hw_update(dev, 0xFFFF); //FIXME? + b43_calc_nrssi_threshold(dev); + } else if (phy->gmode || phy->rev >= 2) { + if (gphy->nrssi[0] == -1000) { + B43_WARN_ON(gphy->nrssi[1] != -1000); + b43_calc_nrssi_slope(dev); + } else + b43_calc_nrssi_threshold(dev); + } + if (phy->radio_rev == 8) + b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230); + b43_phy_init_pctl(dev); + /* FIXME: The spec says in the following if, the 0 should be replaced + 'if OFDM may not be used in the current locale' + but OFDM is legal everywhere */ + if ((dev->dev->bus->chip_id == 0x4306 + && dev->dev->bus->chip_package == 2) || 0) { + b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) + & 0xBFFF); + b43_phy_write(dev, B43_PHY_OFDM(0xC3), + b43_phy_read(dev, B43_PHY_OFDM(0xC3)) + & 0x7FFF); + } +} + +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround) +{ + if (synthetic_pu_workaround) + b43_synth_pu_workaround(dev, channel); + + b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); + + if (channel == 14) { + if (dev->dev->bus->sprom.country_code == + SSB_SPROM1CCODE_JAPAN) + b43_hf_write(dev, + b43_hf_read(dev) & ~B43_HF_ACPR); + else + b43_hf_write(dev, + b43_hf_read(dev) | B43_HF_ACPR); + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + b43_write16(dev, B43_MMIO_CHANNEL_EXT, + b43_read16(dev, B43_MMIO_CHANNEL_EXT) + & 0xF7BF); + } +} + +static void default_baseband_attenuation(struct b43_wldev *dev, + struct b43_bbatt *bb) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) + bb->att = 0; + else + bb->att = 2; +} + +static void default_radio_attenuation(struct b43_wldev *dev, + struct b43_rfatt *rf) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + rf->with_padmix = 0; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BCM4309G) { + if (bus->boardinfo.rev < 0x43) { + rf->att = 2; + return; + } else if (bus->boardinfo.rev < 0x51) { + rf->att = 3; + return; + } + } + + if (phy->type == B43_PHYTYPE_A) { + rf->att = 0x60; + return; + } + + switch (phy->radio_ver) { + case 0x2053: + switch (phy->radio_rev) { + case 1: + rf->att = 6; + return; + } + break; + case 0x2050: + switch (phy->radio_rev) { + case 0: + rf->att = 5; + return; + case 1: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 3; + else + rf->att = 1; + } else { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 7; + else + rf->att = 6; + } + return; + case 2: + if (phy->type == B43_PHYTYPE_G) { + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == SSB_BOARD_BCM4309G + && bus->boardinfo.rev >= 30) + rf->att = 3; + else if (bus->boardinfo.vendor == + SSB_BOARDVENDOR_BCM + && bus->boardinfo.type == + SSB_BOARD_BU4306) + rf->att = 5; + else if (bus->chip_id == 0x4320) + rf->att = 4; + else + rf->att = 3; + } else + rf->att = 6; + return; + case 3: + rf->att = 5; + return; + case 4: + case 5: + rf->att = 1; + return; + case 6: + case 7: + rf->att = 5; + return; + case 8: + rf->att = 0xA; + rf->with_padmix = 1; + return; + case 9: + default: + rf->att = 5; + return; + } + } + rf->att = 5; +} + +static u16 default_tx_control(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->radio_ver != 0x2050) + return 0; + if (phy->radio_rev == 1) + return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX; + if (phy->radio_rev < 6) + return B43_TXCTL_PA2DB; + if (phy->radio_rev == 8) + return B43_TXCTL_TXMIX; + return 0; +} + +static u8 b43_gphy_aci_detect(struct b43_wldev *dev, u8 channel) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = b43_phy_read(dev, 0x0403); + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); + if (gphy->aci_hw_rssi) + rssi = b43_phy_read(dev, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0; i < 100; i++) { + temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + b43_phy_write(dev, 0x0403, saved); + + return ret; +} + +static u8 b43_gphy_aci_scan(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u8 ret[13]; + unsigned int channel = phy->channel; + unsigned int i, j, start, end; + + if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); + b43_set_all_gains(dev, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i - 1] = b43_gphy_aci_detect(dev, i); + } + b43_switch_channel(dev, channel); + b43_phy_write(dev, 0x0802, + (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); + b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); + b43_phy_write(dev, B43_PHY_G_CRS, + b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); + b43_set_original_gains(dev); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + b43_radio_unlock(dev); + b43_phy_unlock(dev); + + return ret[channel - 1]; +} + +static s32 b43_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num / den; + else + return (num + den / 2) / den; +} + +static s8 b43_tssi2dbm_entry(s8 entry[], u8 index, + s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = b43_tssi2dbm_ad(f * 4096 - + b43_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, + s16 pab0, s16 pab1, s16 pab2) +{ + unsigned int i; + u8 *tab; + int err; + + tab = kmalloc(64, GFP_KERNEL); + if (!tab) { + b43err(dev->wl, "Could not allocate memory " + "for tssi2dbm table\n"); + return NULL; + } + for (i = 0; i < 64; i++) { + err = b43_tssi2dbm_entry(tab, i, pab0, pab1, pab2); + if (err) { + b43err(dev->wl, "Could not generate " + "tssi2dBm table\n"); + kfree(tab); + return NULL; + } + } + + return tab; +} + +/* Initialise the TSSI->dBm lookup table */ +static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + s16 pab0, pab1, pab2; + + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); + + B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) && + (phy->radio_ver != 0x2050)); /* Not supported anymore */ + + gphy->dyn_tssi_tbl = 0; + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) { + gphy->tgt_idle_tssi = + (s8) (dev->dev->bus->sprom.itssi_bg); + } else + gphy->tgt_idle_tssi = 62; + gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0, + pab1, pab2); + if (!gphy->tssi2dbm) + return -ENOMEM; + gphy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + gphy->tgt_idle_tssi = 52; + gphy->tssi2dbm = b43_tssi2dbm_g_table; + } + + return 0; +} + +static int b43_gphy_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy; + struct b43_txpower_lo_control *lo; + int err, i; + + gphy = kzalloc(sizeof(*gphy), GFP_KERNEL); + if (!gphy) { + err = -ENOMEM; + goto error; + } + dev->phy.g = gphy; + + memset(gphy->minlowsig, 0xFF, sizeof(gphy->minlowsig)); + + /* NRSSI */ + for (i = 0; i < ARRAY_SIZE(gphy->nrssi); i++) + gphy->nrssi[i] = -1000; + for (i = 0; i < ARRAY_SIZE(gphy->nrssi_lt); i++) + gphy->nrssi_lt[i] = i; + + gphy->lofcal = 0xFFFF; + gphy->initval = 0xFFFF; + + gphy->interfmode = B43_INTERFMODE_NONE; + + /* OFDM-table address caching. */ + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; + + + lo = kzalloc(sizeof(*lo), GFP_KERNEL); + if (!lo) { + err = -ENOMEM; + goto err_free_gphy; + } + gphy->lo_control = lo; + + lo->tx_bias = 0xFF; + INIT_LIST_HEAD(&lo->calib_list); + + err = b43_gphy_init_tssi2dbm_table(dev); + if (err) + goto err_free_lo; + + return 0; + +err_free_lo: + kfree(lo); +err_free_gphy: + kfree(gphy); +error: + return err; +} + +static int b43_gphy_op_prepare(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + struct b43_txpower_lo_control *lo = gphy->lo_control; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + + default_baseband_attenuation(dev, &gphy->bbatt); + default_radio_attenuation(dev, &gphy->rfatt); + gphy->tx_control = (default_tx_control(dev) << 4); + generate_rfatt_list(dev, &lo->rfatt_list); + generate_bbatt_list(dev, &lo->bbatt_list); + + /* Commit previous writes */ + b43_read32(dev, B43_MMIO_MACCTL); + + if (phy->rev == 1) { + /* Workaround: Temporarly disable gmode through the early init + * phase, as the gmode stuff is not needed for phy rev 1 */ + phy->gmode = 0; + b43_wireless_core_reset(dev, 0); + b43_phy_initg(dev); + phy->gmode = 1; + b43_wireless_core_reset(dev, B43_TMSLOW_GMODE); + } + + return 0; +} + +static int b43_gphy_op_init(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + + b43_phy_initg(dev); + gphy->initialised = 1; + + return 0; +} + +static void b43_gphy_op_exit(struct b43_wldev *dev) +{ + struct b43_phy_g *gphy = dev->phy.g; + + if (gphy->initialised) { + //TODO + gphy->initialised = 0; + } + b43_lo_g_cleanup(dev); + kfree(gphy->lo_control); + if (gphy->dyn_tssi_tbl) + kfree(gphy->tssi2dbm); + kfree(gphy); + dev->phy.g = NULL; +} + +static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + /* G-PHY needs 0x80 for read access. */ + reg |= 0x80; + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); +} + +static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + /* Register 1 is a 32-bit register. */ + B43_WARN_ON(reg == 1); + + b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); +} + +static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev) +{ + return (dev->phy.rev >= 6); +} + +static void b43_gphy_op_software_rfkill(struct b43_wldev *dev, + enum rfkill_state state) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int channel; + + might_sleep(); + + if (state == RFKILL_STATE_UNBLOCKED) { + /* Turn radio ON */ + if (phy->radio_on) + return; + + b43_phy_write(dev, 0x0015, 0x8000); + b43_phy_write(dev, 0x0015, 0xCC00); + b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000)); + if (gphy->radio_off_context.valid) { + /* Restore the RFover values. */ + b43_phy_write(dev, B43_PHY_RFOVER, + gphy->radio_off_context.rfover); + b43_phy_write(dev, B43_PHY_RFOVERVAL, + gphy->radio_off_context.rfoverval); + gphy->radio_off_context.valid = 0; + } + channel = phy->channel; + b43_gphy_channel_switch(dev, 6, 1); + b43_gphy_channel_switch(dev, channel, 0); + } else { + /* Turn radio OFF */ + u16 rfover, rfoverval; + + rfover = b43_phy_read(dev, B43_PHY_RFOVER); + rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); + gphy->radio_off_context.rfover = rfover; + gphy->radio_off_context.rfoverval = rfoverval; + gphy->radio_off_context.valid = 1; + b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); + b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); + } +} + +static int b43_gphy_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + b43_gphy_channel_switch(dev, new_channel, 0); + + return 0; +} + +static unsigned int b43_gphy_op_get_default_chan(struct b43_wldev *dev) +{ + return 1; /* Default to channel 1 */ +} + +static void b43_gphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) +{ + struct b43_phy *phy = &dev->phy; + u64 hf; + u16 tmp; + int autodiv = 0; + + if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1) + autodiv = 1; + + hf = b43_hf_read(dev); + hf &= ~B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); + + tmp = b43_phy_read(dev, B43_PHY_BBANDCFG); + tmp &= ~B43_PHY_BBANDCFG_RXANT; + tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna) + << B43_PHY_BBANDCFG_RXANT_SHIFT; + b43_phy_write(dev, B43_PHY_BBANDCFG, tmp); + + if (autodiv) { + tmp = b43_phy_read(dev, B43_PHY_ANTDWELL); + if (antenna == B43_ANTENNA_AUTO0) + tmp &= ~B43_PHY_ANTDWELL_AUTODIV1; + else + tmp |= B43_PHY_ANTDWELL_AUTODIV1; + b43_phy_write(dev, B43_PHY_ANTDWELL, tmp); + } + tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT); + if (autodiv) + tmp |= B43_PHY_ANTWRSETT_ARXDIV; + else + tmp &= ~B43_PHY_ANTWRSETT_ARXDIV; + b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp); + if (phy->rev >= 2) { + tmp = b43_phy_read(dev, B43_PHY_OFDM61); + tmp |= B43_PHY_OFDM61_10; + b43_phy_write(dev, B43_PHY_OFDM61, tmp); + + tmp = + b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK); + tmp = (tmp & 0xFF00) | 0x15; + b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK, + tmp); + + if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_ADIVRELATED, + 8); + } else { + tmp = + b43_phy_read(dev, + B43_PHY_ADIVRELATED); + tmp = (tmp & 0xFF00) | 8; + b43_phy_write(dev, B43_PHY_ADIVRELATED, + tmp); + } + } + if (phy->rev >= 6) + b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC); + + hf |= B43_HF_ANTDIVHELP; + b43_hf_write(dev, hf); +} + +static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, + enum b43_interference_mitigation mode) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + int currentmode; + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + if ((phy->rev == 0) || (!phy->gmode)) + return -ENODEV; + + gphy->aci_wlan_automatic = 0; + switch (mode) { + case B43_INTERFMODE_AUTOWLAN: + gphy->aci_wlan_automatic = 1; + if (gphy->aci_enable) + mode = B43_INTERFMODE_MANUALWLAN; + else + mode = B43_INTERFMODE_NONE; + break; + case B43_INTERFMODE_NONE: + case B43_INTERFMODE_NONWLAN: + case B43_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = gphy->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != B43_INTERFMODE_NONE) + b43_radio_interference_mitigation_disable(dev, currentmode); + + if (mode == B43_INTERFMODE_NONE) { + gphy->aci_enable = 0; + gphy->aci_hw_rssi = 0; + } else + b43_radio_interference_mitigation_enable(dev, mode); + gphy->interfmode = mode; + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) +{ + struct b43_phy_g *gphy = dev->phy.g; + s8 dbm; + s32 tmp; + + tmp = (gphy->tgt_idle_tssi - gphy->cur_idle_tssi + tssi); + tmp = clamp_val(tmp, 0x00, 0x3F); + dbm = gphy->tssi2dbm[tmp]; + + return dbm; +} + +static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, + int *_bbatt, int *_rfatt) +{ + int rfatt = *_rfatt; + int bbatt = *_bbatt; + struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; + + /* Get baseband and radio attenuation values into their permitted ranges. + * Radio attenuation affects power level 4 times as much as baseband. */ + + /* Range constants */ + const int rf_min = lo->rfatt_list.min_val; + const int rf_max = lo->rfatt_list.max_val; + const int bb_min = lo->bbatt_list.min_val; + const int bb_max = lo->bbatt_list.max_val; + + while (1) { + if (rfatt > rf_max && bbatt > bb_max - 4) + break; /* Can not get it into ranges */ + if (rfatt < rf_min && bbatt < bb_min + 4) + break; /* Can not get it into ranges */ + if (bbatt > bb_max && rfatt > rf_max - 1) + break; /* Can not get it into ranges */ + if (bbatt < bb_min && rfatt < rf_min + 1) + break; /* Can not get it into ranges */ + + if (bbatt > bb_max) { + bbatt -= 4; + rfatt += 1; + continue; + } + if (bbatt < bb_min) { + bbatt += 4; + rfatt -= 1; + continue; + } + if (rfatt > rf_max) { + rfatt -= 1; + bbatt += 4; + continue; + } + if (rfatt < rf_min) { + rfatt += 1; + bbatt -= 4; + continue; + } + break; + } + + *_rfatt = clamp_val(rfatt, rf_min, rf_max); + *_bbatt = clamp_val(bbatt, bb_min, bb_max); +} + +static void b43_gphy_op_xmitpower(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + u16 tmp; + s8 v0, v1, v2, v3; + s8 average; + int max_pwr; + int desired_pwr, estimated_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + int rfatt, bbatt; + u8 tx_control; + + if (gphy->cur_idle_tssi == 0) + return; + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (bus->boardinfo.type == SSB_BOARD_BU4306)) + return; + + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) { + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); + v0 = (s8) (tmp & 0x00FF); + v1 = (s8) ((tmp & 0xFF00) >> 8); + tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); + v2 = (s8) (tmp & 0x00FF); + v3 = (s8) ((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F + || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + b43_shm_clear_tssi(dev); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & 0x8)) + average -= 13; + + estimated_pwr = b43_gphy_estimate_power_out(dev, average); + + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) + max_pwr -= 0x3; + if (unlikely(max_pwr <= 0)) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = 60; /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } + + /*TODO: + max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /* Get desired power (in Q5.2) */ + desired_pwr = INT_TO_Q52(phy->power_level); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "Current TX power output: " Q52_FMT + " dBm, " "Desired TX power output: " + Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + /* So do we finally need to adjust something? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + return; + + /* Calculate the new attenuation values. */ + bbatt = gphy->bbatt.att; + bbatt += bbatt_delta; + rfatt = gphy->rfatt.att; + rfatt += rfatt_delta; + + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + tx_control = gphy->tx_control; + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) { + if (rfatt <= 1) { + if (tx_control == 0) { + tx_control = + B43_TXCTL_PA2DB | + B43_TXCTL_TXMIX; + rfatt += 2; + bbatt += 2; + } else if (dev->dev->bus->sprom. + boardflags_lo & + B43_BFL_PACTRL) { + bbatt += 4 * (rfatt - 2); + rfatt = 2; + } + } else if (rfatt > 4 && tx_control) { + tx_control = 0; + if (bbatt < 3) { + rfatt -= 3; + bbatt += 2; + } else { + rfatt -= 2; + bbatt -= 2; + } + } + } + /* Save the control values */ + gphy->tx_control = tx_control; + b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); + gphy->rfatt.att = rfatt; + gphy->bbatt.att = bbatt; + + /* Adjust the hardware */ + b43_phy_lock(dev); + b43_radio_lock(dev); + b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, + gphy->tx_control); + b43_radio_unlock(dev); + b43_phy_unlock(dev); +} + +static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + + //TODO: update_aci_moving_average + if (gphy->aci_enable && gphy->aci_wlan_automatic) { + b43_mac_suspend(dev); + if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { + if (0 /*TODO: bunch of conditions */ ) { + phy->ops->interf_mitigation(dev, + B43_INTERFMODE_MANUALWLAN); + } + } else if (0 /*TODO*/) { + if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) + phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); + } + b43_mac_enable(dev); + } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + b43_lo_g_maintanance_work(dev); +} + +static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) + return; + + b43_mac_suspend(dev); + b43_calc_nrssi_slope(dev); + if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { + u8 old_chan = phy->channel; + + /* VCO Calibration */ + if (old_chan >= 8) + b43_switch_channel(dev, 1); + else + b43_switch_channel(dev, 13); + b43_switch_channel(dev, old_chan); + } + b43_mac_enable(dev); +} + +const struct b43_phy_operations b43_phyops_g = { + .allocate = b43_gphy_op_allocate, + .prepare = b43_gphy_op_prepare, + .init = b43_gphy_op_init, + .exit = b43_gphy_op_exit, + .phy_read = b43_gphy_op_read, + .phy_write = b43_gphy_op_write, + .radio_read = b43_gphy_op_radio_read, + .radio_write = b43_gphy_op_radio_write, + .supports_hwpctl = b43_gphy_op_supports_hwpctl, + .software_rfkill = b43_gphy_op_software_rfkill, + .switch_channel = b43_gphy_op_switch_channel, + .get_default_chan = b43_gphy_op_get_default_chan, + .set_rx_antenna = b43_gphy_op_set_rx_antenna, + .interf_mitigation = b43_gphy_op_interf_mitigation, + .xmitpower = b43_gphy_op_xmitpower, + .pwork_15sec = b43_gphy_op_pwork_15sec, + .pwork_60sec = b43_gphy_op_pwork_60sec, +}; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h new file mode 100644 index 0000000..1f0daeb --- /dev/null +++ b/drivers/net/wireless/b43/phy_g.h @@ -0,0 +1,201 @@ +#ifndef LINUX_B43_PHY_G_H_ +#define LINUX_B43_PHY_G_H_ + +/* OFDM PHY registers are defined in the A-PHY header. */ +#include "phy_a.h" + +/* CCK (B) PHY Registers */ +#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ +#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ +#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ +#define B43_PHY_PGACTL_UNKNOWN 0xEFA0 +#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) +#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ + +/* Extended G-PHY Registers */ +#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ +#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */ +#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */ +#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */ +#define B43_PHY_GTABNR_SHIFT 10 +#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */ +#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */ +#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */ +#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */ +#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */ +#define B43_PHY_RFOVERVAL_EXTLNA 0x8000 +#define B43_PHY_RFOVERVAL_LNA 0x7000 +#define B43_PHY_RFOVERVAL_LNA_SHIFT 12 +#define B43_PHY_RFOVERVAL_PGA 0x0F00 +#define B43_PHY_RFOVERVAL_PGA_SHIFT 8 +#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */ +#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0 +#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */ +#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */ +#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */ +#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */ +#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */ + + +/*** G-PHY table numbers */ +#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset)) +#define B43_GTAB_NRSSI B43_GTAB(0x00, 0) +#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120) +#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298) + +u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); +void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); + + +/* Returns the boolean whether "TX Magnification" is enabled. */ +#define has_tx_magnification(phy) \ + (((phy)->rev >= 2) && \ + ((phy)->radio_ver == 0x2050) && \ + ((phy)->radio_rev == 8)) +/* Card uses the loopback gain stuff */ +#define has_loopback_gain(phy) \ + (((phy)->rev > 1) || ((phy)->gmode)) + +/* Radio Attenuation (RF Attenuation) */ +struct b43_rfatt { + u8 att; /* Attenuation value */ + bool with_padmix; /* Flag, PAD Mixer enabled. */ +}; +struct b43_rfatt_list { + /* Attenuation values list */ + const struct b43_rfatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_rfatt(const struct b43_rfatt *a, + const struct b43_rfatt *b) +{ + return ((a->att == b->att) && + (a->with_padmix == b->with_padmix)); +} + +/* Baseband Attenuation */ +struct b43_bbatt { + u8 att; /* Attenuation value */ +}; +struct b43_bbatt_list { + /* Attenuation values list */ + const struct b43_bbatt *list; + u8 len; + /* Minimum/Maximum attenuation values */ + u8 min_val; + u8 max_val; +}; + +/* Returns true, if the values are the same. */ +static inline bool b43_compare_bbatt(const struct b43_bbatt *a, + const struct b43_bbatt *b) +{ + return (a->att == b->att); +} + +/* tx_control bits. */ +#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */ +#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */ +#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */ + +struct b43_txpower_lo_control; + +struct b43_phy_g { + bool initialised; + bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ + + /* ACI (adjacent channel interference) flags. */ + bool aci_enable; + bool aci_wlan_automatic; + bool aci_hw_rssi; + + /* Radio switched on/off */ + bool radio_on; + struct { + /* Values saved when turning the radio off. + * They are needed when turning it on again. */ + bool valid; + u16 rfover; + u16 rfoverval; + } radio_off_context; + + u16 minlowsig[2]; + u16 minlowsigpos[2]; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* Target idle TSSI */ + int tgt_idle_tssi; + /* Current idle TSSI */ + int cur_idle_tssi; + + /* LocalOscillator control values. */ + struct b43_txpower_lo_control *lo_control; + /* Values from b43_calc_loopback_gain() */ + s16 max_lb_gain; /* Maximum Loopback gain in hdB */ + s16 trsw_rx_gain; /* TRSW RX gain in hdB */ + s16 lna_lod_gain; /* LNA lod */ + s16 lna_gain; /* LNA */ + s16 pga_gain; /* PGA */ + + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define B43_INTERFSTACK_SIZE 26 + u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + u16 lofcal; + + u16 initval; //FIXME rename? + + /* The device does address auto increment for the OFDM tables. + * We cache the previously used address here and omit the address + * write on the next table access, if possible. */ + u16 ofdmtab_addr; /* The address currently set in hardware. */ + enum { /* The last data flow direction. */ + B43_OFDMTAB_DIRECTION_UNKNOWN = 0, + B43_OFDMTAB_DIRECTION_READ, + B43_OFDMTAB_DIRECTION_WRITE, + } ofdmtab_addr_direction; +}; + +void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, + u16 baseband_attenuation); +void b43_gphy_channel_switch(struct b43_wldev *dev, + unsigned int channel, + bool synthetic_pu_workaround); + +struct b43_phy_operations; +extern const struct b43_phy_operations b43_phyops_g; + +#endif /* LINUX_B43_PHY_G_H_ */ diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index fec5645..7b9e99a 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -24,6 +24,7 @@ #include "rfkill.h" #include "b43.h" +#include "phy_common.h" #include @@ -114,11 +115,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state) goto out_unlock; } if (!dev->phy.radio_on) - b43_radio_turn_on(dev); + b43_software_rfkill(dev, state); break; case RFKILL_STATE_SOFT_BLOCKED: if (dev->phy.radio_on) - b43_radio_turn_off(dev, 0); + b43_software_rfkill(dev, state); break; default: b43warn(wl, "Received unexpected rfkill state %d.\n", state); diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index 275095b..5adaa36 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -29,7 +29,7 @@ #include "b43.h" #include "sysfs.h" #include "main.h" -#include "phy.h" +#include "phy_common.h" #define GENERIC_FILESIZE 64 @@ -59,7 +59,12 @@ static ssize_t b43_attr_interfmode_show(struct device *dev, mutex_lock(&wldev->wl->mutex); - switch (wldev->phy.interfmode) { + if (wldev->phy.type != B43_PHYTYPE_G) { + mutex_unlock(&wldev->wl->mutex); + return -ENOSYS; + } + + switch (wldev->phy.g->interfmode) { case B43_INTERFMODE_NONE: count = snprintf(buf, PAGE_SIZE, @@ -117,11 +122,15 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, mutex_lock(&wldev->wl->mutex); spin_lock_irqsave(&wldev->wl->irq_lock, flags); - err = b43_radio_set_interference_mitigation(wldev, mode); - if (err) { - b43err(wldev->wl, "Interference Mitigation not " - "supported by device\n"); - } + if (wldev->phy.ops->interf_mitigation) { + err = wldev->phy.ops->interf_mitigation(wldev, mode); + if (err) { + b43err(wldev->wl, "Interference Mitigation not " + "supported by device\n"); + } + } else + err = -ENOSYS; + mmiowb(); spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); mutex_unlock(&wldev->wl->mutex); diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c index 3f5ea06..1ef9a64 100644 --- a/drivers/net/wireless/b43/tables.c +++ b/drivers/net/wireless/b43/tables.c @@ -27,7 +27,8 @@ #include "b43.h" #include "tables.h" -#include "phy.h" +#include "phy_g.h" + const u32 b43_tab_rotor[] = { 0xFEB93FFD, 0xFEC63FFD, /* 0 */ @@ -377,17 +378,17 @@ static inline void assert_sizes(void) u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; return b43_phy_read(dev, B43_PHY_OTABLEI); @@ -398,34 +399,34 @@ u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, u16 offset, u16 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); } u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u32 ret; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; ret = b43_phy_read(dev, B43_PHY_OTABLEQ); ret <<= 16; ret |= b43_phy_read(dev, B43_PHY_OTABLEI); @@ -436,17 +437,17 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value) { - struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = dev->phy.g; u16 addr; addr = table + offset; - if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || - (addr - 1 != phy->ofdmtab_addr)) { + if ((gphy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != gphy->ofdmtab_addr)) { /* The hardware has a different address in memory. Update it. */ b43_phy_write(dev, B43_PHY_OTABLECTL, addr); - phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; } - phy->ofdmtab_addr = addr; + gphy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 2aa5755..1de2c2e 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -24,7 +24,7 @@ #include "b43.h" #include "tables_nphy.h" -#include "phy.h" +#include "phy_common.h" #include "nphy.h" diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index daa9421..0c0fb15 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c @@ -27,7 +27,7 @@ #include "b43.h" #include "main.h" #include "tables.h" -#include "phy.h" +#include "phy_common.h" #include "wa.h" static void b43_wa_papd(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 9dda816..c8a8312 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -28,7 +28,7 @@ */ #include "xmit.h" -#include "phy.h" +#include "phy_common.h" #include "dma.h" #include "pio.h" @@ -431,6 +431,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, int adjust_2053, int adjust_2050) { struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; s32 tmp; switch (phy->radio_ver) { @@ -450,7 +451,8 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; - tmp = phy->nrssi_lt[in_rssi]; + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + tmp = gphy->nrssi_lt[in_rssi]; tmp = 31 - tmp; tmp *= -131; tmp /= 128; -- cgit v0.10.2 From 18c8adeb0244f823ba78a51e23f813fe68bc3c54 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 28 Aug 2008 19:33:40 +0200 Subject: b43: Rewrite TX power adjustment This patch rewrites the TX power recalculation algorithms to scale better with changed enviromnent. If there's low TX traffic, the power will be checked against the desired values every 60 seconds. If there is high TX traffic, the check is redone every 2 seconds. This improves the reaction times a lot and confuses the rate control less. It will also reduce the time it initially takes to tune to a new TX power value. With the old algorithm it could take about 30 to 45 seconds to settle to a new power value. This will happen in about two to four seconds now. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index fc28015..f9c8161 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -173,6 +173,11 @@ enum { #define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */ #define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */ #define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */ +/* TSSI information */ +#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_A 0x0068 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_SHM_SH_TSSI_OFDM_G 0x0070 /* TSSI for last 4 OFDM frames (32bit) */ +#define B43_TSSI_MAX 0x7F /* Max value for one TSSI value */ /* SHM_SHARED TX FIFO variables */ #define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */ #define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */ @@ -648,6 +653,11 @@ struct b43_wl { struct b43_qos_params qos_params[4]; /* Workqueue for updating QOS parameters in hardware. */ struct work_struct qos_update_work; + + /* Work for adjustment of the transmission power. + * This is scheduled when we determine that the actual TX output + * power doesn't match what we want. */ + struct work_struct txpower_adjust_work; }; /* In-memory representation of a cached microcode file. */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index af43f03..63bafc2 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2805,6 +2805,9 @@ static void b43_periodic_every60sec(struct b43_wldev *dev) if (ops->pwork_60sec) ops->pwork_60sec(dev); + + /* Force check the TX power emission now. */ + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME); } static void b43_periodic_every30sec(struct b43_wldev *dev) @@ -2835,8 +2838,6 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) if (phy->ops->pwork_15sec) phy->ops->pwork_15sec(dev); - phy->ops->xmitpower(dev); - atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); wmb(); } @@ -3382,10 +3383,13 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Adjust the desired TX power level. */ if (conf->power_level != 0) { - if (conf->power_level != phy->power_level) { - phy->power_level = conf->power_level; - phy->ops->xmitpower(dev); + spin_lock_irqsave(&wl->irq_lock, flags); + if (conf->power_level != phy->desired_txpower) { + phy->desired_txpower = conf->power_level; + b43_phy_txpower_check(dev, B43_TXPWR_IGNORE_TIME | + B43_TXPWR_IGNORE_TSSI); } + spin_unlock_irqrestore(&wl->irq_lock, flags); } /* Antennas for RX and management frame TX. */ @@ -3785,6 +3789,7 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, struct b43_phy *phy) { phy->hardware_power_control = !!modparam_hwpctl; + phy->next_txpwr_check_time = jiffies; /* PHY TX errors counter. */ atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); } @@ -4204,6 +4209,8 @@ static void b43_op_stop(struct ieee80211_hw *hw) b43_wireless_core_stop(dev); b43_wireless_core_exit(dev); mutex_unlock(&wl->mutex); + + cancel_work_sync(&(wl->txpower_adjust_work)); } static int b43_op_set_retry_limit(struct ieee80211_hw *hw, @@ -4581,6 +4588,7 @@ static int b43_wireless_init(struct ssb_device *dev) INIT_LIST_HEAD(&wl->devlist); INIT_WORK(&wl->qos_update_work, b43_qos_update_work); INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); + INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); ssb_set_devtypedata(dev, wl); b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c index 831986c..4cfeab8 100644 --- a/drivers/net/wireless/b43/nphy.c +++ b/drivers/net/wireless/b43/nphy.c @@ -34,10 +34,16 @@ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO } -void b43_nphy_xmitpower(struct b43_wldev *dev) +static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev) {//TODO } +static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + static void b43_chantab_radio_upload(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry *e) { @@ -602,10 +608,6 @@ static unsigned int b43_nphy_op_get_default_chan(struct b43_wldev *dev) return 36; } -static void b43_nphy_op_xmitpower(struct b43_wldev *dev) -{//TODO -} - const struct b43_phy_operations b43_phyops_n = { .allocate = b43_nphy_op_allocate, .init = b43_nphy_op_init, @@ -617,5 +619,6 @@ const struct b43_phy_operations b43_phyops_n = { .software_rfkill = b43_nphy_op_software_rfkill, .switch_channel = b43_nphy_op_switch_channel, .get_default_chan = b43_nphy_op_get_default_chan, - .xmitpower = b43_nphy_op_xmitpower, + .recalc_txpower = b43_nphy_op_recalc_txpower, + .adjust_txpower = b43_nphy_op_adjust_txpower, }; diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index dd34731..4d7d59e 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -505,10 +505,16 @@ static void b43_aphy_op_set_rx_antenna(struct b43_wldev *dev, int antenna) b43_hf_write(dev, hf); } -static void b43_aphy_op_xmitpower(struct b43_wldev *dev) +static void b43_aphy_op_adjust_txpower(struct b43_wldev *dev) {//TODO } +static enum b43_txpwr_result b43_aphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{//TODO + return B43_TXPWR_RES_DONE; +} + static void b43_aphy_op_pwork_15sec(struct b43_wldev *dev) {//TODO } @@ -530,7 +536,8 @@ const struct b43_phy_operations b43_phyops_a = { .switch_channel = b43_aphy_op_switch_channel, .get_default_chan = b43_aphy_op_get_default_chan, .set_rx_antenna = b43_aphy_op_set_rx_antenna, - .xmitpower = b43_aphy_op_xmitpower, + .recalc_txpower = b43_aphy_op_recalc_txpower, + .adjust_txpower = b43_aphy_op_adjust_txpower, .pwork_15sec = b43_aphy_op_pwork_15sec, .pwork_60sec = b43_aphy_op_pwork_60sec, }; diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 45074c0..5a550a7 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -274,3 +274,94 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) phy->ops->software_rfkill(dev, state); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); } + +/** + * b43_phy_txpower_adjust_work - TX power workqueue. + * + * Workqueue for updating the TX power parameters in hardware. + */ +void b43_phy_txpower_adjust_work(struct work_struct *work) +{ + struct b43_wl *wl = container_of(work, struct b43_wl, + txpower_adjust_work); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + + if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED))) + dev->phy.ops->adjust_txpower(dev); + + mutex_unlock(&wl->mutex); +} + +/* Called with wl->irq_lock locked */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags) +{ + struct b43_phy *phy = &dev->phy; + unsigned long now = jiffies; + enum b43_txpwr_result result; + + if (!(flags & B43_TXPWR_IGNORE_TIME)) { + /* Check if it's time for a TXpower check. */ + if (time_before(now, phy->next_txpwr_check_time)) + return; /* Not yet */ + } + /* The next check will be needed in two seconds, or later. */ + phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2)); + + if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306)) + return; /* No software txpower adjustment needed */ + + result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI)); + if (result == B43_TXPWR_RES_DONE) + return; /* We are done. */ + B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST); + B43_WARN_ON(phy->ops->adjust_txpower == NULL); + + /* We must adjust the transmission power in hardware. + * Schedule b43_phy_txpower_adjust_work(). */ + queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work); +} + +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset) +{ + const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK); + unsigned int a, b, c, d; + unsigned int average; + u32 tmp; + + tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset); + a = tmp & 0xFF; + b = (tmp >> 8) & 0xFF; + c = (tmp >> 16) & 0xFF; + d = (tmp >> 24) & 0xFF; + if (a == 0 || a == B43_TSSI_MAX || + b == 0 || b == B43_TSSI_MAX || + c == 0 || c == B43_TSSI_MAX || + d == 0 || d == B43_TSSI_MAX) + return -ENOENT; + /* The values are OK. Clear them. */ + tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) | + (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24); + b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp); + + if (is_ofdm) { + a = (a + 32) & 0x3F; + b = (b + 32) & 0x3F; + c = (c + 32) & 0x3F; + d = (d + 32) & 0x3F; + } + + /* Get the average of the values with 0.5 added to each value. */ + average = (a + b + c + d + 2) / 4; + if (is_ofdm) { + /* Adjust for CCK-boost */ + if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO) + & B43_HF_CCKBOOST) + average = (average >= 13) ? (average - 13) : 0; + } + + return average; +} diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index 9b9635e..f8db9f4 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -61,6 +61,17 @@ enum { }; /** + * enum b43_txpwr_result - Return value for the recalc_txpower PHY op. + * + * @B43_TXPWR_RES_NEED_ADJUST: Values changed. Hardware adjustment is needed. + * @B43_TXPWR_RES_DONE: No more work to do. Everything is done. + */ +enum b43_txpwr_result { + B43_TXPWR_RES_NEED_ADJUST, + B43_TXPWR_RES_DONE, +}; + +/** * struct b43_phy_operations - Function pointers for PHY ops. * * @prepare: Prepare the PHY. This is called before @init. @@ -96,8 +107,23 @@ enum { * @interf_mitigation: Switch the Interference Mitigation mode. * Can be NULL, if not supported. * - * @xmitpower: FIXME REMOVEME + * @recalc_txpower: Recalculate the transmission power parameters. + * This callback has to recalculate the TX power settings, + * but does not need to write them to the hardware, yet. + * Returns enum b43_txpwr_result to indicate whether the hardware + * needs to be adjusted. + * If B43_TXPWR_NEED_ADJUST is returned, @adjust_txpower + * will be called later. + * If the parameter "ignore_tssi" is true, the TSSI values should + * be ignored and a recalculation of the power settings should be + * done even if the TSSI values did not change. + * This callback is called with wl->irq_lock held and must not sleep. * Must not be NULL. + * @adjust_txpower: Write the previously calculated TX power settings + * (from @recalc_txpower) to the hardware. + * This function may sleep. + * Can be NULL, if (and ONLY if) @recalc_txpower _always_ + * returns B43_TXPWR_RES_DONE. * * @pwork_15sec: Periodic work. Called every 15 seconds. * Can be NULL, if not required. @@ -127,7 +153,9 @@ struct b43_phy_operations { enum b43_interference_mitigation new_mode); /* Transmission power adjustment */ - void (*xmitpower)(struct b43_wldev *dev); + enum b43_txpwr_result (*recalc_txpower)(struct b43_wldev *dev, + bool ignore_tssi); + void (*adjust_txpower)(struct b43_wldev *dev); /* Misc */ void (*pwork_15sec)(struct b43_wldev *dev); @@ -183,11 +211,15 @@ struct b43_phy { /* Desired TX power level (in dBm). * This is set by the user and adjusted in b43_phy_xmitpower(). */ - u8 power_level; + int desired_txpower; /* Hardware Power Control enabled? */ bool hardware_power_control; + /* The time (in absolute jiffies) when the next TX power output + * check is needed. */ + unsigned long next_txpwr_check_time; + /* current channel */ unsigned int channel; @@ -309,4 +341,41 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel); */ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state); +/** + * b43_phy_txpower_check - Check TX power output. + * + * Compare the current TX power output to the desired power emission + * and schedule an adjustment in case it mismatches. + * Requires wl->irq_lock locked. + * + * @flags: OR'ed enum b43_phy_txpower_check_flags flags. + * See the docs below. + */ +void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags); +/** + * enum b43_phy_txpower_check_flags - Flags for b43_phy_txpower_check() + * + * @B43_TXPWR_IGNORE_TIME: Ignore the schedule time and force-redo + * the check now. + * @B43_TXPWR_IGNORE_TSSI: Redo the recalculation, even if the average + * TSSI did not change. + */ +enum b43_phy_txpower_check_flags { + B43_TXPWR_IGNORE_TIME = (1 << 0), + B43_TXPWR_IGNORE_TSSI = (1 << 1), +}; + +struct work_struct; +void b43_phy_txpower_adjust_work(struct work_struct *work); + +/** + * b43_phy_shm_tssi_read - Read the average of the last 4 TSSI from SHM. + * + * @shm_offset: The SHM address to read the values from. + * + * Returns the average of the 4 TSSI values, or a negative error code. + */ +int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset); + + #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index bb95c54..fce8489 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -2659,6 +2659,7 @@ static int b43_gphy_op_allocate(struct b43_wldev *dev) /* OFDM-table address caching. */ gphy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; + gphy->average_tssi = 0xFF; lo = kzalloc(sizeof(*lo), GFP_KERNEL); if (!lo) { @@ -3011,113 +3012,20 @@ static void b43_put_attenuation_into_ranges(struct b43_wldev *dev, *_bbatt = clamp_val(bbatt, bb_min, bb_max); } -static void b43_gphy_op_xmitpower(struct b43_wldev *dev) +static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) { - struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; - u16 tmp; - s8 v0, v1, v2, v3; - s8 average; - int max_pwr; - int desired_pwr, estimated_pwr, pwr_adjust; - int rfatt_delta, bbatt_delta; int rfatt, bbatt; u8 tx_control; - if (gphy->cur_idle_tssi == 0) - return; - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306)) - return; - - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - tmp = 0; - - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) { - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0070); - v0 = (s8) (tmp & 0x00FF); - v1 = (s8) ((tmp & 0xFF00) >> 8); - tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0072); - v2 = (s8) (tmp & 0x00FF); - v3 = (s8) ((tmp & 0xFF00) >> 8); - if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F - || v3 == 0x7F) - return; - v0 = (v0 + 0x20) & 0x3F; - v1 = (v1 + 0x20) & 0x3F; - v2 = (v2 + 0x20) & 0x3F; - v3 = (v3 + 0x20) & 0x3F; - tmp = 1; - } - b43_shm_clear_tssi(dev); - - average = (v0 + v1 + v2 + v3 + 2) / 4; - - if (tmp && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) & 0x8)) - average -= 13; - - estimated_pwr = b43_gphy_estimate_power_out(dev, average); - - max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.boardflags_lo - & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) - max_pwr -= 0x3; - if (unlikely(max_pwr <= 0)) { - b43warn(dev->wl, - "Invalid max-TX-power value in SPROM.\n"); - max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.maxpwr_bg = max_pwr; - } - - /*TODO: - max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr) - where REG is the max power as per the regulatory domain - */ - - /* Get desired power (in Q5.2) */ - desired_pwr = INT_TO_Q52(phy->power_level); - /* And limit it. max_pwr already is Q5.2 */ - desired_pwr = clamp_val(desired_pwr, 0, max_pwr); - if (b43_debug(dev, B43_DBG_XMITPOWER)) { - b43dbg(dev->wl, - "Current TX power output: " Q52_FMT - " dBm, " "Desired TX power output: " - Q52_FMT " dBm\n", Q52_ARG(estimated_pwr), - Q52_ARG(desired_pwr)); - } - - /* Calculate the adjustment delta. */ - pwr_adjust = desired_pwr - estimated_pwr; - - /* RF attenuation delta. */ - rfatt_delta = ((pwr_adjust + 7) / 8); - /* Lower attenuation => Bigger power output. Negate it. */ - rfatt_delta = -rfatt_delta; - - /* Baseband attenuation delta. */ - bbatt_delta = pwr_adjust / 2; - /* Lower attenuation => Bigger power output. Negate it. */ - bbatt_delta = -bbatt_delta; - /* RF att affects power level 4 times as much as - * Baseband attennuation. Subtract it. */ - bbatt_delta -= 4 * rfatt_delta; - - /* So do we finally need to adjust something? */ - if ((rfatt_delta == 0) && (bbatt_delta == 0)) - return; + spin_lock_irq(&dev->wl->irq_lock); /* Calculate the new attenuation values. */ bbatt = gphy->bbatt.att; - bbatt += bbatt_delta; + bbatt += gphy->bbatt_delta; rfatt = gphy->rfatt.att; - rfatt += rfatt_delta; + rfatt += gphy->rfatt_delta; b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt); tx_control = gphy->tx_control; @@ -3152,6 +3060,14 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) gphy->rfatt.att = rfatt; gphy->bbatt.att = bbatt; + /* We drop the lock early, so we can sleep during hardware + * adjustment. Possible races with op_recalc_txpower are harmless, + * as we will be called once again in case we raced. */ + spin_unlock_irq(&dev->wl->irq_lock); + + if (b43_debug(dev, B43_DBG_XMITPOWER)) + b43dbg(dev->wl, "Adjusting TX power\n"); + /* Adjust the hardware */ b43_phy_lock(dev); b43_radio_lock(dev); @@ -3161,6 +3077,111 @@ static void b43_gphy_op_xmitpower(struct b43_wldev *dev) b43_phy_unlock(dev); } +static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, + bool ignore_tssi) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_g *gphy = phy->g; + unsigned int average_tssi; + int cck_result, ofdm_result; + int estimated_pwr, desired_pwr, pwr_adjust; + int rfatt_delta, bbatt_delta; + unsigned int max_pwr; + + /* First get the average TSSI */ + cck_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_CCK); + ofdm_result = b43_phy_shm_tssi_read(dev, B43_SHM_SH_TSSI_OFDM_G); + if ((cck_result < 0) && (ofdm_result < 0)) { + /* No TSSI information available */ + if (!ignore_tssi) + goto no_adjustment_needed; + cck_result = 0; + ofdm_result = 0; + } + if (cck_result < 0) + average_tssi = ofdm_result; + else if (ofdm_result < 0) + average_tssi = cck_result; + else + average_tssi = (cck_result + ofdm_result) / 2; + /* Merge the average with the stored value. */ + if (likely(gphy->average_tssi != 0xFF)) + average_tssi = (average_tssi + gphy->average_tssi) / 2; + gphy->average_tssi = average_tssi; + B43_WARN_ON(average_tssi >= B43_TSSI_MAX); + + /* Estimate the TX power emission based on the TSSI */ + estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi); + + B43_WARN_ON(phy->type != B43_PHYTYPE_G); + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + max_pwr -= 3; /* minus 0.75 */ + if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) { + b43warn(dev->wl, + "Invalid max-TX-power value in SPROM.\n"); + max_pwr = INT_TO_Q52(20); /* fake it */ + dev->dev->bus->sprom.maxpwr_bg = max_pwr; + } + + /* Get desired power (in Q5.2) */ + if (phy->desired_txpower < 0) + desired_pwr = INT_TO_Q52(0); + else + desired_pwr = INT_TO_Q52(phy->desired_txpower); + /* And limit it. max_pwr already is Q5.2 */ + desired_pwr = clamp_val(desired_pwr, 0, max_pwr); + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + b43dbg(dev->wl, + "[TX power] current = " Q52_FMT + " dBm, desired = " Q52_FMT + " dBm, max = " Q52_FMT "\n", + Q52_ARG(estimated_pwr), + Q52_ARG(desired_pwr), + Q52_ARG(max_pwr)); + } + + /* Calculate the adjustment delta. */ + pwr_adjust = desired_pwr - estimated_pwr; + if (pwr_adjust == 0) + goto no_adjustment_needed; + + /* RF attenuation delta. */ + rfatt_delta = ((pwr_adjust + 7) / 8); + /* Lower attenuation => Bigger power output. Negate it. */ + rfatt_delta = -rfatt_delta; + + /* Baseband attenuation delta. */ + bbatt_delta = pwr_adjust / 2; + /* Lower attenuation => Bigger power output. Negate it. */ + bbatt_delta = -bbatt_delta; + /* RF att affects power level 4 times as much as + * Baseband attennuation. Subtract it. */ + bbatt_delta -= 4 * rfatt_delta; + + if (b43_debug(dev, B43_DBG_XMITPOWER)) { + int dbm = pwr_adjust < 0 ? -pwr_adjust : pwr_adjust; + b43dbg(dev->wl, + "[TX power deltas] %s" Q52_FMT " dBm => " + "bbatt-delta = %d, rfatt-delta = %d\n", + (pwr_adjust < 0 ? "-" : ""), Q52_ARG(dbm), + bbatt_delta, rfatt_delta); + } + /* So do we finally need to adjust something in hardware? */ + if ((rfatt_delta == 0) && (bbatt_delta == 0)) + goto no_adjustment_needed; + + /* Save the deltas for later when we adjust the power. */ + gphy->bbatt_delta = bbatt_delta; + gphy->rfatt_delta = rfatt_delta; + + /* We need to adjust the TX power on the device. */ + return B43_TXPWR_RES_NEED_ADJUST; + +no_adjustment_needed: + return B43_TXPWR_RES_DONE; +} + static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3223,7 +3244,8 @@ const struct b43_phy_operations b43_phyops_g = { .get_default_chan = b43_gphy_op_get_default_chan, .set_rx_antenna = b43_gphy_op_set_rx_antenna, .interf_mitigation = b43_gphy_op_interf_mitigation, - .xmitpower = b43_gphy_op_xmitpower, + .recalc_txpower = b43_gphy_op_recalc_txpower, + .adjust_txpower = b43_gphy_op_adjust_txpower, .pwork_15sec = b43_gphy_op_pwork_15sec, .pwork_60sec = b43_gphy_op_pwork_60sec, }; diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 1f0daeb..7f95ede 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -115,7 +115,6 @@ struct b43_txpower_lo_control; struct b43_phy_g { bool initialised; - bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ bool aci_enable; @@ -135,12 +134,26 @@ struct b43_phy_g { u16 minlowsig[2]; u16 minlowsigpos[2]; - /* TSSI to dBm table in use */ + /* Pointer to the table used to convert a + * TSSI value to dBm-Q5.2 */ const s8 *tssi2dbm; + /* tssi2dbm is kmalloc()ed. Only used for free()ing. */ + bool dyn_tssi_tbl; /* Target idle TSSI */ int tgt_idle_tssi; /* Current idle TSSI */ int cur_idle_tssi; + /* The current average TSSI. + * Needs irq_lock, as it's updated in the IRQ path. */ + u8 average_tssi; + /* Current TX power level attenuation control values */ + struct b43_bbatt bbatt; + struct b43_rfatt rfatt; + u8 tx_control; /* B43_TXCTL_XXX */ + /* The calculated attenuation deltas that are used later + * when adjusting the actual power output. */ + int bbatt_delta; + int rfatt_delta; /* LocalOscillator control values. */ struct b43_txpower_lo_control *lo_control; @@ -151,11 +164,6 @@ struct b43_phy_g { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* Current TX power level attenuation control values */ - struct b43_bbatt bbatt; - struct b43_rfatt rfatt; - u8 tx_control; /* B43_TXCTL_XXX */ - /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index c8a8312..5e0b71c 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -680,6 +680,8 @@ void b43_handle_txstatus(struct b43_wldev *dev, b43_pio_handle_txstatus(dev, status); else b43_dma_handle_txstatus(dev, status); + + b43_phy_txpower_check(dev, 0); } /* Fill out the mac80211 TXstatus report based on the b43-specific -- cgit v0.10.2